Java tutorial
/* * The MIT License * * Copyright 2012 Universidad de Montemorelos A. C. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package mx.edu.um.mateo.inventario.dao.impl; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import mx.edu.um.mateo.general.dao.BaseDao; import mx.edu.um.mateo.general.model.Usuario; import mx.edu.um.mateo.general.utils.Constantes; import mx.edu.um.mateo.inventario.dao.CancelacionDao; import mx.edu.um.mateo.inventario.dao.EntradaDao; import mx.edu.um.mateo.inventario.model.Almacen; import mx.edu.um.mateo.inventario.model.Cancelacion; import mx.edu.um.mateo.inventario.model.Entrada; import mx.edu.um.mateo.inventario.model.Estatus; import mx.edu.um.mateo.inventario.model.Folio; import mx.edu.um.mateo.inventario.model.LoteEntrada; import mx.edu.um.mateo.inventario.model.LoteSalida; import mx.edu.um.mateo.inventario.model.Producto; import mx.edu.um.mateo.inventario.model.Salida; import mx.edu.um.mateo.inventario.model.XEntrada; import mx.edu.um.mateo.inventario.model.XLoteEntrada; import mx.edu.um.mateo.inventario.model.XLoteSalida; import mx.edu.um.mateo.inventario.model.XProducto; import mx.edu.um.mateo.inventario.model.XSalida; import mx.edu.um.mateo.inventario.utils.NoCuadraException; import mx.edu.um.mateo.inventario.utils.NoEstaAbiertaException; import mx.edu.um.mateo.inventario.utils.NoEstaCerradaException; import mx.edu.um.mateo.inventario.utils.NoSePuedeCerrarEnCeroException; import mx.edu.um.mateo.inventario.utils.NoSePuedeCerrarException; import mx.edu.um.mateo.inventario.utils.ProductoNoSoportaFraccionException; import org.hibernate.Criteria; import org.hibernate.LockOptions; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; /** * * @author J. David Mendoza <jdmendoza@um.edu.mx> */ @Repository @Transactional public class EntradaDaoHibernate extends BaseDao implements EntradaDao { @Autowired private CancelacionDao cancelacionDao; public EntradaDaoHibernate() { log.info("Nueva instancia de EntradaDao"); } @Override @Transactional(readOnly = true) public Map<String, Object> lista(Map<String, Object> params) { log.debug("Buscando lista de entradas con params {}", params); if (params == null) { params = new HashMap<>(); } if (!params.containsKey("max")) { params.put("max", 10); } else { params.put("max", Math.min((Integer) params.get("max"), 100)); } if (params.containsKey("pagina")) { Long pagina = (Long) params.get("pagina"); Long offset = (pagina - 1) * (Integer) params.get("max"); params.put("offset", offset.intValue()); } if (!params.containsKey("offset")) { params.put("offset", 0); } Criteria criteria = currentSession().createCriteria(Entrada.class); Criteria countCriteria = currentSession().createCriteria(Entrada.class); criteria.createAlias("estatus", "est"); countCriteria.createAlias("estatus", "est"); if (params.containsKey("almacen")) { criteria.createCriteria("almacen").add(Restrictions.idEq(params.get("almacen"))); countCriteria.createCriteria("almacen").add(Restrictions.idEq(params.get("almacen"))); } if (params.containsKey("proveedorId")) { criteria.createCriteria("proveedor").add(Restrictions.idEq(params.get("proveedorId"))); countCriteria.createCriteria("proveedor").add(Restrictions.idEq(params.get("proveedorId"))); } if (params.containsKey("fechaIniciado")) { log.debug("Buscando desde {}", params.get("fechaIniciado")); criteria.add(Restrictions.ge("fechaCreacion", params.get("fechaIniciado"))); countCriteria.add(Restrictions.ge("fechaCreacion", params.get("fechaIniciado"))); } else { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 1); log.debug("Asignando busqueda desde {}", calendar.getTime()); criteria.add(Restrictions.ge("fechaCreacion", calendar.getTime())); countCriteria.add(Restrictions.ge("fechaCreacion", calendar.getTime())); } if (params.containsKey("fechaTerminado")) { log.debug("Buscando hasta {}", params.get("fechaTerminado")); criteria.add(Restrictions.le("fechaCreacion", params.get("fechaTerminado"))); countCriteria.add(Restrictions.le("fechaCreacion", params.get("fechaTerminado"))); } if (params.containsKey(Constantes.ABIERTA) || params.containsKey(Constantes.CERRADA) || params.containsKey(Constantes.PENDIENTE) || params.containsKey(Constantes.FACTURADA) || params.containsKey(Constantes.CANCELADA) || params.containsKey(Constantes.DEVOLUCION)) { Disjunction propiedades = Restrictions.disjunction(); if (params.containsKey(Constantes.ABIERTA)) { propiedades.add(Restrictions.eq("est.nombre", Constantes.ABIERTA)); } if (params.containsKey(Constantes.CERRADA)) { propiedades.add(Restrictions.eq("est.nombre", Constantes.CERRADA)); } if (params.containsKey(Constantes.PENDIENTE)) { propiedades.add(Restrictions.eq("est.nombre", Constantes.PENDIENTE)); } if (params.containsKey(Constantes.FACTURADA)) { propiedades.add(Restrictions.eq("est.nombre", Constantes.FACTURADA)); } if (params.containsKey(Constantes.CANCELADA)) { propiedades.add(Restrictions.eq("est.nombre", Constantes.CANCELADA)); } criteria.add(propiedades); countCriteria.add(propiedades); if (params.containsKey(Constantes.DEVOLUCION)) { criteria.add(Restrictions.eq("devolucion", Boolean.TRUE)); countCriteria.add(Restrictions.eq("devolucion", Boolean.TRUE)); } } if (params.containsKey("filtro")) { String filtro = (String) params.get("filtro"); Disjunction propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.ilike("folio", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("factura", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("comentarios", filtro, MatchMode.ANYWHERE)); criteria.add(propiedades); countCriteria.add(propiedades); } if (params.containsKey("order")) { String campo = (String) params.get("order"); if (params.get("sort").equals("desc")) { criteria.addOrder(Order.desc(campo)); } else { criteria.addOrder(Order.asc(campo)); } } else { criteria.addOrder(Order.asc("est.prioridad")); } if (!params.containsKey("reporte")) { criteria.setFirstResult((Integer) params.get("offset")); criteria.setMaxResults((Integer) params.get("max")); } params.put("entradas", criteria.list()); countCriteria.setProjection(Projections.rowCount()); params.put("cantidad", (Long) countCriteria.list().get(0)); return params; } @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true) public List<Entrada> buscaEntradasParaFactura(Map<String, Object> params) { log.debug("Buscando lista de entradas con params {}", params); if (params == null) { params = new HashMap<>(); } if (!params.containsKey("max")) { params.put("max", 10); } else { params.put("max", Math.min((Integer) params.get("max"), 100)); } if (!params.containsKey("offset")) { params.put("offset", 0); } Criteria criteria = currentSession().createCriteria(Entrada.class); if (params.containsKey("almacen")) { criteria.createCriteria("almacen").add(Restrictions.idEq(params.get("almacen"))); } if (params.containsKey("filtro")) { String filtro = (String) params.get("filtro"); Disjunction propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.ilike("folio", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("factura", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("comentarios", filtro, MatchMode.ANYWHERE)); criteria.add(propiedades); } if (params.containsKey("facturaId")) { Query query = currentSession().createQuery( "select e.id from FacturaAlmacen f inner join f.entradas as e where f.id = :facturaId"); query.setLong("facturaId", (Long) params.get("facturaId")); List<Long> idsDeEntradas = query.list(); log.debug("idsDeEntradas: {}", idsDeEntradas); if (idsDeEntradas != null && idsDeEntradas.size() > 0) { criteria.add(Restrictions.not(Restrictions.in("id", idsDeEntradas))); } } criteria.add(Restrictions.eq("devolucion", Boolean.TRUE)); criteria.createCriteria("estatus").add(Restrictions.eq("nombre", Constantes.CERRADA)); criteria.addOrder(Order.desc("fechaModificacion")); criteria.setFirstResult((Integer) params.get("offset")); criteria.setMaxResults((Integer) params.get("max")); return criteria.list(); } @Override @Transactional(readOnly = true) public Entrada obtiene(Long id) { return (Entrada) currentSession().get(Entrada.class, id); } @Override @Transactional(readOnly = true) public Entrada carga(Long id) { return (Entrada) currentSession().load(Entrada.class, id); } @Override public Entrada crea(Entrada entrada, Usuario usuario) { Session session = currentSession(); if (usuario != null) { entrada.setAlmacen(usuario.getAlmacen()); } Query query = currentSession().createQuery("select e from Estatus e where e.nombre = :nombre"); query.setString("nombre", Constantes.ABIERTA); Estatus estatus = (Estatus) query.uniqueResult(); entrada.setEstatus(estatus); entrada.setFolio(getFolioTemporal(entrada.getAlmacen())); Date fecha = new Date(); entrada.setFechaCreacion(fecha); entrada.setFechaModificacion(fecha); session.save(entrada); audita(entrada, usuario, Constantes.CREAR, fecha, false); session.flush(); return entrada; } @Override public Entrada crea(Entrada entrada) { return this.crea(entrada, null); } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class }) public Entrada actualiza(Entrada entrada) throws NoEstaAbiertaException { return this.actualiza(entrada, null); } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class }) public Entrada actualiza(Entrada otraEntrada, Usuario usuario) throws NoEstaAbiertaException { Entrada entrada = (Entrada) currentSession().get(Entrada.class, otraEntrada.getId()); switch (entrada.getEstatus().getNombre()) { case Constantes.ABIERTA: Session session = currentSession(); entrada.setVersion(otraEntrada.getVersion()); entrada.setFactura(otraEntrada.getFactura()); entrada.setFechaFactura(otraEntrada.getFechaFactura()); entrada.setComentarios(otraEntrada.getComentarios()); entrada.setTipoCambio(otraEntrada.getTipoCambio()); entrada.setDevolucion(otraEntrada.getDevolucion()); entrada.setIva(otraEntrada.getIva()); entrada.setTotal(otraEntrada.getTotal()); entrada.setProveedor(otraEntrada.getProveedor()); Date fecha = new Date(); entrada.setFechaModificacion(fecha); session.update(entrada); audita(entrada, usuario, Constantes.ACTUALIZAR, fecha, false); session.flush(); return entrada; default: throw new NoEstaAbiertaException("No se puede actualizar una entrada que no este abierta"); } } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class, NoSePuedeCerrarException.class, NoCuadraException.class, NoSePuedeCerrarEnCeroException.class }) public String pendiente(Long entradaId, Usuario usuario) throws NoSePuedeCerrarException, NoCuadraException, NoSePuedeCerrarEnCeroException, NoEstaAbiertaException { Entrada entrada = (Entrada) currentSession().get(Entrada.class, entradaId); if (entrada != null) { if (entrada.getEstatus().getNombre().equals(Constantes.ABIERTA)) { if (usuario != null) { entrada.setAlmacen(usuario.getAlmacen()); } Date fecha = new Date(); entrada = preparaParaCerrar(entrada, usuario, fecha); Query query = currentSession().createQuery("select e from Estatus e where e.nombre = :nombre"); query.setString("nombre", Constantes.PENDIENTE); Estatus estatus = (Estatus) query.uniqueResult(); entrada.setEstatus(estatus); entrada.setFolio(getFolio(entrada.getAlmacen())); entrada.setFechaModificacion(fecha); currentSession().update(entrada); audita(entrada, usuario, Constantes.ACTUALIZAR, fecha, true); currentSession().flush(); return entrada.getFolio(); } else { throw new NoEstaAbiertaException("No se puede actualizar una entrada que no este abierta"); } } else { throw new NoSePuedeCerrarException("No se puede cerrar la entrada pues no existe"); } } @Override @Transactional(rollbackFor = { NoSePuedeCerrarException.class, NoCuadraException.class, NoSePuedeCerrarEnCeroException.class, NoEstaAbiertaException.class }) public String cierra(Long entradaId, Usuario usuario) throws NoSePuedeCerrarException, NoCuadraException, NoSePuedeCerrarEnCeroException, NoEstaAbiertaException { Entrada entrada = (Entrada) currentSession().get(Entrada.class, entradaId); entrada = cierra(entrada, usuario); return entrada.getFolio(); } @Override @Transactional(rollbackFor = { NoSePuedeCerrarException.class, NoCuadraException.class, NoSePuedeCerrarEnCeroException.class, NoEstaAbiertaException.class }) public Entrada cierra(Entrada entrada, Usuario usuario) throws NoSePuedeCerrarException, NoCuadraException, NoSePuedeCerrarEnCeroException, NoEstaAbiertaException { if (entrada != null) { if (entrada.getEstatus().getNombre().equals(Constantes.ABIERTA)) { if (usuario != null) { entrada.setAlmacen(usuario.getAlmacen()); } Date fecha = new Date(); entrada = preparaParaCerrar(entrada, usuario, fecha); Query query = currentSession().createQuery("select e from Estatus e where e.nombre = :nombre"); query.setString("nombre", Constantes.CERRADA); Estatus estatus = (Estatus) query.uniqueResult(); entrada.setEstatus(estatus); entrada.setFolio(getFolio(entrada.getAlmacen())); entrada.setFechaModificacion(fecha); currentSession().update(entrada); audita(entrada, usuario, Constantes.ACTUALIZAR, fecha, true); currentSession().flush(); return entrada; } else { throw new NoEstaAbiertaException("No se puede actualizar una entrada que no este abierta"); } } else { throw new NoSePuedeCerrarException("No se puede cerrar la entrada pues no existe"); } } @Override @Transactional(rollbackFor = { NoSePuedeCerrarException.class }) public Entrada cierraPendiente(Entrada entrada, Usuario usuario) throws NoSePuedeCerrarException { Entrada pendiente = (Entrada) currentSession().get(Entrada.class, entrada.getId()); if (entrada.getVersion() != pendiente.getVersion()) { throw new NoSePuedeCerrarException("No es la ultima version de la entrada"); } pendiente.setFactura(entrada.getFactura()); pendiente.setFechaFactura(entrada.getFechaFactura()); pendiente.setComentarios(entrada.getComentarios()); entrada = pendiente; Query query = currentSession().createQuery("select e from Estatus e where e.nombre = :nombre"); query.setString("nombre", Constantes.CERRADA); Estatus estatus = (Estatus) query.uniqueResult(); entrada.setEstatus(estatus); Date fecha = new Date(); entrada.setFechaModificacion(fecha); currentSession().update(entrada); audita(entrada, usuario, Constantes.ACTUALIZAR, fecha, false); currentSession().flush(); return entrada; } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class }) public String elimina(Long id) throws NoEstaAbiertaException { return this.elimina(id, null); } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class }) public String elimina(Long id, Usuario usuario) throws NoEstaAbiertaException { Entrada entrada = obtiene(id); if (entrada.getEstatus().getNombre().equals(Constantes.ABIERTA)) { String nombre = entrada.getFolio(); currentSession().delete(entrada); audita(entrada, usuario, Constantes.ELIMINAR, new Date(), false); currentSession().flush(); return nombre; } else { throw new NoEstaAbiertaException("No se puede eliminar una entrada que no este abierta"); } } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class, ProductoNoSoportaFraccionException.class }) public LoteEntrada creaLote(LoteEntrada lote) throws ProductoNoSoportaFraccionException, NoEstaAbiertaException { log.debug("Creando lote {}", lote); lote.setProducto((Producto) currentSession().get(Producto.class, lote.getProducto().getId())); lote.setEntrada((Entrada) currentSession().get(Entrada.class, lote.getEntrada().getId())); if (lote.getEntrada().getEstatus().getNombre().equals(Constantes.ABIERTA)) { if (!lote.getProducto().getFraccion()) { BigDecimal[] resultado = lote.getCantidad().divideAndRemainder(new BigDecimal("1")); if (resultado[1].doubleValue() > 0) { throw new ProductoNoSoportaFraccionException(); } } BigDecimal subtotal = lote.getPrecioUnitario().multiply(lote.getCantidad()); BigDecimal iva = subtotal.multiply(lote.getProducto().getIva()).setScale(2, RoundingMode.HALF_UP); lote.setIva(iva); lote.setFechaCreacion(new Date()); currentSession().save(lote); return lote; } else { throw new NoEstaAbiertaException("No se puede crear un lote en una entrada que no este abierta"); } } @Override @Transactional(rollbackFor = { NoEstaAbiertaException.class }) public Long eliminaLote(Long id) throws NoEstaAbiertaException { log.debug("Eliminando lote {}", id); LoteEntrada lote = (LoteEntrada) currentSession().get(LoteEntrada.class, id); if (lote.getEntrada().getEstatus().getNombre().equals(Constantes.ABIERTA)) { id = lote.getEntrada().getId(); currentSession().delete(lote); currentSession().flush(); return id; } throw new NoEstaAbiertaException("No se pudo eliminar el lote " + id); } private String getFolioTemporal(Almacen almacen) { Query query = currentSession() .createQuery("select f from Folio f where f.nombre = :nombre and f.almacen.id = :almacenId"); query.setString("nombre", "ENTRADA-TEMPORAL"); query.setLong("almacenId", almacen.getId()); query.setLockOptions(LockOptions.UPGRADE); Folio folio = (Folio) query.uniqueResult(); if (folio == null) { folio = new Folio("ENTRADA-TEMPORAL"); folio.setAlmacen(almacen); currentSession().save(folio); currentSession().flush(); return getFolioTemporal(almacen); } folio.setValor(folio.getValor() + 1); java.text.NumberFormat nf = java.text.DecimalFormat.getInstance(); nf.setGroupingUsed(false); nf.setMinimumIntegerDigits(9); nf.setMaximumIntegerDigits(9); nf.setMaximumFractionDigits(0); StringBuilder sb = new StringBuilder(); sb.append("TE-"); sb.append(almacen.getEmpresa().getOrganizacion().getCodigo()); sb.append(almacen.getEmpresa().getCodigo()); sb.append(almacen.getCodigo()); sb.append(nf.format(folio.getValor())); return sb.toString(); } private String getFolio(Almacen almacen) { Query query = currentSession() .createQuery("select f from Folio f where f.nombre = :nombre and f.almacen.id = :almacenId"); query.setString("nombre", "ENTRADA"); query.setLong("almacenId", almacen.getId()); query.setLockOptions(LockOptions.UPGRADE); Folio folio = (Folio) query.uniqueResult(); if (folio == null) { folio = new Folio("ENTRADA"); folio.setAlmacen(almacen); currentSession().save(folio); return getFolio(almacen); } folio.setValor(folio.getValor() + 1); java.text.NumberFormat nf = java.text.DecimalFormat.getInstance(); nf.setGroupingUsed(false); nf.setMinimumIntegerDigits(9); nf.setMaximumIntegerDigits(9); nf.setMaximumFractionDigits(0); StringBuilder sb = new StringBuilder(); sb.append("E-"); sb.append(almacen.getEmpresa().getOrganizacion().getCodigo()); sb.append(almacen.getEmpresa().getCodigo()); sb.append(almacen.getCodigo()); sb.append(nf.format(folio.getValor())); return sb.toString(); } private BigDecimal costoPromedio(LoteEntrada lote) { Producto producto = lote.getProducto(); BigDecimal cantidad = lote.getCantidad(); BigDecimal viejoBalance = producto.getPrecioUnitario().multiply(producto.getExistencia()); BigDecimal nuevoBalance = lote.getPrecioUnitario().multiply(cantidad); BigDecimal balanceTotal = viejoBalance.add(nuevoBalance); BigDecimal articulos = cantidad.add(producto.getExistencia()); return balanceTotal.divide(articulos, 10, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP); } private Entrada preparaParaCerrar(Entrada entrada, Usuario usuario, Date fecha) throws NoCuadraException, NoSePuedeCerrarEnCeroException { BigDecimal iva = entrada.getIva(); BigDecimal total = entrada.getTotal(); entrada.setIva(BigDecimal.ZERO); entrada.setTotal(BigDecimal.ZERO); for (LoteEntrada lote : entrada.getLotes()) { Producto producto = lote.getProducto(); producto.setPrecioUnitario(costoPromedio(lote)); if (!entrada.getDevolucion()) { producto.setUltimoPrecio(lote.getPrecioUnitario()); } producto.setExistencia(producto.getExistencia().add(lote.getCantidad())); producto.setFechaModificacion(fecha); currentSession().update(producto); auditaProducto(producto, usuario, Constantes.ACTUALIZAR, entrada.getId(), null, fecha); BigDecimal subtotal = lote.getPrecioUnitario().multiply(lote.getCantidad()); entrada.setIva(entrada.getIva().add(lote.getIva())); entrada.setTotal(entrada.getTotal().add(subtotal.add(lote.getIva()))); } if (total.equals(BigDecimal.ZERO)) { throw new NoSePuedeCerrarEnCeroException("No se puede cerrar la entrada en cero"); } // Si tanto el iva o el total difieren mas de un 5% del valor que // viene en la factura lanzar excepcion if (iva.compareTo(entrada.getIva()) != 0 || total.compareTo(entrada.getTotal()) != 0) { BigDecimal variacion = new BigDecimal("0.05"); BigDecimal topeIva = entrada.getIva().multiply(variacion); BigDecimal topeTotal = entrada.getTotal().multiply(variacion); if (iva.compareTo(entrada.getIva()) < 0 || total.compareTo(entrada.getTotal()) < 0) { if (iva.compareTo(entrada.getIva().subtract(topeIva)) >= 0 && total.compareTo(entrada.getTotal().subtract(topeTotal)) >= 0) { // todavia puede pasar } else { throw new NoCuadraException("No se puede cerrar porque no cuadran los totales"); } } else { if (iva.compareTo(entrada.getIva().add(topeIva)) <= 0 && total.compareTo(entrada.getTotal().add(topeTotal)) <= 0) { // todavia puede pasar } else { throw new NoCuadraException("No se puede cerrar porque no cuadran los totales"); } } } return entrada; } @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true) public Map<String, Object> preCancelacion(Long id, Usuario usuario) throws NoEstaCerradaException { log.info("{} mando llamar precancelacion de entrada {}", usuario, id); Entrada entrada = (Entrada) currentSession().get(Entrada.class, id); if (entrada.getEstatus().getNombre().equals(Constantes.CERRADA) || entrada.getEstatus().getNombre().equals(Constantes.FACTURADA)) { Set<Producto> productos = new HashSet<>(); for (LoteEntrada lote : entrada.getLotes()) { productos.add(lote.getProducto()); } log.debug("Buscando entradas que contengan los productos {} despues de la fecha {}", productos, entrada.getFechaModificacion()); Query query = currentSession() .createQuery("select e from Entrada e inner join e.lotes le inner join e.estatus es " + "where(es.nombre = 'CERRADA' or es.nombre = 'PENDIENTE') " + "and le.producto in (:productos) " + "and e.fechaModificacion > :fecha"); query.setParameterList("productos", productos); query.setTimestamp("fecha", entrada.getFechaModificacion()); List<Entrada> entradas = (List<Entrada>) query.list(); for (Entrada e : entradas) { log.debug("ENTRADA: {}", e); for (LoteEntrada lote : e.getLotes()) { productos.add(lote.getProducto()); } } entradas.add(entrada); query = currentSession() .createQuery("select s from Salida s inner join s.lotes ls inner join s.estatus es " + "where es.nombre = 'CERRADA' " + "and ls.producto in (:productos) " + "and s.fechaModificacion > :fecha"); query.setParameterList("productos", productos); query.setTimestamp("fecha", entrada.getFechaModificacion()); List<Salida> salidas = (List<Salida>) query.list(); for (Salida salida : salidas) { log.debug("SALIDA: {}", salida); for (LoteSalida lote : salida.getLotes()) { productos.add(lote.getProducto()); } } Map<Long, Producto> productosCancelados = new HashMap<>(); Map<Long, Producto> productosSinHistoria = new HashMap<>(); for (Producto producto : productos) { log.debug("Buscando historial de {}", producto); query = currentSession() .createQuery("select xp from XProducto xp " + "where xp.productoId = :productoId " + "and (xp.actividad = 'CREAR' or actividad = 'ACTUALIZAR') " + "and xp.fechaCreacion < :fecha " + "and (xp.entradaId is null or xp.entradaId != :entradaId) " + "order by xp.fechaCreacion desc"); query.setLong("productoId", producto.getId()); query.setTimestamp("fecha", entrada.getFechaModificacion()); query.setLong("entradaId", entrada.getId()); query.setMaxResults(1); List<XProducto> xproductos = (List<XProducto>) query.list(); if (xproductos != null && xproductos.get(0) != null) { XProducto xproducto = xproductos.get(0); log.debug("Encontre historia del producto {}", xproducto); Producto p = new Producto(); BeanUtils.copyProperties(xproducto, p); p.setTipoProducto(producto.getTipoProducto()); p.setAlmacen(producto.getAlmacen()); productosCancelados.put(producto.getId(), p); } else { log.debug("No encontre historia del producto {}", producto); Producto p = new Producto(); BeanUtils.copyProperties(producto, p); p.setPrecioUnitario(BigDecimal.ZERO); p.setUltimoPrecio(BigDecimal.ZERO); p.setExistencia(BigDecimal.ZERO); productosSinHistoria.put(producto.getId(), p); } } Map<String, Object> resultado = new HashMap<>(); resultado.put("entrada", entrada); resultado.put("productos", productos); if (entradas != null && entradas.size() > 0) { resultado.put("entradas", entradas); } if (salidas != null && salidas.size() > 0) { resultado.put("salidas", salidas); } if (productosCancelados.size() > 0) { resultado.put("productosCancelados", productosCancelados.values()); } if (productosSinHistoria.size() > 0) { resultado.put("productosSinHistoria", productosSinHistoria.values()); } return resultado; } else { throw new NoEstaCerradaException("La entrada no se puede cancelar porque no esta cerrada o facturada", entrada); } } @SuppressWarnings("unchecked") @Override @Transactional(rollbackFor = { NoEstaCerradaException.class }) public Cancelacion cancelar(Long id, Usuario usuario, String comentarios) throws NoEstaCerradaException { log.info("{} esta cancelando entrada {}", usuario, id); Entrada entrada = (Entrada) currentSession().get(Entrada.class, id); if (entrada.getEstatus().getNombre().equals(Constantes.CERRADA) || entrada.getEstatus().getNombre().equals(Constantes.FACTURADA)) { Set<Producto> productos = new HashSet<>(); for (LoteEntrada lote : entrada.getLotes()) { productos.add(lote.getProducto()); } log.debug("Buscando entradas que contengan los productos {} despues de la fecha {}", productos, entrada.getFechaModificacion()); Query query = currentSession() .createQuery("select e from Entrada e inner join e.lotes le inner join e.estatus es " + "where(es.nombre = 'CERRADA' or es.nombre = 'PENDIENTE') " + "and le.producto in (:productos) " + "and e.fechaModificacion > :fecha"); query.setParameterList("productos", productos); query.setTimestamp("fecha", entrada.getFechaModificacion()); List<Entrada> entradas = (List<Entrada>) query.list(); for (Entrada e : entradas) { log.debug("ENTRADA: {}", e); for (LoteEntrada lote : e.getLotes()) { productos.add(lote.getProducto()); } } entradas.add(entrada); query = currentSession() .createQuery("select s from Salida s inner join s.lotes ls inner join s.estatus es " + "where es.nombre = 'CERRADA' " + "and ls.producto in (:productos) " + "and s.fechaModificacion > :fecha"); query.setParameterList("productos", productos); query.setTimestamp("fecha", entrada.getFechaModificacion()); List<Salida> salidas = (List<Salida>) query.list(); for (Salida s : salidas) { log.debug("SALIDA: {}", s); for (LoteSalida lote : s.getLotes()) { productos.add(lote.getProducto()); } } Date fecha = new Date(); for (Producto producto : productos) { log.debug("Buscando historial de {}", producto); query = currentSession() .createQuery("select xp from XProducto xp " + "where xp.productoId = :productoId " + "and (xp.actividad = 'CREAR' or actividad = 'ACTUALIZAR') " + "and xp.fechaCreacion < :fecha " + "and (xp.entradaId is null or xp.entradaId != :entradaId) " + "order by xp.fechaCreacion desc"); query.setLong("productoId", producto.getId()); query.setTimestamp("fecha", entrada.getFechaModificacion()); query.setLong("entradaId", entrada.getId()); query.setMaxResults(1); List<XProducto> xproductos = (List<XProducto>) query.list(); if (xproductos != null && xproductos.get(0) != null) { XProducto xproducto = xproductos.get(0); log.debug("Encontre historia del producto {}", xproducto); producto.setPrecioUnitario(xproducto.getPrecioUnitario()); producto.setUltimoPrecio(xproducto.getUltimoPrecio()); producto.setExistencia(xproducto.getExistencia()); producto.setFechaModificacion(fecha); } else { log.debug("No encontre historia del producto {}", producto); producto.setPrecioUnitario(BigDecimal.ZERO); producto.setUltimoPrecio(BigDecimal.ZERO); producto.setExistencia(BigDecimal.ZERO); producto.setFechaModificacion(fecha); } currentSession().update(producto); } query = currentSession().createQuery("select e from Estatus e where e.nombre = :nombre"); query.setString("nombre", Constantes.CANCELADA); Estatus cancelada = (Estatus) query.uniqueResult(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String fechaString = sdf.format(fecha); for (Entrada e : entradas) { e.setFactura(e.getFactura() + "C" + fechaString); e.setEstatus(cancelada); e.setFechaModificacion(fecha); currentSession().update(e); audita(e, usuario, Constantes.CANCELAR, fecha, true); } for (Salida s : salidas) { s.setReporte(s.getReporte() + "C" + fechaString); s.setEstatus(cancelada); s.setFechaModificacion(fecha); currentSession().update(s); auditaSalida(s, usuario, Constantes.CANCELAR, fecha, true); } // Crear cancelacion Cancelacion cancelacion = new Cancelacion(); cancelacion.setFolio(cancelacionDao.getFolio(entrada.getAlmacen())); cancelacion.setComentarios(comentarios); cancelacion.setEntrada(entrada); cancelacion.setProductos(productos); if (entradas != null && entradas.size() > 0) { cancelacion.setEntradas(entradas); } if (salidas != null && salidas.size() > 0) { cancelacion.setSalidas(salidas); } cancelacion = cancelacionDao.crea(cancelacion, usuario); currentSession().flush(); for (Producto producto : productos) { auditaProducto(producto, usuario, Constantes.CANCELAR, null, cancelacion.getId(), fecha); } return cancelacion; } else { throw new NoEstaCerradaException("La entrada no se puede cancelar porque no esta cerrada o facturada", entrada); } } private void auditaProducto(Producto producto, Usuario usuario, String actividad, Long entradaId, Long cancelacionId, Date fecha) { XProducto xproducto = new XProducto(); BeanUtils.copyProperties(producto, xproducto, new String[] { "id", "version" }); xproducto.setId(null); xproducto.setProductoId(producto.getId()); xproducto.setEntradaId(entradaId); xproducto.setCancelacionId(cancelacionId); xproducto.setTipoProductoId(producto.getTipoProducto().getId()); xproducto.setAlmacenId(producto.getAlmacen().getId()); xproducto.setFechaCreacion(fecha); xproducto.setActividad(actividad); xproducto.setCreador((usuario != null) ? usuario.getUsername() : "sistema"); currentSession().save(xproducto); } private void audita(Entrada entrada, Usuario usuario, String actividad, Date fecha, Boolean conLotes) { XEntrada xentrada = new XEntrada(); BeanUtils.copyProperties(entrada, xentrada, new String[] { "id", "version" }); xentrada.setEntradaId(entrada.getId()); xentrada.setAlmacenId(entrada.getAlmacen().getId()); xentrada.setProveedorId(entrada.getProveedor().getId()); xentrada.setEstatusId(entrada.getEstatus().getId()); xentrada.setFechaCreacion(fecha); xentrada.setActividad(actividad); xentrada.setCreador((usuario != null) ? usuario.getUsername() : "sistema"); currentSession().save(xentrada); if (conLotes) { for (LoteEntrada lote : entrada.getLotes()) { XLoteEntrada xlote = new XLoteEntrada(); BeanUtils.copyProperties(lote, xlote, new String[] { "id", "version" }); xlote.setLoteEntradaId(lote.getId()); xlote.setEntradaId(entrada.getId()); xlote.setProductoId(lote.getProducto().getId()); xlote.setActividad(actividad); xlote.setCreador((usuario != null) ? usuario.getUsername() : "sistema"); xlote.setFechaCreacion(fecha); currentSession().save(xlote); } } } private void auditaSalida(Salida salida, Usuario usuario, String actividad, Date fecha, Boolean conLotes) { XSalida xsalida = new XSalida(); BeanUtils.copyProperties(salida, xsalida, new String[] { "id", "version" }); xsalida.setSalidaId(salida.getId()); xsalida.setAlmacenId(salida.getAlmacen().getId()); xsalida.setClienteId(salida.getCliente().getId()); xsalida.setEstatusId(salida.getEstatus().getId()); xsalida.setFechaCreacion(fecha); xsalida.setActividad(actividad); xsalida.setCreador((usuario != null) ? usuario.getUsername() : "sistema"); currentSession().save(xsalida); if (conLotes) { for (LoteSalida lote : salida.getLotes()) { XLoteSalida xlote = new XLoteSalida(); BeanUtils.copyProperties(lote, xlote, new String[] { "id", "version" }); xlote.setLoteSalidaId(lote.getId()); xlote.setSalidaId(salida.getId()); xlote.setProductoId(lote.getProducto().getId()); xlote.setActividad(actividad); xlote.setCreador((usuario != null) ? usuario.getUsername() : "sistema"); xlote.setFechaCreacion(fecha); currentSession().save(xlote); } } } }