/*
* 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.SalidaDao;
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.NoEstaAbiertaException;
import mx.edu.um.mateo.inventario.utils.NoEstaCerradaException;
import mx.edu.um.mateo.inventario.utils.NoHayExistenciasSuficientes;
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 SalidaDaoHibernate extends BaseDao implements SalidaDao {
@Autowired
private CancelacionDao cancelacionDao;
public SalidaDaoHibernate() {
log.info("Nueva instancia de SalidaDao");
}
@Override
@Transactional(readOnly = true)
public Map<String, Object> lista(Map<String, Object> params) {
log.debug("Buscando lista de salidas 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(Salida.class);
Criteria countCriteria = currentSession().createCriteria(Salida.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("clienteId")) {
criteria.createCriteria("cliente").add(
Restrictions.idEq(params.get("clienteId")));
countCriteria.createCriteria("cliente").add(
Restrictions.idEq(params.get("clienteId")));
}
if (params.containsKey("estatusId")) {
criteria.createCriteria("estatus").add(
Restrictions.idEq(params.get("estatusId")));
countCriteria.createCriteria("estatus").add(
Restrictions.idEq(params.get("estatusId")));
}
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)) {
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("filtro")) {
String filtro = (String) params.get("filtro");
Disjunction propiedades = Restrictions.disjunction();
propiedades.add(Restrictions.ilike("folio", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("reporte", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("empleado", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("departamento", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("atendio", 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 if (!params.containsKey("estatusId")) {
criteria.addOrder(Order.asc("est.prioridad"));
}
criteria.addOrder(Order.desc("fechaModificacion"));
if (!params.containsKey("reporte")) {
criteria.setFirstResult((Integer) params.get("offset"));
criteria.setMaxResults((Integer) params.get("max"));
}
params.put("salidas", criteria.list());
countCriteria.setProjection(Projections.rowCount());
params.put("cantidad", (Long) countCriteria.list().get(0));
return params;
}
@SuppressWarnings("unchecked")
@Override
@Transactional(readOnly = true)
public List<Salida> buscaSalidasParaFactura(Map<String, Object> params) {
log.debug("Buscando lista de salidas 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(Salida.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("reporte", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("empleado", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("departamento", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("atendio", filtro,
MatchMode.ANYWHERE));
propiedades.add(Restrictions.ilike("comentarios", filtro,
MatchMode.ANYWHERE));
criteria.add(propiedades);
}
if (params.containsKey("facturaId")) {
Query query = currentSession().createQuery("select s.id from FacturaAlmacen f inner join f.salidas as s where f.id = :facturaId");
query.setLong("facturaId", (Long) params.get("facturaId"));
List<Long> idsDeSalidas = query.list();
log.debug("idsDeSalidas: {}", idsDeSalidas);
if (idsDeSalidas != null && idsDeSalidas.size() > 0) {
criteria.add(Restrictions.not(Restrictions.in("id", idsDeSalidas)));
}
}
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 Salida obtiene(Long id) {
return (Salida) currentSession().get(Salida.class, id);
}
@Override
@Transactional(readOnly = true)
public Salida carga(Long id) {
return (Salida) currentSession().load(Salida.class, id);
}
@Override
public Salida crea(Salida salida, Usuario usuario) {
Session session = currentSession();
if (usuario != null) {
salida.setAlmacen(usuario.getAlmacen());
salida.setAtendio(usuario.getUsername());
}
Query query = currentSession().createQuery(
"select e from Estatus e where e.nombre = :nombre");
query.setString("nombre", Constantes.ABIERTA);
Estatus estatus = (Estatus) query.uniqueResult();
salida.setEstatus(estatus);
salida.setFolio(getFolioTemporal(salida.getAlmacen()));
Date fecha = new Date();
salida.setFechaCreacion(fecha);
salida.setFechaModificacion(fecha);
session.save(salida);
audita(salida, usuario, Constantes.CREAR, fecha, false);
session.flush();
return salida;
}
@Override
public Salida crea(Salida salida) {
return this.crea(salida, null);
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class})
public Salida actualiza(Salida salida) throws NoEstaAbiertaException {
return this.actualiza(salida, null);
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class})
public Salida actualiza(Salida otraSalida, Usuario usuario)
throws NoEstaAbiertaException {
Salida salida = (Salida) currentSession().get(Salida.class,
otraSalida.getId());
switch (salida.getEstatus().getNombre()) {
case Constantes.ABIERTA:
Session session = currentSession();
salida.setVersion(otraSalida.getVersion());
salida.setReporte(otraSalida.getReporte());
salida.setEmpleado(otraSalida.getEmpleado());
salida.setComentarios(otraSalida.getComentarios());
if (usuario != null) {
salida.setAtendio(usuario.getUsername());
} else {
salida.setAtendio(otraSalida.getAtendio());
}
salida.setDepartamento(otraSalida.getDepartamento());
salida.setCliente(otraSalida.getCliente());
Date fecha = new Date();
salida.setFechaModificacion(fecha);
session.update(salida);
audita(salida, usuario, Constantes.ACTUALIZAR, fecha, false);
session.flush();
return salida;
default:
throw new NoEstaAbiertaException(
"No se puede actualizar una salida que no este abierta");
}
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class, NoHayExistenciasSuficientes.class, NoSePuedeCerrarException.class})
public String cierra(Long salidaId, Usuario usuario)
throws NoSePuedeCerrarException, NoHayExistenciasSuficientes,
NoEstaAbiertaException {
Salida salida = (Salida) currentSession().get(Salida.class, salidaId);
salida = cierra(salida, usuario);
return salida.getFolio();
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class, NoHayExistenciasSuficientes.class, NoSePuedeCerrarException.class})
public Salida cierra(Salida salida, Usuario usuario)
throws NoSePuedeCerrarException, NoHayExistenciasSuficientes,
NoEstaAbiertaException {
if (salida != null) {
if (salida.getEstatus().getNombre().equals(Constantes.ABIERTA)) {
if (usuario != null) {
salida.setAlmacen(usuario.getAlmacen());
}
salida.setIva(BigDecimal.ZERO);
salida.setTotal(BigDecimal.ZERO);
Date fecha = new Date();
for (LoteSalida lote : salida.getLotes()) {
Producto producto = lote.getProducto();
if (producto.getExistencia().subtract(lote.getCantidad())
.compareTo(BigDecimal.ZERO) < 0) {
throw new NoHayExistenciasSuficientes(
"No existen existencias suficientes de "
+ producto.getNombre(), producto);
}
lote.setPrecioUnitario(producto.getPrecioUnitario());
currentSession().update(lote);
producto.setExistencia(producto.getExistencia().subtract(
lote.getCantidad()));
producto.setFechaModificacion(fecha);
currentSession().update(producto);
auditaProducto(producto, usuario, Constantes.ACTUALIZAR,
salida.getId(), null, fecha);
BigDecimal subtotal = lote.getPrecioUnitario().multiply(
lote.getCantidad());
salida.setIva(salida.getIva().add(lote.getIva()));
salida.setTotal(salida.getTotal().add(
subtotal.add(lote.getIva())));
}
Query query = currentSession().createQuery(
"select e from Estatus e where e.nombre = :nombre");
query.setString("nombre", Constantes.CERRADA);
Estatus estatus = (Estatus) query.uniqueResult();
salida.setEstatus(estatus);
salida.setFolio(getFolio(salida.getAlmacen()));
salida.setAtendio(usuario.getApPaterno() + ", "+usuario.getApMaterno()+","
+ usuario.getNombre());
salida.setFechaModificacion(fecha);
currentSession().update(salida);
audita(salida, usuario, Constantes.ACTUALIZAR, fecha, true);
currentSession().flush();
return salida;
} else {
throw new NoEstaAbiertaException(
"No se puede actualizar una salida que no este abierta");
}
} else {
throw new NoSePuedeCerrarException(
"No se puede cerrar la salida pues no existe");
}
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class})
public String elimina(Long id) throws NoEstaAbiertaException {
Salida salida = obtiene(id);
if (salida.getEstatus().getNombre().equals(Constantes.ABIERTA)) {
String nombre = salida.getFolio();
currentSession().delete(salida);
audita(salida, null, Constantes.ELIMINAR, new Date(), false);
currentSession().flush();
return nombre;
} else {
throw new NoEstaAbiertaException(
"No se puede eliminar una salida que no este abierta");
}
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class, ProductoNoSoportaFraccionException.class})
public LoteSalida creaLote(LoteSalida lote)
throws ProductoNoSoportaFraccionException, NoEstaAbiertaException {
if (lote.getSalida().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();
}
}
lote.setPrecioUnitario(lote.getProducto().getPrecioUnitario());
BigDecimal subtotal = lote.getPrecioUnitario().multiply(
lote.getCantidad());
BigDecimal iva = subtotal.multiply(lote.getProducto().getIva())
.setScale(2, RoundingMode.HALF_UP);
lote.setIva(iva);
BigDecimal total = subtotal.add(iva).setScale(2,
RoundingMode.HALF_UP);
lote.setFechaCreacion(new Date());
currentSession().save(lote);
Salida salida = lote.getSalida();
salida.setIva(salida.getIva().add(iva));
salida.setTotal(salida.getTotal().add(total));
currentSession().save(salida);
currentSession().flush();
return lote;
} else {
throw new NoEstaAbiertaException(
"No se puede crear un lote en una salida que no este abierta");
}
}
@Override
@Transactional(rollbackFor = {NoEstaAbiertaException.class})
public Long eliminaLote(Long id) throws NoEstaAbiertaException {
log.debug("Eliminando lote {}", id);
LoteSalida lote = (LoteSalida) currentSession().get(LoteSalida.class,
id);
if (lote.getSalida().getEstatus().getNombre()
.equals(Constantes.ABIERTA)) {
id = lote.getSalida().getId();
Salida salida = lote.getSalida();
salida.setIva(salida.getIva().subtract(lote.getIva()));
salida.setTotal(salida.getTotal().subtract(lote.getTotal()));
currentSession().save(salida);
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", "SALIDA-TEMPORAL");
query.setLong("almacenId", almacen.getId());
query.setLockOptions(LockOptions.UPGRADE);
Folio folio = (Folio) query.uniqueResult();
if (folio == null) {
folio = new Folio("SALIDA-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("TS-");
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", "SALIDA");
query.setLong("almacenId", almacen.getId());
query.setLockOptions(LockOptions.UPGRADE);
Folio folio = (Folio) query.uniqueResult();
if (folio == null) {
folio = new Folio("SALIDA");
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("S-");
sb.append(almacen.getEmpresa().getOrganizacion().getCodigo());
sb.append(almacen.getEmpresa().getCodigo());
sb.append(almacen.getCodigo());
sb.append(nf.format(folio.getValor()));
return sb.toString();
}
@SuppressWarnings("unchecked")
@Override
@Transactional(readOnly = true)
public Map<String, Object> preCancelacion(Long id, Usuario usuario)
throws NoEstaCerradaException {
log.info("{} mando llamar precancelacion de salida {}", usuario, id);
Salida salida = (Salida) currentSession().get(Salida.class, id);
if (salida.getEstatus().getNombre().equals(Constantes.CERRADA)
|| salida.getEstatus().getNombre().equals(Constantes.FACTURADA)) {
Set<Producto> productos = new HashSet<>();
for (LoteSalida lote : salida.getLotes()) {
productos.add(lote.getProducto());
}
log.debug(
"Buscando entradas que contengan los productos {} despues de la fecha {}",
productos, salida.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", salida.getFechaModificacion());
List<Entrada> entradas = (List<Entrada>) query.list();
for (Entrada entrada : entradas) {
log.debug("ENTRADA: {}", entrada);
for (LoteEntrada lote : entrada.getLotes()) {
productos.add(lote.getProducto());
}
}
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", salida.getFechaModificacion());
List<Salida> salidas = (List<Salida>) query.list();
for (Salida otra : salidas) {
log.debug("SALIDA: {}", otra);
for (LoteSalida lote : otra.getLotes()) {
productos.add(lote.getProducto());
}
}
salidas.add(salida);
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.salidaId is null or xp.salidaId != :salidaId) "
+ "order by xp.fechaCreacion desc");
query.setLong("productoId", producto.getId());
query.setTimestamp("fecha", salida.getFechaModificacion());
query.setLong("salidaId", salida.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("salida", salida);
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 salida no se puede cancelar porque no esta cerrada o facturada",
salida);
}
}
@SuppressWarnings("unchecked")
@Override
@Transactional(rollbackFor = {NoEstaCerradaException.class})
public Cancelacion cancelar(Long id, Usuario usuario, String comentarios)
throws NoEstaCerradaException {
log.info("{} esta cancelando salida {}", usuario, id);
Salida salida = (Salida) currentSession().get(Salida.class, id);
if (salida.getEstatus().getNombre().equals(Constantes.CERRADA)
|| salida.getEstatus().getNombre().equals(Constantes.FACTURADA)) {
Set<Producto> productos = new HashSet<>();
for (LoteSalida lote : salida.getLotes()) {
productos.add(lote.getProducto());
}
log.debug(
"Buscando entradas que contengan los productos {} despues de la fecha {}",
productos, salida.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", salida.getFechaModificacion());
List<Entrada> entradas = (List<Entrada>) query.list();
for (Entrada entrada : entradas) {
log.debug("ENTRADA: {}", entrada);
for (LoteEntrada lote : entrada.getLotes()) {
productos.add(lote.getProducto());
}
}
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", salida.getFechaModificacion());
List<Salida> salidas = (List<Salida>) query.list();
for (Salida otra : salidas) {
log.debug("SALIDA: {}", otra);
for (LoteSalida lote : otra.getLotes()) {
productos.add(lote.getProducto());
}
}
salidas.add(salida);
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.salidaId is null or xp.salidaId != :salidaId) "
+ "order by xp.fechaCreacion desc");
query.setLong("productoId", producto.getId());
query.setTimestamp("fecha", salida.getFechaModificacion());
query.setLong("salidaId", salida.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 entrada : entradas) {
entrada.setFactura(entrada.getFactura() + "C" + fechaString);
entrada.setEstatus(cancelada);
entrada.setFechaModificacion(fecha);
currentSession().update(entrada);
auditaEntrada(entrada, usuario, Constantes.CANCELAR, fecha,
true);
}
for (Salida s : salidas) {
s.setReporte(s.getReporte() + "C" + fechaString);
s.setEstatus(cancelada);
s.setFechaModificacion(fecha);
currentSession().update(s);
audita(s, usuario, Constantes.CANCELAR, fecha, true);
}
// Crear cancelacion
Cancelacion cancelacion = new Cancelacion();
cancelacion.setFolio(cancelacionDao.getFolio(salida.getAlmacen()));
cancelacion.setComentarios(comentarios);
cancelacion.setSalida(salida);
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 salida no se puede cancelar porque no esta cerrada o facturada",
salida);
}
}
private void auditaProducto(Producto producto, Usuario usuario,
String actividad, Long salidaId, Long cancelacionId, Date fecha) {
XProducto xproducto = new XProducto();
BeanUtils.copyProperties(producto, xproducto);
xproducto.setId(null);
xproducto.setProductoId(producto.getId());
xproducto.setSalidaId(salidaId);
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 auditaEntrada(Entrada entrada, Usuario usuario,
String actividad, Date fecha, boolean conLotes) {
XEntrada xentrada = new XEntrada();
BeanUtils.copyProperties(entrada, xentrada);
xentrada.setId(null);
xentrada.setEntradaId(entrada.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 audita(Salida salida, Usuario usuario, String actividad,
Date fecha, boolean conLotes) {
XSalida xsalida = new XSalida();
BeanUtils.copyProperties(salida, xsalida);
xsalida.setId(null);
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);
}
}
}
}