/*
 * Arrebol Consultancy copyright.
 * 
 * This code belongs to Arrebol Consultancy
 * its use, redistribution or modification are prohibited 
 * without written authorization from Arrebol Consultancy.
 */
package com.arrebol.taxiservicios.controller.admin;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.admin.ClosingDay;
import com.arrebol.taxiservicios.model.admin.ClosingDayDetail;
import com.arrebol.taxiservicios.model.admin.StableSmallBox;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.UserStatusType;
import com.arrebol.taxiservicios.model.predio.Predio;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Path;
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;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
public class ClosingDayController extends ConnectionManager implements Serializable {

    /**
     *
     * @param date
     * @return
     */
    public boolean existStableSmallBoxByCreatedOn(Date date) {
        logger.info("existStableSmallBoxByCreatedOn");

        boolean success = true;
        Transaction transaction = null;

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

            String query = "SELECT COUNT(ssb.id) "
                    + "FROM StableSmallBox ssb "
                    + "WHERE DATE(ssb.createdOn) = DATE(:date) "
                    + "AND ssb.activeStatus = 'ENEBLED'";

            Long count = (Long) session.createQuery(query).setParameter("date", date).uniqueResult();

            if (null != count && count == 0) {
                success = false;
            }

            transaction.commit();

            logger.info("Total of closing day found: " + count);
        } catch (HibernateException e) {
            logger.error("Can not find stable small box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existStableSmallBoxByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }

    /**
     *
     * @param date
     * @return
     */
    public boolean existNextPaidClosingDayByCreatedOn(Date date) {
        logger.info("existNextPaidClosingDayByCreatedOn");

        boolean success = true;
        Transaction transaction = null;

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

            String query = "SELECT cd.id "
                    + "FROM closing_day cd "
                    + "WHERE DATE(cd.created_on) >= DATE_ADD(DATE(:date), INTERVAL 1 DAY) "
                    + "AND cd.active_status = 'ENEBLED'";

            List<String> records = session.createSQLQuery(query).setParameter("date", date).getResultList();

            if (records.isEmpty()) {
                success = false;
            }

            transaction.commit();

            logger.info("Total of closing day found: " + records.size());
        } catch (HibernateException e) {
            logger.error("Can not find next closing day by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existNextPaidClosingDayByCreatedOn()", e);
            rollback(transaction);
        }

        return success;
    }

    /**
     *
     * @param location
     * @return
     */
    public List<User> getAllActiveUsers(Location location) {
    logger.info("getAllActiveUsers");

    List<User> users = new ArrayList<>();
    Transaction transaction = null;

    try {
        List<User> usersAlreadyClosedDay = getAllUsersWithClasingDay();
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        transaction = session.beginTransaction();
        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);

        Path<String> id = root.get("id");
        Path<Person> person = root.get("person");
        Predicate criterioLocation = builder.equal(root.get("location"), location);

        Predicate userStatusTypePredicate = builder.equal(root.get("userStatusType"), UserStatusType.ENABLED);

        query.select(
                builder.construct(User.class, id, person)
        );

        if (usersAlreadyClosedDay.isEmpty()) {
            query.where(userStatusTypePredicate, criterioLocation);
        } else {
            CriteriaBuilder.In<String> ids = builder.in(root.get("id"));
            usersAlreadyClosedDay.forEach(user -> {
                ids.value(user.getId());
            });
            query.where(userStatusTypePredicate, criterioLocation, builder.not(ids));
        }

        query.orderBy(builder.asc(root.get("person")));

        users = session.createQuery(query).getResultList();

        transaction.commit();

        logger.info("Employee list " + users.size());
    } catch (HibernateException e) {
        logger.error("Can not find active users", e);
        rollback(transaction);
    } catch (Exception e) {
        logger.error("Method getAllActiveUsers()", e);
        rollback(transaction);
    }
    return users;
}


