/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.arrebol.taxiservicios.controller.spa;

import com.arrebol.taxiservicios.controller.admin.GenericPersonController;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.EstatusVenta;
import com.arrebol.taxiservicios.model.enums.GenericEnumType;
import com.arrebol.taxiservicios.model.enums.PersonType;
import com.arrebol.taxiservicios.model.spa.Cesiones;
import com.arrebol.taxiservicios.model.spa.HistorialAbonoMultipleSpa;
import com.arrebol.taxiservicios.model.spa.Pagos;
import com.arrebol.taxiservicios.model.spa.PagosDetalle;
import com.arrebol.taxiservicios.model.spa.PagosSpaView;
import com.arrebol.taxiservicios.model.spa.VentaDetalles;
import com.arrebol.taxiservicios.model.spa.Ventas;
import com.arrebol.taxiservicios.model.view.PersonListView;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author Crov
 */
public class VentasBeanController extends GenericPersonController implements Serializable {

   private static final long serialVersionUID = -6265444716269535946L;
   final Logger logger = LogManager.getLogger(getClass());

   public boolean addVenta(Ventas venta, User user, boolean save) {
      logger.info("addVenta");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            venta.setId(UUID.randomUUID().toString());
            venta.setCreatedBy(user);
            venta.setCreatedOn(correcciónDeHr(new Date(), -7));
            session.save(venta);
            transaction.commit();
            logger.info("Venta saved " + venta.getId());
         } else {
            venta.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
            venta.setLastUpdatedBy(user);
            session.update(venta);
            transaction.commit();
            logger.info("Venta updated " + venta.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Venta can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addVenta() ", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean addVentaDetalles(VentaDetalles detalle, User user, boolean save) {
      logger.info("addVenta");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            detalle.setId(UUID.randomUUID().toString());
            detalle.setCreatedBy(user);
            detalle.setCreatedOn(correcciónDeHr(new Date(), -7));
            session.save(detalle);
            transaction.commit();
            logger.info("Detalle venta saved " + detalle.getId());
         } else {
            detalle.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
            detalle.setLastUpdatedBy(user);
            session.update(detalle);
            transaction.commit();
            logger.info("Detalle venta updated " + detalle.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Detalle venta can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addVentaDetalles() ", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean addPagos(Pagos pago, User user, boolean save) {
      logger.info("addPagos");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            pago.setId(UUID.randomUUID().toString());
            pago.setCreatedBy(user);
            pago.setCreatedOn(correcciónDeHr(new Date(), -7));
            session.save(pago);
            transaction.commit();
            logger.info("Pago saved " + pago.getId());
         } else {
            pago.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
            pago.setLastUpdatedBy(user);
            session.update(pago);
            transaction.commit();
            logger.info("Pago addPagos " + pago.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Venta can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addVenta() ", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean addPagosDetalle(PagosDetalle sub, User user, boolean save) {
      logger.info("addPagos");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            sub.setId(UUID.randomUUID().toString());
            sub.setCreatedBy(user);
            sub.setCreatedOn(correcciónDeHr(new Date(), -7));
            session.save(sub);
            transaction.commit();
            logger.info("Pago saved " + sub.getId());
         } else {
            sub.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
            sub.setLastUpdatedBy(user);
            session.update(sub);
            transaction.commit();
            logger.info("Pago addPagos " + sub.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Venta can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addVenta() ", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean upDatePago(Pagos pago, User user) {
      logger.info("upDatePago");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         pago.setLastUpdatedBy(user);
         session.update(pago);
         transaction.commit();
         logger.info("Pago updated " + pago.getId());

         success = true;
      } catch (HibernateException e) {
         logger.error("Venta can not be updated ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method upDatePago() ", e);
         rollback(transaction);
      }
      return success;
   }

   public List<Ventas> fillVentasByLocation(Location location) {
      logger.info("fillVentasByLocation");
      List<Ventas> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching for Venta..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Ventas> criteria = builder.createQuery(Ventas.class);
         Root<Ventas> root = criteria.from(Ventas.class);

         Predicate criterio = (builder.equal(root.get("location"), location));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2));
         criteria.orderBy(builder.desc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillVentasByLocation() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Ventas> fillVentasByLocationAndEstatusVenta(Location location, EstatusVenta estatus, String cabina) {
      logger.info("fillVentasByLocation");
      List<Ventas> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching for Venta..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Ventas> criteria = builder.createQuery(Ventas.class);
         Root<Ventas> root = criteria.from(Ventas.class);

         Predicate criterio = (builder.equal(root.get("location"), location));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusVenta"), estatus));
         Predicate criterio4 = (builder.equal(root.get("cabina").get("id"), cabina));
         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4));
         criteria.orderBy(builder.desc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillVentasByLocation() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Ventas> fillVentasEnProsesoOConCesionesPendientes(Location location, String cabina) {
      logger.info("fillVentasByLocation");
      List<Ventas> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching for Venta..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Ventas> criteria = builder.createQuery(Ventas.class);
         Root<Cesiones> rootCesiones = criteria.from(Cesiones.class);

         // Hacemos el join inverso: Desde Cesiones a Ventas
         Join<Cesiones, Ventas> joinVentas = rootCesiones.join("venta", JoinType.INNER);

         // Predicados existentes
         Predicate criterio = builder.equal(joinVentas.get("location"), location);
         Predicate criterio2 = builder.equal(joinVentas.get("estatusActivo"), GenericEnumType.ENABLED);

         // Predicado combinado para estatusVenta
         Predicate criterio3 = builder.or(
                 builder.equal(joinVentas.get("estatusVenta"), EstatusVenta.PAGADA),
                 builder.equal(joinVentas.get("estatusVenta"), EstatusVenta.PROCESO)
         );

         Predicate criterio4 = builder.equal(joinVentas.get("cabina").get("id"), cabina);

         // Nuevo predicado para estatusCesion
         Predicate criterio5 = builder.equal(rootCesiones.get("estatusCesion"), GenericEnumType.DISABLED);
         Predicate criterio6 = builder.equal(rootCesiones.get("estatusActivo"), GenericEnumType.ENABLED);

         // Eliminar duplicados usando DISTINCT
         criteria.select(joinVentas).distinct(true);
         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4, criterio5, criterio6));
         criteria.orderBy(builder.desc(joinVentas.get("createdOn")));

         resultList = session.createQuery(criteria).getResultList();
         logger.info("Total of Ventas found: " + (resultList == null ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillVentasByLocation() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Ventas> fillVentasByLocationAndProductoAndFechas(Location location, String producto, Date fechaInicial, Date fechaFinal) {
      logger.info("fillVentasByLocation");
      List<Ventas> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching for Venta..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Ventas> criteria = builder.createQuery(Ventas.class);
         Root<Ventas> root = criteria.from(Ventas.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = fechaFinal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("location"), location));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("producto").get("id"), producto));

         Predicate fechaInicialPredicate = builder.greaterThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localStartDate);
         Predicate fechaFinalPredicate = builder.lessThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localEndDate);

