openxava
/ documentación /
Lección 20: Comportamiento y lógica de negocio
Curso:
1.
Primeros pasos |
2.
Modelo básico del dominio (1) |
3.
Modelo básico del dominio (2) |
4.
Refinar la interfaz de usuario |
5.
Desarrollo ágil |
6.
Herencia de superclases mapeadas |
7.
Herencia de entidades |
8.
Herencia de vistas |
9.
Propiedades Java |
10.
Propiedades calculadas |
11.
@DefaultValueCalculator en colecciones |
12.
@Calculation y totales de colección |
13.
@DefaultValueCalculator desde archivo |
14.
Evolución del esquema manual |
15. Cálculo del
valor por defecto multiusuario |
16.
Sincronizar propiedades persistentes y calculadas |
17. Lógica desde la base de datos
|
18. Validación avanzada
|
19.
Refinar el comportamiento predefinido |
20. Comportamiento
y lógica de negocio |
21.
Referencias y colecciones |
A.
Arquitectura y filosofía |
B.
Java Persistence API |
C.
Anotaciones |
D.
Pruebas automáticas
OpenXava no es simplemente un marco de trabajo para hacer mantenimientos
(altas, bajas, modificaciones y consultas), más bien está concebido para
desarrollar aplicaciones de gestión plenamente funcionales. Hasta ahora
hemos aprendido como crear y refinar la aplicación para manejar los datos.
Ahora vamos a posibilitar al usuario la ejecución de lógica de negocio
específica.
En esta lección vamos a ver como escribir lógica de negocio en el modelo y
llamar a esta lógica desde acciones personalizadas. Así podrás transformar
tu aplicación de gestión de datos en una herramienta útil para el trabajo
cotidiano de tu usuario.
Lógica de
negocio desde el modo detalle
Empezaremos con el caso más simple: un botón en modo detalle para ejecutar
cierta lógica. En este caso para crear la factura desde un pedido:

