openxava / documentación / Lección 11: @DefaultValueCalculator en colecciones
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 de valor por defecto multiusuario |
16. Sincronizar propiedades persistentes y calculadas |
17. Lógica desde la base de datos |
18. Validando con @EntityValidator |
19. Alternativas de validación |
20. Validación al borrar |
21. Anotación Bean Validation propia |
22. Llamada REST desde una validación |
23. Atributos en anotaciones |
24. Refinar el comportamiento predefinido |
25. Comportamiento y lógica de negocio |
26. Referencias y colecciones |
A. Arquitectura y filosofía |
B. Java Persistence API |
C. Anotaciones |
D. Pruebas automáticas
Hemos agregado lógica del negocio a nuestra aplicación utlizando propiedades persistentes y propiedas calculadas, ahora utilizaremos la anotación
@DefaultValueCalculator para las colecciones.
Si no te gustan los videos sigue las instrucciones a continuación.
Usar @DefaultValueCalculator
La forma en que calculamos el importe de la línea de detalle no es la mejor. Tiene, al menos, dos inconvenientes. El primero es que el usuario puede querer tener la posibilidad de cambiar el precio unitario. Y segundo, si el precio de un producto cambia los importes de todas las facturas cambian también, y esto no es bueno.
Para evitar estos inconvenientes lo mejor es almacenar el precio de cada producto en cada línea de detalle. Añadamos pues una propiedad persistente
precioPorUnidad a la clase
Detalle y calculemos su valor desde
precio de
Producto usando un
@DefaultValueCalculator. De tal forma que consigamos el efecto que puedes ver en la siguiente figura:
La lógica para calcular el valor inicial la tendremos en
CalculadorPrecioPorUnidad que simplemente lee el precio del producto. Observa el código de este calculador:
package com.tuempresa.facturacion.calculadores; // En el paquete calculadores
import org.openxava.calculators.*;
import com.tuempresa.facturacion.modelo.*;
import lombok.*;
import static org.openxava.jpa.XPersistence.*; //Para usar getManager()
public class CalculadorPrecioPorUnidad implements ICalculator {
@Getter @Setter
int numeroProducto;
@Override
public Object calculate() throws Exception {
Producto producto = getManager() // getManager() de XPersistence
.find(Producto.class, numeroProducto); // Busca el producto
return producto.getPrecio(); // Retorna su precio
}
}
El siguiente paso es añadir la propiedad precioPorUnidad. Añade el siguiente código a la clase Detalle:
@DefaultValueCalculator(
value=CalculadorPrecioPorUnidad.class, // Esta clase calcula el valor inicial
properties=@PropertyValue(
name="numeroProducto", // La propiedad numeroProducto del calculador...
from="producto.numero") // ... se llena con el valor de producto.numero de la entidad
)
@Money
BigDecimal precioPorUnidad; // Una propiedad persistente convencional
De esta forma cuando el usuario escoge un producto el campo de precio unitario se rellena con el precio del producto, pero dado que es una propiedad persistente, el usuario puede cambiar este valor. Y si en el futuro el precio del producto cambiara este precio unitario de la línea de detalle no cambiaría.
Esto implica que has de adaptar la propiedad calculada
importe:
@Money
@Depends("precioPorUnidad, cantidad") // precioPorUnidad en vez de producto.numero
public BigDecimal getImporte() {
if (precioPorUnidad == null) return BigDecimal.ZERO; // precioPorUnidad en vez de producto y producto.getPrecio()
return new BigDecimal(cantidad).multiply(precioPorUnidad); // precioPorUnidad en vez de producto.getPrecio()
}
Ahora
getImporte() usa
precioPorUnidad como fuente en lugar de
producto.precio.
Finalmente, debemos editar la entidad
DocumentoComercial y modificar la lista de propiedades de la colección para mostrar la nueva propiedad:
@ElementCollection
@ListProperties("producto.numero, producto.descripcion, cantidad, precioPorUnidad, importe") // precioPorUnidad añadida
Collection<Detalle> detalles;
Prueba los módulos
Pedido y
Factura y podrás observar el nuevo comportamiento al añadir líneas de detalle.