         criteria.where(builder.and(criterio, criterio2, criterio3, fechaInicialPredicate, fechaFinalPredicate));
         criteria.orderBy(builder.asc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillVentasByLocation() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosByVenta(Ventas venta) {
      logger.info("fillPagosByVenta");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         Predicate criterio = (builder.equal(root.get("venta").get("id"), venta.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2));
         criteria.orderBy(builder.asc(root.get("fechaAPagar")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosByVentaAndPagoEstatus(Ventas venta, GenericEnumType estatus) {
      logger.info("fillPagosByVenta");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         Predicate criterio = (builder.equal(root.get("venta").get("id"), venta.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), estatus));
         criteria.where(builder.and(criterio, criterio2, criterio3));
         criteria.orderBy(builder.asc(root.get("fechaAPagar")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosNoPagafosByVentaAnd(Ventas venta) {
      logger.info("fillPagosByVenta");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         Predicate criterio = (builder.equal(root.get("venta").get("id"), venta.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), GenericEnumType.DISABLED));
         Predicate criterio4 = (builder.equal(root.get("pagoEstatus"), GenericEnumType.INCOMPLETE));
         criteria.where(builder.and(criterio, criterio2), builder.or(criterio3, criterio4));
         criteria.orderBy(builder.asc(root.get("fechaAPagar")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<VentaDetalles> fillVentaDetallesByVenta(Ventas venta) {
      logger.info("fillVentaDetallesByVenta");
      List<VentaDetalles> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching detalles ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<VentaDetalles> criteria = builder.createQuery(VentaDetalles.class);
         Root<VentaDetalles> root = criteria.from(VentaDetalles.class);

         Predicate criterio = (builder.equal(root.get("venta"), venta));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2));
         criteria.orderBy(builder.asc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Detalles Venta found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Detalles venta cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillVentaDetallesByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<PagosDetalle> fillPagosDetalleByPagos(Pagos pago) {
      logger.info("fillPagosDetalleByPagos");
      List<PagosDetalle> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching detalles pago spa for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<PagosDetalle> criteria = builder.createQuery(PagosDetalle.class);
         Root<PagosDetalle> root = criteria.from(PagosDetalle.class);

         Predicate criterio = (builder.equal(root.get("pago"), pago));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2));
         criteria.orderBy(builder.asc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off detalles found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Detalles cannot be loaded" + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosDetalleByPagos(): " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosByEstatusAndFechasAndProducto(GenericEnumType estatus, Date fechaInicial, Date fechaFinal, String producto) {
      logger.info("fillPagosByVenta");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = fechaFinal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), estatus));
         Predicate criterio4 = (builder.equal(root.get("venta").get("producto").get("id"), producto));

         Predicate fechaInicialPredicate = builder.greaterThanOrEqualTo(root.get("lastUpdatedOn").as(LocalDate.class), localStartDate);
         Predicate fechaFinalPredicate = builder.lessThanOrEqualTo(root.get("lastUpdatedOn").as(LocalDate.class), localEndDate);

         criteria.where(builder.and(criterio2, criterio3, criterio4, fechaInicialPredicate, fechaFinalPredicate));
         criteria.orderBy(builder.asc(root.get("createdOn")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosByLocation(Location location) {
      logger.info("fillPagosByVenta");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), GenericEnumType.DISABLED));
         criteria.where(builder.and(criterio, criterio2, criterio3));
         criteria.orderBy(builder.desc(root.get("fechaPago")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosByLocationAndFechas(Location location, Date fechaInicial, Date fechaFinal) {
      logger.info("fillPagosByLocationAndFechas");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = fechaFinal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), GenericEnumType.DISABLED));

         Predicate criterio4 = (builder.greaterThanOrEqualTo(root.get("fechaPago").as(LocalDate.class), localStartDate));
         Predicate criterio5 = (builder.lessThanOrEqualTo(root.get("fechaPago").as(LocalDate.class), localEndDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4, criterio5));
         criteria.orderBy(builder.desc(root.get("fechaPago")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByLocationAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Pagos> fillPagosFuturosByLocationAndFechas(Location location, Date fechaInicial) {
      logger.info("fillPagosByLocationAndFechas");
      List<Pagos> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching ventas for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("pagoEstatus"), GenericEnumType.DISABLED));

         Predicate criterio4 = (builder.greaterThanOrEqualTo(root.get("fechaPago").as(LocalDate.class), localStartDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4));
         criteria.orderBy(builder.desc(root.get("fechaPago")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off Ventas found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosByLocationAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesByLocation(Location location) {
      logger.info("fillCesionesByLocation");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));
         criteria.where(builder.and(criterio, criterio2, criterio3));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocation() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesByLocationAndFechas(Location location, Date fechaInicial, Date fechaFinal) {
      logger.info("fillCesionesByLocationAndFechas");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = fechaFinal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));

         Predicate criterio4 = (builder.greaterThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localStartDate));
         Predicate criterio5 = (builder.lessThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localEndDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4, criterio5));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocationAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesFuturasByLocationAndFechas(Location location, Date fechaInicial) {
      logger.info("fillCesionesByLocationAndFechas");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));

         Predicate criterio4 = (builder.greaterThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localStartDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocationAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesByLocationAndCabinas(Location location, String idCabina) {
      logger.info("fillCesionesByLocationAndCabinas");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));
         Predicate criterio4 = (builder.equal(root.get("venta").get("cabina").get("id"), idCabina));
         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocationAndCabinas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesByLocationAndCabinasAndFechas(Location location, String idCabina, Date fechaInicial, Date fechaFinal) {
      logger.info("fillCesionesByLocationAndCabinasAndFechas");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = fechaFinal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));
         Predicate criterio4 = (builder.equal(root.get("venta").get("cabina").get("id"), idCabina));

         Predicate criterio5 = (builder.greaterThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localStartDate));
         Predicate criterio6 = (builder.lessThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localEndDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4, criterio5, criterio6));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocationAndCabinasAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesFuturasByLocationAndCabinasAndFechas(Location location, String idCabina, Date fechaInicial) {
      logger.info("fillCesionesByLocationAndCabinasAndFechas");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         LocalDate localStartDate = fechaInicial.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("location").get("id"), location.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         Predicate criterio3 = (builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED));
         Predicate criterio4 = (builder.equal(root.get("venta").get("cabina").get("id"), idCabina));

         Predicate criterio5 = (builder.greaterThanOrEqualTo(root.get("fechaCesion").as(LocalDate.class), localStartDate));

         criteria.where(builder.and(criterio, criterio2, criterio3, criterio4, criterio5));
         criteria.orderBy(builder.desc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Ventas cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByLocationAndCabinasAndFechas() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<PagosSpaView> buscarPagosSpaViewPagadosPorRangoFechas(GenericEnumType estatusPago, Date startDate, Date endDate, Location location) {
      logger.info("buscarPagosSpaViewPagadosPorRangoFechasAndPredio");

      List<PagosSpaView> results = null;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<PagosSpaView> query = builder.createQuery(PagosSpaView.class);
         Root<PagosSpaView> root = query.from(PagosSpaView.class);

         LocalDate localStartDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
         LocalDate localEndDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         // Crear predicados para comparar solo las fechas
         Predicate criterioLocation = builder.equal(root.get("venta").get("location"), location);
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("fechaPago").as(LocalDate.class), localStartDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("fechaPago").as(LocalDate.class), localEndDate);
         Predicate criterioPagoEstatus = builder.equal(root.get("pagoEstatus"), estatusPago);

         query.where(builder.and(criterioPagoEstatus, criterioLocation, startDatePredicate, endDatePredicate));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total PagosSpaView son: " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("No se pudo encontrar los PagosSpaView", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method PagosSpaView", e);
      }