    /**
     * Find Closing daily's list between Dates (Start date and End Date).
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public List<ClosingDay> findClosingDailyListBetweenDates(Date startDate, Date endDate, String idLocation) {
        logger.info("findClosingDailyListBetweenDates");

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

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ClosingDay> query = builder.createQuery(ClosingDay.class);
            Root<ClosingDay> root = query.from(ClosingDay.class);
            
            LocalDate localStartDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate localEndDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

            Path<String> id = root.get("id");
            Path<User> user = root.get("user");
            Path<BigDecimal> amountPaid = root.get("amountPaid");
            Path<BigDecimal> amountExpected = root.get("amountExpected");
            Path<BigDecimal> amountTransfer = root.get("amountTransfer");
            Path<String> comments = root.get("comments");
            Path<Date> createdOn = root.get("createdOn");
            Path<User> createdByPath = root.get("createdBy");
            Path<Location> locationPath = root.get("location");

            Predicate activeStatusPredicate = builder.equal(root.get("activeStatus"), BasicType.ENEBLED);
            Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localStartDate);
            Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localEndDate);
            Predicate locationPredicate = builder.equal(root.get("location"), new Location(idLocation));

            query.select(
                    builder.construct(
                            ClosingDay.class, id, user,
                            amountPaid, amountExpected, comments, createdOn, createdByPath, locationPath, amountTransfer
                    )
            );
            query.where(builder.and(activeStatusPredicate, startDatePredicate, endDatePredicate, locationPredicate));
            query.orderBy(builder.asc(root.get("createdOn")));

            results = session.createQuery(query).getResultList();

            transaction.commit();

            logger.info("Closing daily's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find closing daily list between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findClosingDailyListBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<ClosingDay> findClosingDailyListByStableSmallBox(StableSmallBox stableSmallBox,Date startDate ,String idLocation) {
        logger.info("findClosingDailyListBetweenDates");

        logger.info("findDetailsFromClosingDayID");

        List<ClosingDay> results = null;
        Transaction transaction = null;
        
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            transaction = session.beginTransaction();
   
            results = session.createQuery("FROM ClosingDay c WHERE c.activeStatus = 'ENEBLED' AND c.location.id = :idLocation AND DATE(c.createdOn) > DATE(:fechaInicio) AND DATE(c.createdOn) <= DATE(:fechaFinal) ")
                    .setParameter("idLocation", idLocation)
                    .setParameter("fechaInicio", startDate)
                    .setParameter("fechaFinal", stableSmallBox.getCreatedOn())
                    .getResultList();

            transaction.commit();

            logger.info("Closing daily detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find closing daily details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromClosingDayID()", e);
            rollback(transaction);
        }
        return results;
    }
    
    
     public Map<Predio, Double> getTotalesByPredioInClosingDay(StableSmallBox stableSmallBox,Date startDate ,String idLocation){
    
         logger.info("findClosingDailyListBetweenDates");

        logger.info("findDetailsFromClosingDayID");

        List<Object> results = null;
        Map<Predio, Double> totales = new HashMap<>();
        Transaction transaction = null;
        
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            transaction = session.beginTransaction();
   
            results = session.createQuery("SELECT SUM(cd.amount), cd.predio FROM ClosingDayDetail cd "
                    + "INNER JOIN ClosingDay c ON c.id= cd.closingDay "
                    + "WHERE c.activeStatus = 'ENEBLED' AND c.location.id = :idLocation AND DATE(c.createdOn) > DATE(:fechaInicio) AND DATE(c.createdOn) <= DATE(:fechaFinal) AND cd.type LIKE 'ABONO. Lote:%' "
                    + "GROUP BY cd.predio") 
                    .setParameter("idLocation", idLocation)
                    .setParameter("fechaInicio", startDate)
                    .setParameter("fechaFinal", stableSmallBox.getCreatedOn())
                    .getResultList();
            
            
             for (Object result : results) {
                 Object[] temp = (Object[]) result;
                 totales.put( (Predio) temp[1], Double.valueOf(temp[0].toString()));
             }
            transaction.commit();

            logger.info("Closing daily detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find closing daily details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromClosingDayID()", e);
            rollback(transaction);
        }
        
    
        return totales;
    
    
    }
    
    public ClosingDay findLastClosingDay(String idLocation) {
        logger.info("findLastClosingDay");

        ClosingDay result = null;
        Transaction transaction = null;

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

            transaction = session.beginTransaction();

            result = (ClosingDay) session.createQuery("FROM ClosingDay c WHERE c.activeStatus = 'ENEBLED' AND c.location.id = :idLocation ORDER BY c.createdOn DESC")
                    .setParameter("idLocation", idLocation)
                    .setMaxResults(1) 
                    .uniqueResult();

            transaction.commit();

            logger.info("Last closing daily detail retrieved: " + result);
        } catch (HibernateException e) {
            logger.error("Can not find the last closing daily detail", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Error in findLastClosingDay()", e);
            rollback(transaction);
        }
        return result;
    }
    
    public Date lastStableSmallBoxBySmallBox(StableSmallBox stableSmallBox) {
        logger.info("lastStableSmallBoxByDate");

        Date success = null;
        Transaction transaction = null;

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

            String query = "SELECT cd.createdOn FROM StableSmallBox cd "
                    + "WHERE DATE(cd.createdOn) < DATE(:date) AND cd.location.id = :locationID AND cd.activeStatus = 'ENEBLED' "
                    + "order by cd.createdOn DESC";

            success = (Date) session.createQuery(query)
                    .setParameter("date",stableSmallBox.getCreatedOn())
                    .setParameter("locationID", stableSmallBox.getLocation().getId()).setMaxResults(1)
                    .uniqueResult();

            transaction.commit();

            logger.info("Total of closing day found: ");
        } catch (HibernateException e) {
            logger.error("Can not find stable small box by created on", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method lastStableSmallBoxByDate()", e);
            rollback(transaction);
        }

        return success;
    }
    
   
    public List<ClosingDay> findClosingDailyCurdate(String idLocation) {
        logger.info("findDetailsFromClosingDayID");

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

        Date fecha = getLastDateStableSmallBox(idLocation);

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

            transaction = session.beginTransaction();

            results = session.createQuery("FROM ClosingDay c WHERE c.activeStatus = 'ENEBLED' AND c.location.id = :idLocation AND DATE(c.createdOn) > :fecha ")
                    .setParameter("idLocation", idLocation)
                    .setParameter("fecha", fecha)
                    .getResultList();

            transaction.commit();

            logger.info("Closing daily detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find closing daily details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromClosingDayID()", e);
            rollback(transaction);
        }
        return results;
    }

    public Date getLastDateStableSmallBox(String locationId) {
        logger.info("getLastDateStableSmallBox");

        Date total = new Date();
        Transaction transaction = null;
        logger.info(locationId);

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

            String sqlQuery = "SELECT DATE(sgb.created_on) FROM stable_small_box sgb WHERE DATE(sgb.created_on) < CURDATE() AND sgb.id_location = '" + locationId + "' AND sgb.active_status = 'ENEBLED' ORDER BY sgb.created_on DESC LIMIT 1";

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            total = (Date) (nativeQuery.uniqueResult());

            logger.info(total);
            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not load the last date in stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getLastDateStableSmallBox()", e);
            rollback(transaction);
        }

        return total;
    }

    public List<ClosingDayDetail> findDetailsFromClosingDayID(ClosingDay closingDay) {
        logger.info("findDetailsFromClosingDayID");

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

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

            transaction = session.beginTransaction();

            results = session.createQuery("FROM ClosingDayDetail WHERE closingDay = :closingDay ORDER BY type, person")
                    .setParameter("closingDay", closingDay)
                    .getResultList();

            transaction.commit();

            logger.info("Closing daily detail's list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find closing daily details list", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findDetailsFromClosingDayID()", e);
            rollback(transaction);
        }
        return results;
    }

    /**
     * Update active status (ENEBLED/DISABLED) of closing day table by ID.
     *
     * @param id Primary key to be updated.
     * @param status Status to be updated (ENEBLED/DISABLED).
     * @param lastUpdatedBy User to apply update.
     * @return
     */
    public boolean updateClosingDailyById(String id, BasicType status, User lastUpdatedBy) {
        logger.info("updateClosingDailyById");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<ClosingDay> query = builder.createCriteriaUpdate(ClosingDay.class);
            Root<ClosingDay> root = query.from(ClosingDay.class);

            query.set(root.get("activeStatus"), status);
            query.set(root.get("lastUpdatedBy"), lastUpdatedBy);
            query.set(root.get("lastUpdatedOn"), new Date());

            query.where(builder.equal(root.get("id"), id));

            int total = session.createQuery(query).executeUpdate();

            if (1 == total) {
                transaction.commit();
                success = true;
                logger.info("Update closing day status successfully");
            } else {
                logger.info("CAN NOT update closing day");
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.info("CAN NOT update closing day", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateClosingDailyById()", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     *
     * @param sqlQuery
     * @param userID
     * @return
     */
    public Double findTotals(String sqlQuery, String userID) {
        logger.info("findTotals");

        Double total = null;
        Transaction transaction = null;

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

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            nativeQuery.setParameter("userID", userID);

            total = (Double) (nativeQuery.uniqueResult());

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not execute sql native query", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findTotals()", e);
            rollback(transaction);
        }

        return total;
    }

    public BigDecimal findTotalsBigDecimal(String sqlQuery, String userID) {
        logger.info("findTotals");

        BigDecimal total = null;
        Transaction transaction = null;

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

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            nativeQuery.setParameter("userID", userID);

            total = (BigDecimal) (nativeQuery.uniqueResult());

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not execute sql native query", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findTotals()", e);
            rollback(transaction);
        }

