/* * 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.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import mx.edu.um.mateo.general.dao.BaseDao; import mx.edu.um.mateo.general.model.Imagen; import mx.edu.um.mateo.general.model.Usuario; import mx.edu.um.mateo.general.utils.Constantes; import mx.edu.um.mateo.inventario.dao.ProductoDao; import mx.edu.um.mateo.inventario.model.HistorialProducto; import mx.edu.um.mateo.inventario.model.Producto; import mx.edu.um.mateo.inventario.model.TipoProducto; import mx.edu.um.mateo.inventario.model.XProducto; import org.apache.commons.lang.StringUtils; import org.hibernate.Criteria; 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.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; /** * * @author J. David Mendoza <jdmendoza@um.edu.mx> */ @Repository @Transactional public class ProductoDaoHibernate extends BaseDao implements ProductoDao { public ProductoDaoHibernate() { log.info("Nueva instancia de ProductoDao"); } @Override @Transactional(readOnly = true) public Map<String, Object> lista(Map<String, Object> params) { log.debug("Buscando lista de productos 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(Producto.class); Criteria countCriteria = currentSession() .createCriteria(Producto.class); 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("inactivo")) { criteria.add(Restrictions.eq("inactivo", true)); countCriteria.add(Restrictions.eq("inactivo", true)); } else { Disjunction propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.eq("inactivo", Boolean.FALSE)); propiedades.add(Restrictions.isNull("inactivo")); criteria.add(propiedades); countCriteria.add(propiedades); } if (params.containsKey("filtro")) { String filtro = (String) params.get("filtro"); Disjunction propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.ilike("sku", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("nombre", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("descripcion", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("marca", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("modelo", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("ubicacion", 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)); } } if (!params.containsKey("reporte")) { criteria.setFirstResult((Integer) params.get("offset")); criteria.setMaxResults((Integer) params.get("max")); } params.put("productos", criteria.list()); countCriteria.setProjection(Projections.rowCount()); params.put("cantidad", (Long) countCriteria.list().get(0)); return params; } @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true) public List<Producto> listaParaSalida(String filtro, Long almacenId) { Criteria criteria = currentSession().createCriteria(Producto.class); criteria.createCriteria("almacen").add(Restrictions.idEq(almacenId)); filtro = "%" + filtro + "%"; Disjunction propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.ilike("sku", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions .ilike("nombre", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("descripcion", filtro, MatchMode.ANYWHERE)); propiedades .add(Restrictions.ilike("marca", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions .ilike("modelo", filtro, MatchMode.ANYWHERE)); propiedades.add(Restrictions.ilike("ubicacion", filtro, MatchMode.ANYWHERE)); criteria.add(propiedades); propiedades = Restrictions.disjunction(); propiedades.add(Restrictions.eq("inactivo", Boolean.FALSE)); propiedades.add(Restrictions.isNull("inactivo")); criteria.add(propiedades); criteria.add(Restrictions.gt("existencia", BigDecimal.ZERO)); criteria.setMaxResults(10); return criteria.list(); } @Override @Transactional(readOnly = true) public Producto obtiene(Long id) { return (Producto) currentSession().get(Producto.class, id); } @Override public Producto crea(Producto producto, Usuario usuario) { Session session = currentSession(); if (usuario != null) { producto.setAlmacen(usuario.getAlmacen()); } producto.setTipoProducto((TipoProducto) session.get(TipoProducto.class, producto.getTipoProducto().getId())); Date fecha = new Date(); producto.setFechaCreacion(fecha); producto.setFechaModificacion(fecha); session.save(producto); audita(producto, usuario, Constantes.CREAR, fecha); session.flush(); return producto; } @Override public Producto crea(Producto producto) { return this.crea(producto, null); } @Override public Producto actualiza(Producto producto) { return this.actualiza(producto, null); } @Override public Producto actualiza(Producto otro, Usuario usuario) { Date fecha = new Date(); Session session = currentSession(); Producto producto = (Producto) session .get(Producto.class, otro.getId()); BeanUtils.copyProperties(otro, producto, new String[]{"id", "version", "precioUnitario", "ultimoPrecio", "existencia", "puntoReorden", "tipoProducto", "almacen", "imagenes", "fechaCreacion", "fechaInactivo", "inactivo" }); producto.setTipoProducto((TipoProducto) session.get(TipoProducto.class, otro.getTipoProducto().getId())); if (otro.getInactivo() && (producto.getInactivo() == null || !producto.getInactivo())) { producto.setInactivo(true); producto.setFechaInactivo(fecha); } else if (!otro.getInactivo() && producto.getInactivo() != null && producto.getInactivo()) { producto.setInactivo(false); producto.setFechaInactivo(null); } producto.setFechaModificacion(fecha); if (producto.getImagenes().size() > 0) { Imagen imagen = producto.getImagenes().get(0); producto.getImagenes().clear(); producto.getImagenes().add(otro.getImagenes().get(0)); session.delete(imagen); session.flush(); } else if (otro.getImagenes() != null && otro.getImagenes().size() > 0) { producto.getImagenes().add(otro.getImagenes().get(0)); } session.update(producto); audita(producto, usuario, Constantes.ACTUALIZAR, fecha); session.flush(); return producto; } @Override public String elimina(Long id) { return elimina(id, null); } @Override public String elimina(Long id, Usuario usuario) { Producto producto = obtiene(id); String nombre = producto.getNombre(); audita(producto, usuario, Constantes.ELIMINAR, new Date()); currentSession().delete(producto); currentSession().flush(); return nombre; } @Override @Transactional(readOnly = true) public Map<String, Object> historial(Long id, Map<String, Object> params) { StringBuilder sb = new StringBuilder(); sb.append("select new map("); sb.append("p.actividad as actividad, p.creador as creador "); sb.append(", p.precioUnitario as precioUnitario, p.ultimoPrecio as ultimoPrecio "); sb.append(", p.existencia as existencia "); sb.append(", p.fechaCreacion as fecha "); sb.append(", p.entradaId as entradaId "); sb.append(", p.salidaId as salidaId "); sb.append(", p.cancelacionId as cancelacionId "); sb.append(", (select e.folio from Entrada e where e.id = p.entradaId) as folioEntrada "); sb.append(", (select s.folio from Salida s where s.id = p.salidaId) as folioSalida "); sb.append(", (select c.folio from Cancelacion c where c.id = p.cancelacionId) as folioCancelacion "); sb.append(") from XProducto p where p.productoId = :productoId order by p.id desc"); Query query = currentSession().createQuery(sb.toString()); query.setLong("productoId", id); if (params.containsKey("max")) { Integer max = (Integer) params.get("max"); query.setMaxResults(max); params.put("max", max); } else { query.setMaxResults(10); params.put("max", 10); } 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")) { Integer offset = (Integer) params.get("offset"); query.setFirstResult(offset); params.put("offset", offset); } else { query.setFirstResult(0); params.put("offset", 0); } params.put("historial", query.list()); sb = new StringBuilder(); sb.append("select count(*) as cantidad from XProducto p where p.productoId = :productoId"); query = currentSession().createQuery(sb.toString()); query.setLong("productoId", id); params.put("cantidad", query.uniqueResult()); return params; } @SuppressWarnings("unchecked") @Override public void guardaHistorial(Date fecha) { log.debug("Buscando historial de productos de la fecha {}", fecha); StringBuilder sb = new StringBuilder(); sb.append("select new HistorialProducto(p.id, p.almacen) from Producto p order by p.codigo"); log.debug("Cargando lista de productos"); List<HistorialProducto> productos = currentSession().createQuery( sb.toString()).list(); List<HistorialProducto> resultado = new ArrayList<>(); log.debug("Buscando historial por producto ({})", productos.size()); int cont = 0; for (HistorialProducto hp : productos) { if (cont++ % 10 == 0) { log.debug("Leyendo {} / {} Productos", cont, productos.size()); } sb = new StringBuilder(); sb.append("select new map(p.existencia as existencia) from XProducto p where p.productoId = :productoId and p.fechaCreacion <= :fecha order by p.fechaCreacion desc"); Query query = currentSession().createQuery(sb.toString()); query.setLong("productoId", hp.getProductoId()); query.setTimestamp("fecha", fecha); query.setMaxResults(1); Map<String, Object> existencia = (Map<String, Object>) query .uniqueResult(); if (existencia != null && !existencia.isEmpty()) { sb = new StringBuilder(); sb.append("select hp from HistorialProducto hp where fecha = :fecha and productoId = :productoId"); Query query2 = currentSession().createQuery(sb.toString()); query2.setDate("fecha", fecha); query2.setLong("productoId", hp.getProductoId()); HistorialProducto otro = (HistorialProducto) query2 .uniqueResult(); if (otro != null) { hp = otro; } hp.setExistencia((BigDecimal) existencia.get("existencia")); hp.setFecha(fecha); resultado.add(hp); } } log.debug("{} / {} Productos", cont, productos.size()); log.debug("Guardando historial de productos ({})", resultado.size()); cont = 0; for (HistorialProducto hp : resultado) { if (cont++ % 10 == 0) { log.debug("Guardando {} / {} Productos", cont, resultado.size()); } currentSession().saveOrUpdate(hp); } } @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true) public Map<String, Object> obtieneHistorial(Map<String, Object> params) { List<Producto> resultado = new ArrayList<>(); if (params.containsKey("fecha") && params.containsKey("almacen")) { Date fecha = (Date) params.get("fecha"); Long almacenId = (Long) params.get("almacen"); log.debug("Buscando historial de productos de la fecha {}", fecha); StringBuilder sb = new StringBuilder(); sb.append("select new HistorialProducto(p.id, p.almacen) from Producto p where p.almacen.id = :almacenId order by p.codigo"); log.debug("Cargando lista de productos"); Query query1 = currentSession().createQuery(sb.toString()); query1.setLong("almacenId", almacenId); List<HistorialProducto> productos = query1.list(); log.debug("Buscando historial por producto ({})", productos.size()); int cont = 0; for (HistorialProducto hp : productos) { if (cont++ % 10 == 0) { log.debug("Leyendo {} / {} Productos", cont, productos.size()); } sb = new StringBuilder(); sb.append("select new Producto(p.productoId, p.sku, p.nombre, p.descripcion, p.marca, p.modelo, p.ubicacion, p.existencia, p.unidadMedida, p.precioUnitario, p.fraccion, tp.nombre, a.nombre) from XProducto p, TipoProducto tp, Almacen a where p.tipoProductoId = tp.id and p.almacenId = a.id and p.productoId = :productoId and p.fechaCreacion <= :fecha order by p.fechaCreacion desc"); Query query = currentSession().createQuery(sb.toString()); query.setLong("productoId", hp.getProductoId()); query.setTimestamp("fecha", fecha); query.setMaxResults(1); Producto producto = (Producto) query.uniqueResult(); if (producto != null) { resultado.add(producto); } } log.debug("{} / {} Productos", cont, productos.size()); log.debug("Se encontro el historial de productos ({})", resultado.size()); params.put("productos", resultado); params.put("cantidad", 1L); params.put("max", 1); } return params; } @Override public Map<String, Object> historialTodos(Map<String, Object> params) { return params; } private void audita(Producto producto, Usuario usuario, String actividad, Date fecha) { XProducto xproducto = new XProducto(); BeanUtils.copyProperties(producto, xproducto, new String[]{"id", "version"}); xproducto.setProductoId(producto.getId()); 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); } @SuppressWarnings("unchecked") @Override public void arreglaDescripciones() { log.debug("Arreglando descripciones"); Date fecha = new Date(); Query query = currentSession().createQuery("from Producto"); List<Producto> productos = query.list(); int cont = 0; for (Producto producto : productos) { if (StringUtils.isBlank(producto.getDescripcion())) { log.debug("Actualizando {}", producto); producto.setDescripcion(producto.getNombre()); currentSession().update(producto); this.audita(producto, null, Constantes.ACTUALIZAR, fecha); cont++; } } currentSession().flush(); log.debug("Se arreglaron {} de {}", cont, productos.size()); } @Override public String eliminaImagen(Long productoId, Usuario usuario) { log.debug("Elimina imagenes de producto {}", productoId); Producto producto = (Producto) currentSession().get(Producto.class, productoId); String nombre = producto.getNombre(); producto.getImagenes().clear(); currentSession().update(producto); currentSession().flush(); return nombre; } @Override public List<Map<String, Object>> revisaEntradas(String fechaString, Usuario usuario) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); List<Map<String, Object>> entradas = new ArrayList<>(); try { Date fecha = sdf.parse(fechaString); StringBuilder s = new StringBuilder(); s.append("select new map(x.entradaId as entradaId, e.folio as folio, x.productoId as productoId, p.sku as sku, count(x.productoId) as cantidad) "); s.append("from XProducto x, Entrada e, Producto p "); s.append("where x.entradaId = e.id and x.productoId = p.id and x.fechaCreacion >= :fecha and x.almacenId = :almacenId "); s.append("group by x.entradaId, e.folio, x.productoId, p.sku "); s.append("order by cantidad desc, e.folio desc"); Query query = currentSession().createQuery(s.toString()); query.setDate("fecha", fecha); query.setLong("almacenId", usuario.getAlmacen().getId()); List<Map<String, Object>> resultados = (List<Map<String, Object>>) query.list(); for (Map<String, Object> resultado : resultados) { if (((Long)resultado.get("cantidad")) > 1) { entradas.add(resultado); } } } catch (ParseException e) { log.error("No pude entender la fecha " + fechaString, e); } return entradas; } }