      return results;
   }

   public List<PagosDetalle> buscarPagosDetalleByAbonoLote(String idPago) {
      logger.info("buscarPagosDetalleByAbonoLote");

      List<PagosDetalle> results = null;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<PagosDetalle> query = builder.createQuery(PagosDetalle.class);
         Root<PagosDetalle> root = query.from(PagosDetalle.class);

         // Crear predicados para comparar solo las fechas
         Predicate abonoPredicate = builder.equal(root.get("pago").get("id"), idPago);
         Predicate criterioActivo = builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED);

         query.where(builder.and(criterioActivo, abonoPredicate));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total PagosDetalle son: " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("No se pudo encontrar los PagosDetalle", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method PagosDetalle", e);
      }

      return results;
   }

   public PagosSpaView fillFoliosByPagos(String abreviacionFolio) {
      PagosSpaView result = null;
      Transaction transaction = null;
      try {
         logger.info("Search last generated folio..");

         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         String query = "SELECT pa FROM PagosSpaView pa "
                 + "WHERE pa.folio LIKE '" + abreviacionFolio + "%' "
                 + "ORDER BY "
                 + "SUBSTRING_INDEX(pa.folio, '-', 1) DESC, "
                 + "SUBSTRING_INDEX(SUBSTRING_INDEX(pa.folio, '-', -1), '-', -6) DESC ";

         result = (PagosSpaView) session.createQuery(query)
                 .setMaxResults(1)
                 .uniqueResult();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Search for the last generated folio " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillFoliosByPagos() " + e);
         rollback(transaction);
      }
      return result;
   }

   public boolean addCesiones(Cesiones cesion, User user, boolean save) {
      logger.info("addCesiones");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            cesion.setId(UUID.randomUUID().toString());
            cesion.setCreatedBy(user);
            cesion.setCreatedOn(correcciónDeHr(new Date(), -7));
            session.save(cesion);
            transaction.commit();
            logger.info("Cesion saved " + cesion.getId());
         } else {
            cesion.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
            cesion.setLastUpdatedBy(user);
            session.update(cesion);
            transaction.commit();
            logger.info("Cesion update " + cesion.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Cesion can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addCesiones() ", e);
         rollback(transaction);
      }
      return success;
   }

   public List<Cesiones> fillCesionesByVenta(Ventas venta) {
      logger.info("fillCesionesByVenta");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         Predicate criterio = (builder.equal(root.get("venta").get("id"), venta.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2));
         criteria.orderBy(builder.asc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Cesiones cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public List<Cesiones> fillCesionesByVentaAndEstatus(Ventas venta, GenericEnumType estatus) {
      logger.info("fillCesionesByVenta");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         Predicate criterio = (builder.equal(root.get("venta").get("id"), venta.getId()));
         Predicate criterio2 = (builder.equal(root.get("estatusCesion"), estatus));
         Predicate criterio3 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2, criterio3));
         criteria.orderBy(builder.asc(root.get("fechaCesion")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Cesiones cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByVenta() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public Cesiones fillCesionById(String idSesion) {
      logger.info("fillCesionById");
      Cesiones result = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for pagos..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         Predicate criterio = (builder.equal(root.get("id"), idSesion));
         criteria.where(builder.and(criterio));
         result = session.createQuery(criteria).getSingleResult();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Cesion cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionById() " + e);
         rollback(transaction);
      }
      return result;
   }

   public Pagos fillPagosById(String id) {
      logger.info("fillPagosById");
      Pagos result = null;
      Transaction transaction = null;
      try {
         logger.info("Searching pago..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Pagos> criteria = builder.createQuery(Pagos.class);
         Root<Pagos> root = criteria.from(Pagos.class);

         Predicate criterio = (builder.equal(root.get("id"), id));
         criteria.where(builder.and(criterio));
         result = session.createQuery(criteria).getSingleResult();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Pago " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosById() " + e);
         rollback(transaction);
      }
      return result;
   }

   public PagosDetalle fillPagosDetalleById(String id) {
      logger.info("fillPagosDetalleById");
      PagosDetalle result = null;
      Transaction transaction = null;
      try {
         logger.info("Searching detalle pago..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<PagosDetalle> criteria = builder.createQuery(PagosDetalle.class);
         Root<PagosDetalle> root = criteria.from(PagosDetalle.class);

         Predicate criterio = (builder.equal(root.get("id"), id));
         criteria.where(builder.and(criterio));
         result = session.createQuery(criteria).getSingleResult();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Detalle pago " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillPagosDetalleById() " + e);
         rollback(transaction);
      }
      return result;
   }

   public long fillCesionesNoTomadasByVenta(String idVenta) {
      logger.info("Counting sesiones tomadas...");
      long count = 0;
      Transaction transaction = null;
      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();
         CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         criteria.select(builder.count(root));
         criteria.where(
                 builder.equal(root.get("venta").get("id"), idVenta),
                 builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED),
                 builder.equal(root.get("estatusCesion"), GenericEnumType.DISABLED)
         );

         count = session.createQuery(criteria).getSingleResult();
         logger.info("Total of sesiones tomadas found: " + count);
         transaction.commit();
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Unable to count sesiones tomadas", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillCesionesTomadasByVenta", e);
      }
      return count;
   }

   public List<Cesiones> fillCesionesByCabinaAndFecha(String idCabina, Date fecha) {
      logger.info("fillCesionesByCabinaAndFecha");
      List<Cesiones> resultList = null;
      Transaction transaction = null;
      try {
         logger.info("Searching cesiones for Cabina And Fecha..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<Cesiones> criteria = builder.createQuery(Cesiones.class);
         Root<Cesiones> root = criteria.from(Cesiones.class);

         LocalDate localFecha = fecha.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

         Predicate criterio = (builder.equal(root.get("venta").get("cabina").get("id"), idCabina));
         Predicate criterio2 = (builder.equal(root.get("fechaCesion").as(LocalDate.class), localFecha));
         Predicate criterio3 = (builder.equal(root.get("estatusActivo"), GenericEnumType.ENABLED));
         criteria.where(builder.and(criterio, criterio2, criterio3));
         criteria.orderBy(builder.asc(root.get("fechaCesion")), builder.asc(root.get("hora")), builder.asc(root.get("minutos")));
         resultList = session.createQuery(criteria).getResultList();

         logger.info("Total off cesiones found: " + (null == resultList ? -1 : resultList.size()));
         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Cesiones cannot be loaded " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillCesionesByCabinaAndFecha() " + e);
         rollback(transaction);
      }
      return resultList;
   }

   public boolean addHitorialAbonoMultipleSpa(HistorialAbonoMultipleSpa abonoMultiple, User user, boolean save) {
      logger.info("addHitorialAbonoMultipleSpa");
      boolean success = false;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         if (save) {
            abonoMultiple.setId(UUID.randomUUID().toString());
            abonoMultiple.setCreatedBy(user);
            abonoMultiple.setCreatedOn(new Date());
            session.save(abonoMultiple);
            transaction.commit();
            logger.info("Abono saved " + abonoMultiple.getId());
         } else {
            abonoMultiple.setLastUpdatedOn(new Date());
            abonoMultiple.setLastUpdatedBy(user);
            session.update(abonoMultiple);
            transaction.commit();
            logger.info("Hitorial Abono Multiple updated " + abonoMultiple.getId());
         }

         success = true;
      } catch (HibernateException e) {
         logger.error("Hitorial Abono Multiple can not be added ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method addHitorialAbonoMultipleSpa() ", e);
         rollback(transaction);
      }
      return success;
   }

   public HistorialAbonoMultipleSpa fillHistorialAbonoMultipleSpaById(String id) {
      logger.info("fillHistorialAbonoMultipleSpaById");
      HistorialAbonoMultipleSpa result = null;
      Transaction transaction = null;
      try {
         logger.info("Searching AbonoMultiple..");
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();

         CriteriaQuery<HistorialAbonoMultipleSpa> criteria = builder.createQuery(HistorialAbonoMultipleSpa.class);
         Root<HistorialAbonoMultipleSpa> root = criteria.from(HistorialAbonoMultipleSpa.class);

         Predicate criterio = (builder.equal(root.get("id"), id));
         criteria.where(builder.and(criterio));
         result = session.createQuery(criteria).getSingleResult();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("AbonoMultiple " + e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method fillHistorialAbonoMultipleSpaById() " + e);
         rollback(transaction);
      }
      return result;
   }

   public int verificarCesionExistente(String id_cabinas, Date fecha_cesion, int hora_inicio, int minutos_inicio, double duracion) {
      logger.info("Verificando cesión existente...");

      Transaction transaction = null;
      int count = 0;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         // Extraer horas y minutos de la duración
         int horas_duracion = (int) Math.floor(duracion);
         int minutos_duracion = (int) ((duracion - horas_duracion) * 100);

         // Calcular la hora de fin correctamente
         int hora_fin = hora_inicio + horas_duracion;
         int minutos_fin = minutos_inicio + minutos_duracion;

         // Ajustar si los minutos sobrepasan 60
         hora_fin += minutos_fin / 60;
         minutos_fin = minutos_fin % 60;

         String sql = "SELECT ce.id, ce.fecha_cesion, ce.hora, ce.minutos, ce.duracion "
                 + "FROM cesiones ce "
                 + "INNER JOIN ventas ve ON ve.id = ce.id_venta "
                 + "WHERE DATE(ce.fecha_cesion) = DATE(:fecha_cesion) "
                 + "AND ( "
                 + "   (:hora_inicio * 60 + :minutos_inicio BETWEEN (ce.hora * 60 + ce.minutos) "
                 + "    AND (ce.hora * 60 + ce.minutos + (FLOOR(ce.duracion) * 60 + (ce.duracion - FLOOR(ce.duracion)) * 100) - 1)) "
                 + "  OR "
                 + "   ((:hora_fin * 60 + :minutos_fin) > (ce.hora * 60 + ce.minutos) "
                 + "    AND (ce.hora * 60 + ce.minutos + (FLOOR(ce.duracion) * 60 + (ce.duracion - FLOOR(ce.duracion)) * 100)) > (:hora_inicio * 60 + :minutos_inicio)) "
                 + ") "
                 + "AND ve.id_cabinas = :id_cabinas";

         List<Object> rows = session.createNativeQuery(sql)
                 .setParameter("id_cabinas", id_cabinas)
                 .setParameter("fecha_cesion", fecha_cesion)
                 .setParameter("hora_inicio", hora_inicio)
                 .setParameter("minutos_inicio", minutos_inicio)
                 .setParameter("hora_fin", hora_fin)
                 .setParameter("minutos_fin", minutos_fin)
                 .getResultList();
         transaction.commit();

         count = rows.size();
         logger.info("Cesiones encontradas: " + count);
      } catch (HibernateException e) {
         logger.error("Error al verificar cesión", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Error en verificarCesionExistente()", e);
         rollback(transaction);
      }

      return count;
   }

   public List<PersonListView> findListOfPersonsByType(PersonType type, Location location) {
      List<PersonListView> results = null;
      Transaction transaction = null;

      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();

         String hql = "FROM PersonListView WHERE type = :type AND location = :location";

         results = session.createQuery(hql).setParameter("type", type).setParameter("location", location).getResultList();

         transaction.commit();
      } catch (HibernateException e) {
         logger.error("Can not list of persons", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method findListOfPersonsByType() ", e);
         rollback(transaction);
      }
      return results;
   }

   private Date correcciónDeHr(Date fecha, int horas) {
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(fecha);
      calendar.add(Calendar.HOUR_OF_DAY, horas);
      Date nuevaFecha = calendar.getTime();
      return nuevaFecha;
   }

}