        return total;
    }

    /**
     *
     * @param closingDay
     * @param details
     * @return
     */
    public boolean saveClosingDayAndDetails(ClosingDay closingDay, List<ClosingDayDetail> details) {
        logger.info("saveClosingDayAndDetails");

        boolean success = false;
        Transaction transaction = null;

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

            session.save(closingDay);

            details.forEach(detail -> {
                session.save(detail);
            });

            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Can not save Closing Day And Details", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method saveClosingDayAndDetails()", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     *
     * @param userID
     * @return
     */
    
    //Modificar para poder añadir las cosas 
    public List<ClosingDayDetail> findClosingDayDetails(String userID) {
        List<ClosingDayDetail> details = new ArrayList<>();
        try {
            
            details.addAll(buildDetailsList(4, executeNativeSQLQuery(query_details_expenses, userID)));
            details.addAll(buildDetailsList(13, executeNativeSQLQuery(query_details_expenses_by_type, userID)));
            details.addAll(buildDetailsList(13, executeNativeSQLQuery(query_details_expenses_by_type_earning, userID)));
            details.addAll(buildDetailsList(14, executeNativeSQLQuery(query_details_abono_lote, userID)));
            details.addAll(buildDetailsList(15, executeNativeSQLQuery(query_details_abono_proyecto, userID)));
            details.addAll(buildDetailsList(18, executeNativeSQLQuery(query_details_devolucion_abono_entrada, userID)));   
            details.addAll(buildDetailsList(19, executeNativeSQLQuery(query_details_devolucion_abono, userID)));   
            details.addAll(buildDetailsList(20, executeNativeSQLQuery(query_details_abonos_rembolso_cancelacion_compra_lote, userID)));                 
            details.addAll(buildDetailsList(16, executeNativeSQLQuery(query_details_urbanizacion, userID)));
            details.addAll(buildDetailsList(21, executeNativeSQLQuery(query_details_abono_lote_detalle, userID)));

        } catch (Exception e) {
            logger.error(e);
        }
        return details;
    }

    /**
     *
     * @return
     */
    private List<User> getAllUsersWithClasingDay() {
        List<User> users = new ArrayList<>();
        Transaction transaction = null;

        try {
            String hql = "SELECT c From ClosingDay c WHERE DATE(c.createdOn) = CURDATE() AND c.activeStatus = 'ENEBLED'";
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            Query query = session.createQuery(hql);
            List<ClosingDay> results = query.getResultList();

            results.forEach((ClosingDay closingDay) -> {
                users.add(closingDay.getUser());
            });

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not save Closing Day And Details", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method saveClosingDayAndDetails()", e);
            rollback(transaction);
        }
        return users;
    }

    /**
     *
     * @param queryNumber 1: query_details_sales , 2: query_details_sanctions_in
     * , 3: query_details_sanctions_out , 4: query_details_expenses , 5:
     * query_details_invoices.
     * @param results
     * @return
     */
    private List<ClosingDayDetail> buildDetailsList(int queryNumber, Object results) {
        List<ClosingDayDetail> details = new ArrayList<>();
        try {
            List<?> list = new ArrayList<>();
            if (null != results) {
                if (results.getClass().isArray()) {
                    list = Arrays.asList((Object[]) results);
                } else if (results instanceof Collection) {
                    list = new ArrayList<>((Collection<?>) results);
                }

                for (Object object : list) {
                    Object[] array = (Object[]) object;

                    ClosingDayDetail closingDayDetail = new ClosingDayDetail(queryNumber, array);
                    details.add(closingDayDetail);
                }
                logger.info("execute sql native query's list "+queryNumber+" " + details.size());
            }
        } catch (Exception e) {
            logger.error(e);
        }
        return details;
    }

    /**
     *
     * @param sqlQuery
     * @param userID
     * @return
     */
    private Object executeNativeSQLQuery(String sqlQuery, String userID) {
        Object results = null;
        Transaction transaction = null;

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

            NativeQuery nativeQuery = session.createSQLQuery(sqlQuery);

            nativeQuery.setParameter("userID", userID);

            results = nativeQuery.getResultList();

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not execute sql native query", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method executeNativeSQLQuery()", e);
            rollback(transaction);
        }

        return results;
    }

    public User getUserById(String userId) {
        logger.info("getUserById");

        User general = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            general = session.get(User.class, userId);

            transaction.commit();
            logger.info("User " + general);
        } catch (HibernateException e) {
            logger.error("User cannot be loaded " + userId, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getUserById(" + userId + ") ", e);
            rollback(transaction);
        }
        return general;
    }

    /**
     *
     * @param idLocation
     * @return
     */
    public boolean existSalesToPay(String idLocation) {
        logger.info("existSalesToPay");

        boolean existSalestoPay = true;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT COUNT(styleClass) "
                    + "FROM DashboardToCollectView "
                    + "WHERE styleClass = 'datatableRowEmpty'"
                    + "AND idLocation = :idLocation";

            Long count = (Long) session.createQuery(query).setParameter("idLocation", idLocation).uniqueResult();

            if (null != count && count == 0) {
                existSalestoPay = false;
            }

            transaction.commit();

            logger.info("Total of existing sales to pay " + count);
        } catch (HibernateException e) {
            logger.error("Can not find existing sales to pay", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existSalesToPay()", e);
            rollback(transaction);
        }

        return existSalestoPay;
    }
    
     public boolean validateTransferInvoice(User createdBy) {
        logger.info("validateTransferInvoice");

        Transaction transaction = null;
        boolean result = false;

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

            Query query = session.createQuery("SELECT COUNT(transfer) FROM Invoice transfer WHERE transfer.statusType = 'PENDING' AND transfer.createdBy = :createdBy")
                    .setParameter("createdBy", createdBy);
            
            Long count = (Long)query.uniqueResult();

            if(count  == 0) result = true;
            
            transaction.commit();
            ;
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of Transfers", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findAllTransferPendingByUser", e);
        }

        return result;
    }
     
     public boolean validateInvoice(User createdBy) {
        logger.info("validateTransferInvoice");

        Transaction transaction = null;
        boolean result = false;

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

            Query query = session.createQuery("SELECT COUNT(transfer) FROM Invoice transfer WHERE transfer.authorize = 'PENDING' AND transfer.createdBy = :createdBy")
                    .setParameter("createdBy", createdBy);
            
            Long count = (Long)query.uniqueResult();

            if(count  == 0) result = true;
            
            transaction.commit();
            ;
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of Transfers", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findAllTransferPendingByUser", e);
        }

        return result;
    }
     
    public boolean validateTransferExpense(User createdBy) {
        logger.info("validateTransferInvoice");

        Transaction transaction = null;
        boolean result = false;

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

            Query query = session.createQuery("SELECT COUNT(transfer) FROM Expense transfer WHERE transfer.status = 'PENDING' AND transfer.createdBy = :createdBy")
                    .setParameter("createdBy", createdBy);
            
            Long count = (Long)query.uniqueResult();

            if(count  == 0) result = true;
            
            transaction.commit();
            ;
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of Transfers", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findAllTransferPendingByUser", e);
        }

        return result;
    }
    
    public boolean validateTransferPaymentToClient(User createdBy) {
        logger.info("validateTransferInvoice");

        Transaction transaction = null;
        boolean result = false;

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

            Query query = session.createQuery("SELECT COUNT(transfer) FROM PaymentClient transfer WHERE transfer.actionStatus = 'PENDING' AND transfer.createdBy = :createdBy")
                    .setParameter("createdBy", createdBy);
            
            Long count = (Long)query.uniqueResult();

            if(count  == 0) result = true;
            
            transaction.commit();
            ;
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of Transfers", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findAllTransferPendingByUser", e);
        }

        return result;
    }

    private final String complete_name = "CONCAT(\n"
            + "                    CASE\n"
            + "                        WHEN p.first_name IS NOT NULL AND p.first_name != ''\n"
            + "                        THEN CONCAT(SUBSTR(UPPER(p.first_name), 1, 1),SUBSTR(LOWER(p.first_name), 2), ' ')\n"
            + "                        ELSE ''\n"
            + "                    END,\n"
            + "                    CASE\n"
            + "                        WHEN p.second_name IS NOT NULL AND p.second_name != ''\n"
            + "                        THEN CONCAT(SUBSTR(UPPER(p.second_name), 1, 1),SUBSTR(LOWER(p.second_name), 2), ' ')\n"
            + "                        ELSE ''\n"
            + "                    END, \n"
            + "                    CASE\n"
            + "                        WHEN p.last_name IS NOT NULL AND p.last_name != ''\n"
            + "                        THEN CONCAT(SUBSTR(UPPER(p.last_name), 1, 1),SUBSTR(LOWER(p.last_name), 2), ' ')\n"
            + "                        ELSE ''\n"
            + "                    END,\n"
            + "                    CASE\n"
            + "                        WHEN p.middle_name IS NOT NULL AND p.middle_name != ''\n"
            + "                        THEN CONCAT(SUBSTR(UPPER(p.middle_name), 1, 1),SUBSTR(LOWER(p.middle_name), 2))\n"
            + "                        ELSE ''\n"
            + "                    END\n"
            + "                ) AS person_name";
    private final String sub_query_to_find_previously_closing_day = "(SELECT DATE(cd.created_on) FROM closing_day cd WHERE DATE(cd.created_on) <= CURDATE() AND cd.user_id = :userID AND cd.active_status = 'ENEBLED' order by cd.created_on DESC LIMIT 1)";
    
    private final String query_details_urbanizacion = "SELECT dlu.id, dlu.id_lote, l.id_cliente ,u.nombre, dlu.saldo_pagado, CONCAT(p.first_name,' ',p.second_name,' ', p.last_name,' ',p.middle_name) AS `complete_name` FROM detalle_lote_urbanizacion dlu INNER JOIN lote l ON dlu.id_lote = l.id INNER JOIN urbanizacion u ON dlu.id_urbanizacion = u.id LEFT JOIN person p ON l.id_cliente = p.id WHERE DATE(dlu.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND dlu.created_by = :userID";
    
    
    private final String query_details_expenses = "SELECT e.payment, e.expense_type, t.customer_id, e.description, " + complete_name + ", e.id FROM expense e INNER JOIN taxi t ON e.taxi_id = t.id INNER JOIN person p ON t.customer_id = p.id WHERE DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND expense_type NOT IN ('MANDADOS','APOYO_VIAL') AND expense_type IN ('INICIO','PAGO_ORDEN_SERVICIO','ABONO_FINANCIAMIENTO') AND e.created_by = :userID "
            + "UNION "
            + "SELECT e.payment, e.expense_type, e.driver_id, e.description, " + complete_name + ", e.id FROM expense e LEFT JOIN person p ON e.driver_id = p.id WHERE p.id IS NULL AND e.taxi_id is null AND DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND expense_type NOT IN ('MANDADOS','APOYO_VIAL') AND expense_type IN ('INICIO','PAGO_ORDEN_SERVICIO','ABONO_FINANCIAMIENTO') AND e.created_by = :userID";

    private final String query_details_expenses_by_type="SELECT e.payment, eic.name, t.customer_id, e.description, " + complete_name + ", e.id FROM expense e INNER JOIN expense_income_catalog eic ON e.id_expense_type = eic.id INNER JOIN taxi t ON e.taxi_id = t.id INNER JOIN person p ON t.customer_id = p.id WHERE DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND eic.type = 'EXPENSE' AND e.created_by = :userID "
            + "UNION "
            +"SELECT e.payment, eic.name, e.driver_id, e.description, " + complete_name + ", e.id FROM expense e INNER JOIN expense_income_catalog eic ON e.id_expense_type = eic.id LEFT JOIN person p ON e.driver_id = p.id WHERE p.id IS NULL AND e.taxi_id is null AND DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND eic.type = 'EXPENSE' AND e.created_by = :userID ";
    
     private final String query_details_expenses_by_type_earning="SELECT e.payment, eic.name, t.customer_id, e.description, " + complete_name + ", e.id FROM expense e INNER JOIN expense_income_catalog eic ON e.id_expense_type = eic.id INNER JOIN taxi t ON e.taxi_id = t.id INNER JOIN person p ON t.customer_id = p.id WHERE DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND eic.type = 'EARNING'  AND e.created_by = :userID "
            + "UNION "
            +"SELECT e.payment, eic.name, e.driver_id, e.description, " + complete_name + ", e.id FROM expense e INNER JOIN expense_income_catalog eic ON e.id_expense_type = eic.id LEFT JOIN person p ON e.driver_id = p.id WHERE p.id IS NULL AND e.taxi_id is null AND DATE(e.created_on)  > " + sub_query_to_find_previously_closing_day + "  AND e.expense_status_type = 'AUTHORIZED' AND eic.type = 'EARNING' AND e.created_by = :userID ";
    
    
    private final String query_details_abono_lote = "SELECT (e.cantidad_pagada + e.cobranza_pagada + e.mandado_pagado), CONCAT(e.tipo_abono, '. Lote: ', IFNULL(lo.folio, ''), '. Fraccionamiento: ', pro.nombre_proyecto) AS tipoAbAndNomPro ,p.id AS client , ROUND(e.pago, 2) AS pago_redondeado,"+complete_name+", + e.id, pro.id as proyecto "
            + "FROM abono_lote e INNER JOIN person p ON e.id_cliente = p.id "
            + "INNER JOIN lote lo "
                + "on e.id_lote=lo.id "
            + "INNER JOIN manzana ma " 
                + "on lo.id_manzana=ma.id "
            + "INNER JOIN proyecto pro "
                + "on ma.id_proyecto=pro.id "
            + "WHERE DATE(e.last_updated_on)  > " + sub_query_to_find_previously_closing_day + " "
            + "AND e.pago_estatus='ENABLED' "
            + "AND e.estatus_activo = 'ENABLED' "
            + "AND e.last_updated_by = :userID ";
    
    private final String query_details_abonos_rembolso_cancelacion_compra_lote= "SELECT (e.cantidad_pagada),CONCAT('ABONO REMBOLSO. Lote: ', IFNULL(lo.folio, ''), '. Fraccionamiento: ', pro.nombre_proyecto) AS tipoAbAndNomPro, p.id AS client , ROUND(e.pago, 2) AS pago_redondeado,"+complete_name+", + e.id "
            + "FROM abonos_rembolso_cancelacion_compra_lote e "
            + " INNER JOIN rembolsos_cancelacion_compra_lote re "
                + "on re.id=e.id_rembolso "
            + " INNER JOIN solicitudes_cancelacion_compra_lote so "
                + "on so.id=re.id_solicitud "
            + " INNER JOIN person p "
                + "on p.id = so.id_persona_lote "
            + "INNER JOIN lote lo "
                + "on so.id_lote=lo.id "
            + "INNER JOIN manzana ma "
                + "on lo.id_manzana=ma.id "
            + "INNER JOIN proyecto pro "
                + "on ma.id_proyecto=pro.id "
            + " WHERE DATE(e.last_updated_on)  > " + sub_query_to_find_previously_closing_day + " "
            + " AND e.pago_estatus = 'ENABLED' "
            + " AND e.estatus_activo = 'ENABLED' "
            + " AND e.last_updated_by = :userID ";
    
     private final String query_details_devolucion_abono= "SELECT (e.cantidad_devuelta),CONCAT('DEVOLUCIÓN DE ABONO SALIDA. Lote: ', IFNULL(lo.folio, ''), '. Fraccionamiento: ', pro.nombre_proyecto) AS tipoAbAndNomPro, p.id AS client , ROUND(e.cantidad_devuelta, 2) AS pago_redondeado,"+complete_name+", + e.id "            
             + "FROM devolucion_abono e "             
            + " INNER JOIN solicitud_devolucion_abono so "
                + "on so.id=e.id_solicitud_devolucion_abono "             
             + " INNER JOIN abono_lote ab "
                + "on ab.id=so.id_abono_lote "             
            + " INNER JOIN person p "
                + "on p.id = ab.id_cliente "             
            + "INNER JOIN lote lo "
                + "on lo.id=ab.id_lote "             
            + "INNER JOIN manzana ma "
                + "on lo.id_manzana=ma.id "             
            + "INNER JOIN proyecto pro "
                + "on ma.id_proyecto=pro.id "             
            + " WHERE DATE(e.last_updated_on)  > " + sub_query_to_find_previously_closing_day + " "             
            + " AND e.pago_estatus = 'ENABLED' "
            + " AND e.estatus_activo = 'ENABLED' "
            + " AND e.solicitante = :userID ";
     
     private final String query_details_devolucion_abono_entrada= "SELECT (e.cantidad_devuelta),CONCAT('DEVOLUCIÓN DE ABONO ENTRADA. Lote: ', IFNULL(lo.folio, ''), '. Fraccionamiento: ', pro.nombre_proyecto) AS tipoAbAndNomPro, p.id AS client , ROUND(e.cantidad_devuelta, 2) AS pago_redondeado,"+complete_name+", + e.id "            
             + "FROM devolucion_abono_entrada e "             
            + " INNER JOIN solicitud_devolucion_abono so "
                + "on so.id=e.id_solicitud_devolucion_abono "             
             + " INNER JOIN abono_lote ab "
                + "on ab.id=so.id_abono_lote "             
            + " INNER JOIN person p "
                + "on p.id = ab.id_cliente "             
            + "INNER JOIN lote lo "
                + "on lo.id=ab.id_lote "             
            + "INNER JOIN manzana ma "
                + "on lo.id_manzana=ma.id "             
            + "INNER JOIN proyecto pro "
                + "on ma.id_proyecto=pro.id "             
            + " WHERE DATE(e.last_updated_on)  > " + sub_query_to_find_previously_closing_day + " "             
            + " AND e.pago_estatus = 'ENABLED' "
            + " AND e.estatus_activo = 'ENABLED' "
            + " AND e.solicitante = :userID ";
   
    private final String query_details_abono_proyecto = "SELECT e.pago, e.tipo_abono,p.id as proveedor , predio.nombre_proyecto,"+complete_name+", + e.id FROM abono_proyecto e "
            + "INNER JOIN proyecto predio on e.id_proyecto = predio.id "
            + "INNER JOIN person p ON predio.id_propietario = p.id WHERE DATE(e.last_updated_on)  > " + sub_query_to_find_previously_closing_day + " AND pago_estatus='ENABLED' AND e.last_updated_by = :userID ";

   
    private final String query_details_abono_lote_detalle = "SELECT (ed.pago + ed.cobranza + ed.mandado), CONCAT(e.tipo_abono, '. Lote: ', IFNULL(lo.folio, ''), '. Fraccionamiento: ', pro.nombre_proyecto) AS tipoAbAndNomPro ,p.id AS client , ROUND(e.pago, 2) AS pago_redondeado,"+complete_name+", + ed.id, pro.id as proyecto " 
            + "FROM abono_lote_detalle ed "
            + "INNER JOIN abono_lote e on ed.id_abono_lote = e.id "
            + "INNER JOIN person p ON e.id_cliente = p.id "
            + "INNER JOIN lote lo "
                + "on e.id_lote=lo.id "
            + "INNER JOIN manzana ma " 
                + "on lo.id_manzana=ma.id "
            + "INNER JOIN proyecto pro "
                + "on ma.id_proyecto=pro.id "
            + "WHERE DATE(ed.created_on)  > " + sub_query_to_find_previously_closing_day + " "
            + "AND ed.estatus_activo = 'ENABLED' "
            + "AND ed.created_by = :userID ";
    
    final Logger logger = LogManager.getLogger(ClosingDayController.class);
    private static final long serialVersionUID = -6732331411572526429L;
}