Aquí se muestra como esta nueva acción coge el pedido actual y crea una
factura a partir de él. Simplemente copia todos los datos del pedido a la
nueva factura, incluyendo las líneas de detalle. Se muestra un mensaje y
la pestaña FACTURA del pedido visualizará la factura recién creada. Veamos
como codificar este comportamiento.
Crear
una acción para ejecutar lógica personalizada
Como ya sabes el primer paso para tener una acción personalizada en tu
módulo es definir un controlador con esa acción. Por tanto, editemos
controladores.xml y añadamos un nuevo controlador. El siguiente
código muestra el controlador
Pedido:
<controlador nombre="Pedido">
<hereda-de controlador="Facturacion"/> <!-- Para tener las acciones estándar -->
<accion nombre="crearFactura" modo="detail"
clase="com.tuempresa.facturacion.acciones.CrearFacturaDesdePedido"/>
<!-- modo="detail" : Sólo en modo detalle -->
</controlador>
Dado que hemos seguido la convención de dar al controlador el
mismo nombre que a la entidad y el módulo, ya tenemos automáticamente esta
nueva acción disponible para
Pedido. El controlador
Pedido
desciende del controlador
Facturacion. Recuerda que creamos un
controlador
Facturacion en la lección anterior. Es un refinamiento
del controlador
Typical.
Ahora hemos de escribir el código Java para la acción. Puedes verlo aquí:
package com.tuempresa.facturacion.acciones; // En el paquete 'acciones'
import org.openxava.actions.*;
import org.openxava.jpa.*;
import com.tuempresa.facturacion.modelo.*;
public class CrearFacturaDesdePedido
extends ViewBaseAction { // Para usar getView()
public void execute() throws Exception {
Pedido pedido = XPersistence.getManager().find( // Usamos JPA para obtener la
Pedido.class, // entidad Pedido visualizada en la vista
getView().getValue("oid"));
pedido.crearFactura(); // El trabajo de verdad lo delegamos en la entidad
getView().refresh(); // Para ver la factura creada en la pestaña FACTURA
addMessage("factura_creada_desde_pedido", // Mensaje de confirmación
pedido.getFactura());
}
}
Realmente simple. Buscamos la entidad
Pedido, llamamos al
método
crearFactura(), refrescamos la vista y mostramos un
mensaje. Fíjate como la acción es un mero intermediario entre la vista (la
interfaz de usuario) y el modelo (la lógica de negocio).
Recuerda añadir el texto del mensaje en el archivo
MensajesFacturacion_es.properties
de la carpeta
i18n:
factura_creada_desde_pedido=Factura {0} creada a partir del pedido actual
Sin embargo, el mensaje tal cual está no se muestra de forma
agradable, porque enviamos como argumento un objeto
Factura.
Necesitamos un
toString() para
Factura y
Pedido
que sea útil para el usuario. Sobrescribiremos
toString() de
DocumentoComercial
(el padre de
Factura y
Pedido) para conseguirlo. Puedes
ver este método
toString():
abstract public class DocumentoComercial extends Eliminable { {
...
public String toString() {
return anyo + "/" + numero;
}
}
El año y el número son perfectos para identificar una factura o
pedido desde el punto de vista del usuario.
Esto es todo para la acción. Veamos la pieza restante, el método
crearFactura() de la entidad
Pedido.
Escribiendo
la lógica de negocio real en la entidad
La lógica de negocio para crear una nueva
Factura está en la
entidad
Pedido, no en la acción. Esto es la forma natural de
hacerlo. El principio esencial de la Orientación a Objetos es que los
objetos no son solo datos, sino datos y lógica. El código más bello es
aquel cuyos objetos contienen la lógica para manejar sus propios datos. Si
tus entidades son meros contenedores de datos (simples envoltorios de las
tablas de la base de datos) y tus acciones tienen toda la lógica para
manipularlos, en ese caso tu código es una perversión del objetivo
original de la Orientación a Objetos.
Aparte de las razones espirituales, poner la lógica para crear una
Factura
dentro de
Pedido es un enfoque pragmático, porque de esta forma
podemos usar esta lógica desde otras acciones, proceso masivos, servicios
web, etc.
Veamos el código del método
crearFactura() de la clase
Pedido:
public class Pedido extends DocumentoComercial {
...
public void crearFactura() throws Exception { // throws Exception para tener
// un código más simple, de momento
Factura factura = new Factura(); // Instancia una factura
BeanUtils.copyProperties(factura, this); // y copia el estado del pedido actual
factura.setOid(null); // Para que JPA sepa que esta entidad todavía no existe
factura.setFecha(LocalDate.now()); // La fecha para la nueva factura es hoy
factura.setDetalles(new ArrayList<>(getDetalles())); // Clona la colección detalles
XPersistence.getManager().persist(factura);
this.factura = factura; // Siempre después de persist()
}
}
La lógica consiste en crear un nuevo objeto
Factura,
copiar los datos desde el
Pedido actual a él y asignar la entidad
resultante a la referencia
factura del
Pedido actual.
Hay tres sutiles detalles aquí. Primero, has de escribir
factura.setOid(null),
si no la nueva
Factura tendría la misma identidad que el
Pedido
original, además a JPA no le gusta persistir los objetos con el id
autogenerado rellenado de antemano. Segundo, has de asignar la nueva
Factura al actual Pedido (
this.factura = factura) después de
llamar a
persist(factura), si no obtendrás un error de JPA (algo
así como "object references an unsaved transient instance". Tercero, hemos
de envolver la colección
detalles con un
new ArrayList(),
para que sea una colección nueva aunque con los mismos elementos, porque
JPA no quiere la misma colección asignada a dos entidades.
Escribe
menos código usando Apache Commons BeanUtils
Observa como hemos usado
BeanUtils.copyProperties() para copiar
todas las propiedades del actual
Pedido a la nueva
Factura.
Este método copia todas las propiedades con el mismo nombre de un objeto a
otro, incluso si los objetos son de clases diferentes. Esta utilidad
pertenece al proyecto de apache Commons BeanUtils. El jar para esta
utilidad,
commons-beanutils.jar, ya está incluido en tu proyecto.
El siguiente código muestra como usando BeanUtils escribes menos:
BeanUtils.copyProperties(factura, this);
// Es lo mismo que
factura.setOid(getOid());
factura.setAnyo(getAnyo());
factura.setNumero(getNumero());
factura.setFecha(getFecha());
factura.setEliminado(isEliminado());
factura.setCliente(getCliente());
factura.setPorcentajeIVA(getPorcentajeIVA());
factura.setIva(getIva());
factura.setImporteTotal(getImporteTotal());
factura.setObservaciones(getObservaciones());
factura.setDetalles(getDetalles());
Sin embargo, la principal ventaja de usar BeanUtils no es ahorrar
tiempo de tecleo, sino que obtienes un código más resistente a los
cambios. Porque, si añades, quitas o renombras alguna propiedad de
DocumentoComercial
(el padre de
Factura y
Pedido), si estás copiando las
propiedades a mano tienes que cambiar el código, mientras que si estás
usando
BeanUtils.copyProperties() el código funcionará siempre
bien, sin tener que cambiarlo.
Excepciones de aplicación
Recuerda la frase: "La excepción que confirma la regla". Las reglas, la
vida y el software están llenos de excepciones. Y nuestro método
crearFactura() no es una excepción. Hemos escrito código que
funciona en los casos más comunes. Pero, ¿qué ocurre si el pedido no está
listo para ser facturado o si hay algún problema para acceder a la base de
datos? Obviamente, en este caso necesitamos tomar caminos diferentes.
Es decir, el simple
throws Exception que hemos escrito para el
método
crearFactura() no es suficiente para un comportamiento
refinado. Deberiamos crear nuestra propia excepción, hagámoslo:
package com.tuempresa.facturacion.modelo; // En el paquete 'modelo'
import org.openxava.util.*;
public class CrearFacturaException extends Exception { // No RuntimeException
public CrearFacturaException(String mensaje) {
// El XavaResources es para traducir el mensaje desde el id en i18n
super(XavaResources.getString(mensaje));
}
}
Ahora podemos usar nuestra
CrearFacturaException en lugar
de
Exception en el método
crearFactura() de
Pedido:
public void crearFactura()
throws CrearFacturaException // Una excepción de aplicación (1)
{
if (this.factura != null) { // Si ya tiene una factura no podemos crearla
throw new CrearFacturaException(
"pedido_ya_tiene_factura"); // Admite un id de 18n como argumento
}
if (!isEntregado()) { // Si el pedido no está entregado no podemos crear la factura
throw new CrearFacturaException("pedido_no_entregado");
}
try {
Factura factura = new Factura();
BeanUtils.copyProperties(factura, this);
factura.setOid(null);
factura.setFecha(LocalDate.now());
factura.setDetalles(new ArrayList<>(getDetalles()));
XPersistence.getManager().persist(factura);
this.factura = factura;
}
catch (Exception ex) { // Cualquier excepción inesperada (2)
throw new SystemException( // Se lanza una excepción runtime (3)
"imposible_crear_factura", ex);
}
}
Ahora declaramos explícitamente las excepciones de aplicación que
este método lanza (1). Una excepción de aplicación es una excepción
chequeada que indica un comportamiento especial pero esperado del método.
Una excepción de aplicación está relacionada con la lógica de negocio del
método. Puedes crear una excepción de aplicación para cada posible caso.
Por ejemplo, podrías crear una
PedidoYaTieneFacturaException y una
PedidoNoEntregadoException. Esto te permitiría tratar cada caso de
forma diferente desde el código que usa el método. Aunque, esto no es
necesario en nuestro caso, por tanto nosotros simplemente usamos nuestra
CrearFacturaException,
una excepción de aplicación genérica para este método.
También hemos de enfrentarnos a problemas inesperados (2). Los problemas
inesperados incluyen errores del sistema (acceso a base de datos, la red o
problemas de hardware) o errores de programación (
NullPointerException,
IndexOutOfBoundsException, etc). Cuando nos encontramos con
cualquier problema inesperado lanzamos una
RuntimeException (3).
En este caso hemos lanzado una
SystemException, una
RuntimeException
incluida en OpenXava por comodidad, pero puedes lanzar la
RuntimeException
que quieras.
No necesitas modificar el código de la acción. Si tu acción no atrapa las
excepciones, OpenXava lo hace automáticamente. Muestra los mensajes de las
excepciones de aplicación al usuario; y para las excepciones runtime,
muestra un mensaje de error genérico y aborta la transacción.
Para rematar, añadimos el mensaje para la excepción en los archivos
i18n.
Edita el archivo
MensajesFacturacion_es.properties de la carpeta
Facturacion/i18n
añadiendo las siguientes entradas:
pedido_ya_tiene_factura=El pedido ya tiene una factura
pedido_no_entregado=El pedido todavía no está entregado
imposible_crear_factura=Imposible crear factura
Hay cierto debate en la comunidad de desarrolladores sobre la
manera correcta de usar las excepciones en Java. El enfoque usado en esta
sección es la forma clásica de trabajar con excepciones en el mundo Java
empresarial.
Validar desde la acción
Usualmente el mejor lugar para las validaciones es el modelo, es decir,
las entidades. Sin embargo, a veces es necesario poner lógica de
validación en las acciones. Por ejemplo, si quieres preguntar por el
estado actual de la interfaz gráfica has de hacer la validación en la
acción.
En nuestro caso si el usuario pulsa en CREAR FACTURA cuando está creando
un nuevo pedido que todavía no ha grabado, fallará. Falla porque es
imposible crear una factura desde un pedido inexistente. El usuario ha de
grabar el pedido primero.
Modificamos el método
execute() de
CrearFacturaDesdePedido
para validar que la factura visualizada actualmente esté grabada:
public void execute() throws Exception {
// Añade la siguiente condición
if (getView().getValue("oid") == null) {
// Si el oid es nulo el pedido actual no se ha grabado todavía (1)
addError("imposible_crear_factura_pedido_no_existe");
return;
}
...
}
La validación consiste en verificar que el
oid es nulo
(1), en cuyo caso el usuario está introduciendo un pedido nuevo, pero
todavía no lo ha grabado. En este caso se muestra un mensaje y se aborta
la creación de la factura.
Aquí también tenemos un mensaje para añadir al archivo i18n. Edita el
archivo
MensajesFacturacion_es.properties de la carpeta
Facturacion/i18n
añadiendo la siguiente entrada:
imposible_crear_factura_pedido_no_existe=Imposible crea factura: El pedido no existe todavía
Las validaciones le dicen al usuario que ha hecho algo mal. Esto
es necesario, por supuesto, pero es mejor aún crear una aplicación que
ayude al usuario a evitar hacer las cosas mal. Veamos una forma de hacerlo
en la siguiente sección.
Evento
OnChange para ocultar/mostrar una acción por código
Nuestro actual código es suficientemente robusto como para prevenir que
equivocaciones del usuario estropeen los datos. Vamos a ir un paso más
allá, impidiendo que el usuario se equivoque. Ocultaremos la acción para
crear una nueva factura cuando el pedido no esté listo para ello.
OpenXava permite ocultar y mostrar acciones automáticamente. También
permite ejecutar una acción cuando cierta propiedad sea cambiada por el
usuario en la interfaz de usuario. Con estos dos ingredientes podemos
mostrar el botón sólo cuando la acción esté lista para ser usada.
Recuerda que una factura puede ser generada desde un pedido si el pedido
ha sido entregado y no tiene factura todavía. Por tanto, tenemos que
vigilar los cambios en la referencia
factura y la propiedad
entregado
de la entidad
Pedido. Lo primero será crear la acción que oculta o
muestra la acción para crear una factura desde un pedido,
MostrarOcultarCrearFactura,
con este código:
package com.tuempresa.facturacion.acciones; // En el paquete 'acciones'
import org.openxava.actions.*; // Necesario para usar OnChangePropertyAction,
public class MostrarOcultarCrearFactura
extends OnChangePropertyBaseAction { // Necesario para las acciones @OnChange (1)
public void execute() throws Exception {
if (estaPedidoCreado() && estaEntregado() && !tieneFactura()) { // (2)
addActions("Pedido.crearFactura");
}
else {
removeActions("Pedido.crearFactura");
}
}
private boolean estaPedidoCreado() {
return getView().getValue("oid") != null; // Leemos el valor de la vista
}
private boolean estaEntregado() {
Boolean entregado = (Boolean)
getView().getValue("entregado"); // Leemos el valor de la vista
return entregado == null?false:entregado;
}
private boolean tieneFactura() {
return getView().getValue("factura.oid") != null; // Leemos el valor de la vista
}
}
Después anotamos
factura y
entregado en
Pedido
con
@OnChange para que cuando el usuario cambie el valor de
entregado
o
factura en la pantalla, la acción
MostrarOcultarCrearFactura
se ejecute:
public class Pedido extends DocumentoComercial {
...
@OnChange(MostrarOcultarCrearFactura.class) // Añade esto
Factura factura;
...
@OnChange(MostrarOcultarCrearFactura.class) // Añade esto
boolean entregado;
...
}
MostrarOcultarCrearFactura es una acción convencional con un
método
execute(), aunque extiende de
OnChangePropertyBaseAction
(1). Todas las acciones anotadas con
@OnChange tienen que
implementar
IOnChangePropertyAction, aunque es más fácil extender
de
OnChangePropertyBaseAction la cual lo implementa. Desde esta
acción puedes usar
getNewValue() y
getChangedProperty(),
aunque en este caso concreto no los necesitamos.
El método
execute() pregunta si el pedido visualizado está
grabado, entregado y todavía no tiene una factura (2), en cuyo caso
muestra la acción con
addActions("Pedido.crearFactura"), en caso
contrario oculta la acción con
removeActions("Pedido.crearFactura").
Así, ocultamos o mostramos la acción
Pedido.crearFactura,
mostrándola solo cuando proceda. Los métodos
add/removeActions()
permiten especificar varias acciones a mostrar u ocultar separadas por
comas.
Ahora cuando marcas o desmarcas la casilla
entregado o escoges una
factura, el botón para la acción se muestra u oculta. También, cuando el
usuario pulsa en
Nuevo para crear un nuevo pedido el botón para
crear la factura se oculta. Sin embargo, al editar un pedido ya existente,
el botón estará siempre presente, aunque el pedido no cumpla los
requisitos. Esto es porque cuando un objeto se busca y visualiza las
acciones
@OnChange no se ejecutan por defecto. Podemos cambiar
esto con una pequeña modificación en
BuscarExcluyendoEliminados:
public class BuscarExcluyendoEliminados
// extends SearchByViewKeyAction {
extends SearchExecutingOnChangeAction { // Usa ésta como clase base
La acción de búsqueda por defecto, es decir,
SearchByViewKeyAction
no ejecuta las acciones
@OnChange por defecto, por tanto cambiamos
nuestra acción de buscar para que extienda de
SearchExecutingOnChangeAction.
SearchExecutingOnChangeAction se comporta exactamente igual que
SearchByViewKeyAction
pero ejecutando los eventos
OnChange. De esta forma cuando el
usuario escoge un pedido la acción
MostrarOcultarCrearFactura se
ejecuta.
Nos queda un pequeño detalle para que todo esto sea perfecto: cuando el
usuario pulsa en CREAR FACTURA después de que la factura se haya creado el
botón se tiene que ocultar. El usuario no puede crear la factura otra vez.
Podemos implementar esta funcionalidad con un ligero refinamiento de
CrearFacturaDesdePedido,
así:
public void execute() throws Exception {
...
// Todo ha ido bien, por tanto ocultamos la acción
removeActions("Pedido.crearFactura");
}
Como puedes ver simplemente añadimos
removeActions("Pedido.crearFactura")
al final del método
execute().
Mostrar y ocultar acciones no es un sustituto para la validación en el
modelo. Las validaciones siguen siendo necesarias porque las entidades
pueden ser usadas desde cualquier otra parte de la aplicación, no solo de
los módulos de mantenimiento. Sin embargo, el truco de ocultar y mostrar
acciones mejora la experiencia del usuario.
Lógica de negocio
desde el modo lista
En la lección anterior aprendiste como crear acciones de lista. Las
acciones de lista son una herramienta utilísima para dar al usuario la
posibilidad de aplicar lógica a varios objetos a la vez. En nuestro caso,
podemos añadir una acción en el modo lista para crear una nueva factura
automáticamente a partir de varios pedidos seleccionados en la lista, de
esta manera:

Aquí se muestra como esta acción de lista coge los pedidos seleccionados y
crea una factura a partir de ellos. Simplemente copia los datos del pedido
en la nueva factura, añadiendo las línea de detalle de todos los pedidos
en una única factura. También se muestra un mensaje. Veamos como codificar
este comportamiento.
Acción de lista con
lógica propia
Como ya sabes, el primer paso para tener una acción propia en tu módulo es
añadirla a un controlador. Por tanto, editemos
controladores.xml
añadiendo una nueva acción al controlador
Pedido:
<controlador nombre="Pedido">
...
<!-- La nueva acción -->
<accion nombre="crearFacturaDesdePedidosSeleccionados"
modo="list"
clase="com.tuempresa.facturacion.acciones.CrearFacturaDesdePedidosSeleccionados"/>
<!-- modo="list": Sólo se muestra en modo lista -->
</controlador>
Solo con esto ya tienes una nueva acción disponible para
Pedido
en modo lista.
Ahora hemos de escribir el código Java para la acción:
package com.tuempresa.facturacion.acciones;
import java.util.*;
import javax.ejb.*;
import org.openxava.actions.*;
import org.openxava.model.*;
import com.tuempresa.facturacion.modelo.*;
public class CrearFacturaDesdePedidosSeleccionados
extends TabBaseAction { // Tipico de acciones de lista. Permite usar getTab() (1)
public void execute() throws Exception {
Collection<Pedido> pedidos = getPedidosSeleccionados(); // (2)
Factura factura = Factura.crearDesdePedidos(pedidos); // (3)
addMessage("factura_creada_desde_pedidos", factura, pedidos); // (4)
}
private Collection<Pedido> getPedidosSeleccionados() // (5)
throws FinderException
{
Collection<Pedido> pedidos = new ArrayList<>();
for (Map key: getTab().getSelectedKeys()) { // (6)
Pedido pedido = (Pedido) MapFacade.findEntity("Pedido", key); // (7)
pedidos.add(pedido);
}
return pedidos;
}
}
Realmente sencillo. Obtenemos la lista de los pedidos marcados en
la lista (2), llamamos al método estático
crearDesdePedidos() (3)
de
Factura y mostramos un mensaje (4). En este caso también
ponemos la lógica real en la clase del modelo, no en la acción. Dado que
la lógica aplica a varios pedidos y crea una nueva factura, el lugar
natural para ponerlo es en un método estático de la clase
Factura.
El método
getPedidosSeleccionados() (5) devuelve una colección con
las entidades
Pedido marcadas por el usuario en la lista. Para
hacerlo, el método usa
getTab() (6), disponible en
TabBaseAction
(1), que devuelve un objeto
org.openxava.tab.Tab. El objeto
Tab
te permite manejar los datos tabulares de la lista. En este caso usamos
getSelectedKeys()
(6) que devuelve una colección con las claves de las filas seleccionadas.
Dado que esas claves están en formato
Map usamos
MapFacade.findEntity()
(7) para convertirlas en entidades
Pedido.
Acuérdate de añadir el texto del mensaje al fichero
MensajesFacturacion_es.properties en la carpeta
i18n:
factura_creada_desde_pedidos=Factura {0} creada a partir de los pedidos: {1}
Eso es todo para la acción. Veamos la pieza que falta, el método
crearDesdePedidos() de la entidad
Factura.
Lógica
de negocio en el modelo sobre varias entidades
La lógica de negocio para crear una nueva
Factura a partir de
varias entidades
Pedido está en la capa del modelo, es decir, en
las entidades, no en la acción. No podemos poner el método en la clase
Pedido,
porque el proceso se hace a partir de varios pedidos, no de uno. No
podemos usar un método de instancia en
Factura porque todavía no
existe el objeto
Factura, de hecho lo que queremos es crearlo. Por
lo tanto, vamos a crear un método de factoría estático en la clase
Factura
para crear una nueva
Factura a partir de varios pedidos. Puedes
ver este método aquí:
public class Factura extends DocumentoComercial {
...
public static Factura crearDesdePedidos(Collection<Pedido> pedidos)
throws CrearFacturaException
{
Factura factura = null;
for (Pedido pedido: pedidos) {
if (factura == null) { // El primero pedido
pedido.crearFactura(); // Reutilizamos la lógica para crear una
// factura desde un pedido
factura = pedido.getFactura(); // y usamos la factura creada
}
else { // Para el resto de los pedidos la factura ya está creada
pedido.setFactura(factura); // Asigna la factura
pedido.copiarDetallesAFactura(); // Un método de Pedido para copiar las lineas
}
}
if (factura == null) { // Si no hay pedidos
throw new CrearFacturaException("pedidos_no_especificados");
}
return factura;
}
}
Usamos el primer
Pedido para crear una nueva
Factura
usando el método ya existente
crearFactura() de
Pedido.
Entonces llamamos a
copiarDetallesAFactura() de
Pedido
para copiar las líneas de los pedidos restantes a la nueva
Factura
acumulando en ella el
iva e
importeTotal de los pedidos.
Además, asignamos la nueva
Factura como la factura de los pedidos
de la colección.
Si
factura es nulo al final del proceso, es porque la colección
pedidos
está vacía. En este caso lanzamos una
CrearFacturaException, ya
que la acción no atrapa las excepciones, OpenXava muestra el mensaje de la
excepción al usuario. Esto está bien. Si el usuario no marca los pedido y
pulsa en el botón para crear la factura, le aparecerá ese mensaje de
error.
Como puedes ver, copia los
detalles del pedido actual a la factura y acumula el iva y el importeTotal.