package com.arrebol.taxiservicios.controller.sp.report;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.admin.Expense;
import com.arrebol.taxiservicios.model.admin.FinancingCustomer;
import com.arrebol.taxiservicios.model.admin.ReleaseResource;
import com.arrebol.taxiservicios.model.admin.Sale;
import com.arrebol.taxiservicios.model.admin.Taxi;
import com.arrebol.taxiservicios.model.catalog.Color;
import com.arrebol.taxiservicios.model.catalog.Product;
import com.arrebol.taxiservicios.model.catalog.Vehicle;
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.ServiceOrderType;
import com.arrebol.taxiservicios.model.sp.report.ReportCustomerPay;
import com.arrebol.taxiservicios.model.stocktaking.Invoice;
import com.arrebol.taxiservicios.model.stocktaking.InvoiceHasProduct;
import com.arrebol.taxiservicios.model.stocktaking.InvoiceHasProductId;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrder;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderHasProduct;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderHasProductId;
import com.arrebol.taxiservicios.model.stocktaking.view.KardexOutStocktakingView;
import com.arrebol.taxiservicios.model.view.report.PaymentClient;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Tuple;
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;

/**
 *
 * @author Carlos Janitzio Zavala López.
 */
public class ReportCustomerPayController extends ConnectionManager implements Serializable {

    public PaymentClient getPaymentClientById(String paymentId) {
        LOG.info("getPaymentClientById");

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

            sanction = session.get(PaymentClient.class, paymentId);

            transaction.commit();
            LOG.info("PaymentClient " + sanction);
        } catch (HibernateException e) {
            LOG.error("PaymentClient cannot be loaded " + paymentId, e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getPaymentClientById(" + paymentId + ") ", e);
            rollback(transaction);
        }
        return sanction;
    }

    public Taxi getTaxiById(String taxiId) {

        Transaction transaction = null;
        Taxi result = null;

        try {
            LOG.info("Searching taxi by id..");
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

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

            Path<String> idPath = root.get("id");
            Path<String> economicNumberPath = root.get("economicNumber");
            Path<String> vehiclePath = root.get("vehicle");
            Path<String> colorPath = root.get("color");
            Path<String> placaPath = root.get("placa");
            Path<String> serialNumberPath = root.get("serialNumber");
            Path<String> motorNmumberPath = root.get("motorNmumber");
            Path<String> commentsPath = root.get("comments");
            Path<String> yearPath = root.get("year");
            Path<String> insuranceNumber = root.get("insuranceNumber");
            Path<Date> insuranceEndDate = root.get("insuranceEndDate");
            Path<Float> adeudo = root.get("adeudo");

            criteria.select(
                    builder.construct(Taxi.class, idPath, economicNumberPath,
                            vehiclePath, colorPath,
                            placaPath, serialNumberPath, motorNmumberPath,
                            commentsPath, yearPath, insuranceNumber, insuranceEndDate, adeudo
                    ));

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

            result = session.createQuery(criteria).uniqueResult();

            transaction.commit();
            LOG.info("Taxi founds");
        } catch (HibernateException e) {
            rollback(transaction);
            LOG.error("Can not load taxi object ", e);
        } catch (Exception e) {
            rollback(transaction);
            LOG.error("Method getTaxiById of Taxi", e);
        }

        return result;
    }

    public boolean savePaymentClient(PaymentClient paymentClient) {
        boolean success = false;
        Transaction transaction = null;

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

            session.save(paymentClient);
            transaction.commit();

            success = true;

            LOG.info("New record was inserted in PaymentClient");
        } catch (HibernateException e) {
            LOG.error("Can not insert a PaymentClient event", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method savePaymentClient()", e);
            rollback(transaction);
        }
        return success;
    }

    public boolean saveFinancingClient(FinancingCustomer financingCustomer) {
        boolean success = false;
        Transaction transaction = null;

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

            session.save(financingCustomer);
            transaction.commit();

            success = true;

            LOG.info("New record was inserted in FinancingCustomer");
        } catch (HibernateException e) {
            LOG.error("Can not insert a FinancingCustomer event", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method saveFinancingClient()", e);
            rollback(transaction);
        }
        return success;
    }

    public boolean updateTaxiById(Taxi taxi) {
        LOG.info("updateTaxiById");

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

            CriteriaBuilder builder = session.getCriteriaBuilder();

            CriteriaUpdate<Taxi> update = builder.createCriteriaUpdate(Taxi.class);
            Root<Taxi> rootPerson = update.from(Taxi.class);

            update.set("adeudo", taxi.getAdeudo());

            update.where(builder.equal(rootPerson.get("id"), taxi.getId()));

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

            if (1 == total) {
                LOG.info("Taxi updated taxi_id: " + taxi.getId());
                transaction.commit();

                success = true;
            } else {
                LOG.error("Taxi can not be updated " + taxi.getId());
                transaction.rollback();
            }
        } catch (HibernateException e) {
            LOG.error("Taxi cannot be updated " + taxi.getId(), e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method updateTaxiById(" + taxi.getId() + ") ", e);
            rollback(transaction);
        }
        return success;
    }

    /**
     *
     * @param starDate
     * @param endDate
     * @param idTaxi
     * @return
     */
    public List<ReportCustomerPay> callReportCustomerPayToMySQLQuery(String starDate, String endDate, String idTaxi) {
        LOG.info("callReportCustomerPayToMySQLQuery");
        LOG.info("Fecha inicial de reporte ReportCustomerPay: " + starDate);
        LOG.info("Fecha final de reporte ReportCustomerPay: " + endDate);

        List<ReportCustomerPay> list = new ArrayList<>();
        Transaction transaction = null;

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

            List<Object> rows = session.createNativeQuery(queryMySQL)
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .setParameter("idTaxi", idTaxi)
                    .getResultList();

            transaction.commit();

            rows.forEach((row) -> {
                Object[] results = (Object[]) row;

                ReportCustomerPay pay = new ReportCustomerPay(
                        null == results[0] ? null : results[0].toString(),
                        null == results[1] ? null : results[1].toString(),
                        null == results[2] ? null : results[2].toString(),
                        Integer.valueOf(null == results[3] ? "0" : results[3].toString()),
                        Integer.valueOf(null == results[16] ? "0" : results[16].toString()),
                        Float.valueOf(null == results[4] ? "0" : results[4].toString()),
                        Float.valueOf(null == results[5] ? "0" : results[5].toString()),
                        Float.valueOf(null == results[6] ? "0" : results[6].toString()),
                        Float.valueOf(null == results[7] ? "0" : results[7].toString()),
                        Float.valueOf(null == results[8] ? "0" : results[8].toString()),
                        Float.valueOf(null == results[9] ? "0" : results[9].toString()),
                        Float.valueOf(null == results[10] ? "0" : results[10].toString()),
                        null == results[11] ? null : results[11].toString(),
                        null == results[12] ? null : results[12].toString(),
                        null == results[13] ? null : results[13].toString(),
                        Float.valueOf(null == results[14] ? "0" : results[14].toString()),
                        Float.valueOf(null == results[15] ? "0" : results[15].toString()),
                        Float.valueOf(null == results[17] ? "0" : results[17].toString()),
                        // calculateNumberOfDaysBetweenDates(starDate, endDate) - Long.valueOf(null == results[16] ? "0" : results[16].toString()),
                        Long.valueOf(null == results[16] ? "0" : results[16].toString()),
                        // calculateNumberOfDaysBetweenDates(starDate, endDate),
                        Long.valueOf(null == results[19] ? "0" : results[19].toString()),
                        Float.valueOf(null == results[18] ? "0" : results[18].toString()),
                        Float.valueOf(null == results[20] ? "0" : results[20].toString()),
                        Float.valueOf(null == results[21] ? "0" : results[21].toString()),
                        Integer.valueOf(null == results[22] ? "0" : results[22].toString()),
                        Float.valueOf(null == results[23] ? "0" : results[23].toString()),
                        Float.valueOf(null == results[24] ? "0" : results[24].toString()),
                        Integer.valueOf(null == results[25] ? "1" : results[25].toString())
                );
                try {
                    pay.setDiasEnBanca(Float.valueOf(results[26].toString()));
                } catch (Exception e) {
                    LOG.error("setDiasEnBanca", e);
                    pay.setDiasEnBanca(0f);
                }
                list.add(pay);
            });

            LOG.info("Success callReportCustomerPayToMySQLQuery");
        } catch (HibernateException e) {
            LOG.error("Report customer pay", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method callReportCustomerPayToMySQLQuery(" + starDate + " " + endDate + ") ", e);
            rollback(transaction);
        }
        return list;
    }

    public List<Taxi> fillTaxisComboBox() {

        Transaction transaction = null;
        List<Taxi> result = null;

        try {
            LOG.info("Searching all taxis to select..");
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

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

            Path<String> id = root.get("id");
            Path<String> placa = root.get("placa");
            Path<String> year = root.get("year");
            Path<Vehicle> vehicle = root.get("vehicle");
            Path<Color> color = root.get("color");

            criteria.select(
                    builder.construct(Taxi.class, id,
                            placa, year, vehicle, color
                    ));

            criteria.where(builder.equal(root.get("active"), Boolean.TRUE));

            criteria.orderBy(
                    builder.asc(root.get("placa"))
            );
            criteria.orderBy(
                    builder.asc(root.get("year"))
            );

            result = session.createQuery(criteria).getResultList();
            transaction.commit();
            LOG.info("Total of taxis found for ComboBox: " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of taxis for ComboBox ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillTaxisComboBox of Sale", e);
            rollback(transaction);
        }

        return result;
    }

    /**
     *
     * @param taxiID
     * @param starDate
     * @param endDate
     * @return
     */
    public List<Expense> fillExpenseDatatableLeftJoin(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all expenses..");

        List<Expense> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM Expense exp "
                    + "JOIN Taxi tax ON exp.taxi = tax.id "
                    + "LEFT JOIN Person per ON exp.driver = per.id "
                    + "WHERE exp.type NOT IN ('INICIO', 'PAGO_CLIENTE') AND exp.taxi = :taxi AND DATE(exp.createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) "
                    + "ORDER BY exp.createdOn DESC";

            result = session.createQuery(query)
                    .setParameter("taxi", new Taxi(taxiID))
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of expenses found for ComboBox: " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of expenses for ComboBox ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillExpenseDatatable of Expense", e);
            rollback(transaction);
        }

        return result;
    }
    
    public List<Expense> fillExpenseDatatableLeftJoinToPay(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all expenses..");

        List<Expense> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM Expense exp "
                    + "JOIN Taxi tax ON exp.taxi = tax.id "
                    + "LEFT JOIN Person per ON exp.driver = per.id "
                    + "WHERE exp.type NOT IN ('INICIO', 'PAGO_CLIENTE','ABONO_FINANCIAMIENTO') AND exp.taxi = :taxi AND DATE(exp.createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) AND ((exp.paid = 'DISABLED' AND exp.finance = 'DISABLED') OR (exp.paid = 'DISABLED' AND exp.finance = 'ENEBLED'))"
                    + "ORDER BY exp.createdOn DESC";

            result = session.createQuery(query)
                    .setParameter("taxi", new Taxi(taxiID))
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of expenses found for ComboBox: " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of expenses for ComboBox ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillExpenseDatatable of Expense", e);
            rollback(transaction);
        }

        return result;
    }
    
    public List<Expense> fillExpenseDatatableLeftJoinToFinance(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all expenses..");

        List<Expense> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM Expense exp "
                    + "JOIN Taxi tax ON exp.taxi = tax.id "
                    + "LEFT JOIN Person per ON exp.driver = per.id "
                    + "WHERE exp.type NOT IN ('INICIO', 'PAGO_CLIENTE','ABONO_FINANCIAMIENTO') AND exp.taxi = :taxi AND DATE(exp.createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) AND (exp.paid = 'DISABLED' AND exp.finance = 'DISABLED') "
                    + "ORDER BY exp.createdOn DESC";

            result = session.createQuery(query)
                    .setParameter("taxi", new Taxi(taxiID))
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of expenses found for ComboBox: " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of expenses for ComboBox ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillExpenseDatatable of Expense", e);
            rollback(transaction);
        }

        return result;
    }

    public List<PaymentClient> fillPaymentClientDatatable(String taxiID) {
        LOG.info("Searching all payment client..");

        List<PaymentClient> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM PaymentClient exp "
                    + "WHERE exp.activeStatus = 'ENEBLED' AND exp.taxi = '" + taxiID + "' "
                    + "ORDER BY exp.createdOn DESC";

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

            transaction.commit();
            LOG.info("Total of payment client found : " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of payment client ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillPaymentClientDatatable of PaymentClient", e);
            rollback(transaction);
        }

        return result;
    }

    public List<ReleaseResource> fillReleaseDatatable(String taxiID) {
        LOG.info("Searching all payment client..");

        List<ReleaseResource> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM ReleaseResource exp "
                    + "WHERE exp.taxi = '" + taxiID + "' "
                    + "ORDER BY exp.startDate DESC";

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

            transaction.commit();
            LOG.info("Total of release resource found : " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of release resource ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillReleaseDatatable of ReleaseResource", e);
            rollback(transaction);
        }

        return result;
    }

    public List<KardexOutStocktakingView> fillProductsDetailByOrderServices(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all payment client..");

        List<KardexOutStocktakingView> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM KardexOutStocktakingView exp "
                    + "WHERE exp.taxiId = :taxiId AND DATE(exp.fecha) BETWEEN DATE(:starDate) AND DATE(:endDate) AND exp.estatus = 'FINISHED' AND ((exp.cobrado = 'No cobrado' AND exp.financiado = 'No financiado') OR (exp.cobrado = 'No cobrado' AND exp.financiado = 'Financiado')) "
                    + "ORDER BY exp.fecha DESC";

            result = session.createQuery(query)
                    .setParameter("taxiId", taxiID)
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of KardexOutStocktakingView found : " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of KardexOutStocktakingView ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillProductsDetailByOrderServices of KardexOutStocktakingView", e);
            rollback(transaction);
        }

        return result;
    }
    
    
    public List<KardexOutStocktakingView> fillProductsDetailByOrderServicesFinancing(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all payment client..");

        List<KardexOutStocktakingView> result = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            String query = "SELECT exp FROM KardexOutStocktakingView exp "
                    + "WHERE exp.taxiId = :taxiId AND DATE(exp.fecha) BETWEEN DATE(:starDate) AND DATE(:endDate) AND exp.estatus = 'FINISHED' AND exp.cobrado = 'No cobrado' AND exp.financiado = 'No financiado' "
                    + "ORDER BY exp.fecha DESC";

            result = session.createQuery(query)
                    .setParameter("taxiId", taxiID)
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of KardexOutStocktakingView found : " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of KardexOutStocktakingView ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillProductsDetailByOrderServices of KardexOutStocktakingView", e);
            rollback(transaction);
        }

        return result;
    }

    public List<Sale> getSalesbyTaxi(String taxiId, Date initialDate, Date endDate) {

        Transaction transaction = null;
        List<Sale> result = null;

        try {
            LOG.info("Searching all sales by taxi..");

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

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

            Path<String> payDayPath = root.get("payDay");
            Path<String> idPath = root.get("id");
            Path<String> savingDayPath = root.get("paySaving");
            Path<String> payDatePath = root.get("payDate");
            Path<String> accidentPath = root.get("accident");
            Path<String> descriptionPath = root.get("description");
            Path<Person> person = root.get("person");
            Path<Taxi> taxi = root.get("taxi");
            Path<String> createdOnPath = root.get("createdOn");
            Path<Boolean> garagePath = root.get("garage");

            criteria.select(
                    builder.construct(Sale.class, idPath, payDayPath,
                            savingDayPath, payDatePath, accidentPath,
                            descriptionPath, person, createdOnPath, taxi, garagePath)
            );

            Predicate initialDatePredicate = builder.greaterThanOrEqualTo(root.get("payDate"), initialDate);
            Predicate lastDatePredicate = builder.lessThanOrEqualTo(root.get("payDate"), endDate);

            criteria.where(builder.equal(root.get("taxi"), new Taxi(taxiId)),
                    builder.and(
                            initialDatePredicate,
                            lastDatePredicate
                    )
            );

            criteria.orderBy(
                    builder.asc(root.get("payDate"))
            );

            result = session.createQuery(criteria).getResultList();

            transaction.commit();
            LOG.info("Total of sales by taxi: " + result);
        } catch (HibernateException e) {
            LOG.error("Can not load the information for total sales by taxi ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getSalesbyTaxi of Sale", e);
            rollback(transaction);
        }

        return result;
    }

    /**
     *
     * @param taxiId
     * @param initialDate
     * @param endDate
     * @return
     */
    public List<Sale> getSalesbyTaxiTuple(String taxiId, Date initialDate, Date endDate) {
        Transaction transaction = null;
        List<Sale> result = new ArrayList<>();

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

            StringBuilder hql = new StringBuilder();

            hql.append("SELECT ");
            hql.append("s.id AS id, s.payDay AS payDay, s.paySaving AS paySaving, ");
            hql.append("s.payDate AS payDate, s.accident AS accident, ");
            hql.append("s.description AS description, s.person AS person, ");
            hql.append("s.createdOn AS createdOn, s.taxi AS taxi, (CASE WHEN s.garage IS NULL THEN false ELSE s.garage END) AS garage, ");
            hql.append("(CASE WHEN s.nuevaAsignacion IS NULL THEN false ELSE s.nuevaAsignacion END) AS nuevaAsignacion, ");
            hql.append("(CASE WHEN s.banca IS NULL THEN false ELSE s.banca END) AS banca, s.payDayAsSpected as payDayAsSpected ");
            hql.append("FROM Sale s ");
            hql.append("WHERE ");
            hql.append("DATE(s.payDate) BETWEEN DATE(:initialDate) AND DATE(:endDate) AND ");
            hql.append("s.taxi = :taxi ");
            hql.append("ORDER BY s.payDate");

            LOG.info("initialDate: " + initialDate);
            LOG.info("endDate: " + endDate);
            LOG.info("query: " + hql.toString());

            List<Tuple> tuples = session.createQuery(hql.toString(), Tuple.class)
                    .setParameter("initialDate", initialDate)
                    .setParameter("endDate", endDate)
                    .setParameter("taxi", new Taxi(taxiId))
                    .getResultList();

            transaction.commit();

            tuples.forEach((tuple) -> {
                result.add(
                        new Sale(
                                tuple.get("id", String.class),
                                tuple.get("payDay", Double.class),
                                tuple.get("paySaving", Double.class),
                                tuple.get("payDate", Date.class),
                                tuple.get("accident", Double.class),
                                tuple.get("description", String.class),
                                tuple.get("person", Person.class),
                                tuple.get("createdOn", Date.class),
                                tuple.get("taxi", Taxi.class),
                                tuple.get("garage", Boolean.class),
                                tuple.get("nuevaAsignacion", Boolean.class),
                                tuple.get("banca", Boolean.class),
                                tuple.get("payDayAsSpected", Double.class)
                        )
                );
            });

            LOG.info("Total of sales tuples by taxi: " + result.size());
        } catch (HibernateException e) {
            LOG.error("Can not load the information for total sales tuples by taxi ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getSalesbyTaxiTuple of Sale", e);
            rollback(transaction);
        }

        return result;
    }

    /**
     *
     * @param taxiID
     * @param starDate
     * @param endDate
     * @return
     */
    public List<Invoice> fillInvoiceDatatableLeftJoin(String taxiID, Date starDate, Date endDate) {
        LOG.info("Searching all invoice..");

        List<Invoice> result = null;
        Transaction transaction = null;

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

            result = session.createQuery("SELECT exp FROM Invoice exp JOIN Taxi tax ON exp.taxi = tax.id WHERE exp.taxi = :taxi AND DATE(exp.createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) ORDER BY exp.createdOn DESC")
                    .setParameter("taxi", new Taxi(taxiID))
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            LOG.info("Total of invoice found for ComboBox: " + (null == result ? -1 : result.size()));
        } catch (HibernateException e) {
            LOG.error("Can not load list of invoice for ComboBox ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method fillInvoiceDatatableLeftJoin of invoice", e);
            rollback(transaction);
        }

        return result;
    }

    public List<ServiceOrder> getAllServiceOrderActiveAndStatusIn(String idVehiculo,
            Date startDate, Date endDate) {
        LOG.info("getAllServiceOrderActive");

        List<ServiceOrder> serviceOrders = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ServiceOrder> query = builder.createQuery(ServiceOrder.class);

            Root<ServiceOrder> root = query.from(ServiceOrder.class);

            Path<String> id = root.get("id");
            Path<String> name = root.get("name");
            Path<Integer> nameNumber = root.get("nameNumber");
            Path<Float> km = root.get("km");
            Path<Float> kmMaintenance = root.get("kmMaintenance");
            Path<ServiceOrderType> serviceOrderType = root.get("serviceOrderType");
            Path<Taxi> taxi = root.get("taxi");
            Path<Taxi> createdOn = root.get("createdOn");
            Path<String> pendingDate = root.get("pendingDate");
            Path<String> approvateDate = root.get("approvateDate");
            Path<String> progressDate = root.get("progressDate");
            Path<String> finishDate = root.get("finishDate");
            Path<String> description = root.get("description");

            Predicate inClause = builder.equal(root.get("taxi"), new Taxi(idVehiculo));
            Predicate initialDate = builder.greaterThanOrEqualTo(root.get("createdOn"), startDate);
            Predicate lastDate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);

            query.select(
                    builder.construct(ServiceOrder.class,
                            id, name, nameNumber, km, serviceOrderType, taxi, createdOn,
                            pendingDate, approvateDate, progressDate, finishDate, description, kmMaintenance
                    )
            );
            query.where(
                    builder.and(
                            builder.equal(root.get("active"), true),
                            inClause, initialDate, lastDate
                    )
            );
            query.orderBy(builder.asc(root.get("nameNumber")));

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

            transaction.commit();
            LOG.info("Total of Service Orders loaded " + serviceOrders.size());
        } catch (HibernateException e) {
            LOG.error("Service Orders cannot be loaded ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getAllServiceOrderActive() ", e);
            rollback(transaction);
        }
        return serviceOrders;
    }

    public List<ServiceOrder> getAllServiceOrderActiveAndStatusInTuple(String idVehiculo,
            Date startDate, Date endDate) {
        LOG.info("getAllServiceOrderActiveAndStatusInTuple");

        List<ServiceOrder> serviceOrders = new ArrayList<>();
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            StringBuilder hql = new StringBuilder();

            hql.append("SELECT so.id AS id, so.name AS name, so.nameNumber AS nameNumber, ");
            hql.append("so.km AS km, so.serviceOrderType AS serviceOrderType, so.taxi AS taxi, so.createdOn AS createdOn, ");
            hql.append("so.pendingDate AS pendingDate, so.approvateDate AS approvateDate, so.progressDate AS progressDate, ");
            hql.append("so.finishDate AS finishDate, so.description AS description, so.kmMaintenance AS kmMaintenance ");
            hql.append("FROM ServiceOrder so ");
            hql.append("WHERE so.active = true AND ");
            hql.append("DATE(so.createdOn) BETWEEN DATE(:startDate) AND DATE(:endDate) AND ");
            hql.append("so.taxi = :idVehiculo ");
            hql.append("ORDER BY so.nameNumber");

            List<Tuple> tuples = session.createQuery(hql.toString(), Tuple.class)
                    .setParameter("idVehiculo", new Taxi(idVehiculo))
                    .setParameter("startDate", startDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();

            tuples.forEach((tuple) -> {

                serviceOrders.add(
                        new ServiceOrder(
                                tuple.get("id", String.class),
                                tuple.get("name", String.class),
                                tuple.get("nameNumber", Integer.class),
                                tuple.get("km", Float.class),
                                tuple.get("serviceOrderType", ServiceOrderType.class),
                                tuple.get("taxi", Taxi.class),
                                tuple.get("createdOn", Date.class),
                                tuple.get("pendingDate", Date.class),
                                tuple.get("approvateDate", Date.class),
                                tuple.get("progressDate", Date.class),
                                tuple.get("finishDate", Date.class),
                                tuple.get("description", String.class),
                                tuple.get("kmMaintenance", Float.class)
                        )
                );
            });

            LOG.info("Total of Service Orders loaded " + serviceOrders.size());
        } catch (HibernateException e) {
            LOG.error("Service Orders cannot be loaded ", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getAllServiceOrderActiveAndStatusInTuple() ", e);
            rollback(transaction);
        }
        return serviceOrders;
    }

    /**
     *
     * @param id
     * @return
     */
    public List<ServiceOrderHasProduct> findAllProductByOrderId(String id) {
        LOG.info("getServiceOrderHasProduct");

        List<ServiceOrderHasProduct> list = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ServiceOrderHasProduct> query = builder.createQuery(ServiceOrderHasProduct.class);

            Root<ServiceOrderHasProduct> root = query.from(ServiceOrderHasProduct.class);

            Path<ServiceOrderHasProductId> sohpId = root.get("id");
            Path<Product> product = root.get("product");
            Path<Integer> quantity = root.get("quantity");
            Path<Float> price = root.get("price");
            Path<Float> total = root.get("total");

            query.select(builder.construct(ServiceOrderHasProduct.class,
                    sohpId, product, quantity, price, total));

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

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

            transaction.commit();
            LOG.info("Load all products by Service Order");
        } catch (HibernateException e) {
            LOG.error("HibernateException getServiceOrderHasProduct()", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method getServiceOrderHasProduct() ", e);
            rollback(transaction);
        }
        return list;
    }

    public List<InvoiceHasProduct> findAllProductByInvoiceId(String id) {
        LOG.info("findAllProductByInvoiceId");

        List<InvoiceHasProduct> list = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<InvoiceHasProduct> query = builder.createQuery(InvoiceHasProduct.class);

            Root<InvoiceHasProduct> root = query.from(InvoiceHasProduct.class);

            Path<InvoiceHasProductId> sohpId = root.get("id");
            Path<Product> product = root.get("product");
            Path<Integer> quantity = root.get("quantity");
            Path<Float> price = root.get("priceMenudeo");
            Path<User> usuario = root.get("createdBy");

            query.select(builder.construct(InvoiceHasProduct.class,
                    sohpId, product, price, quantity, usuario));

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

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

            transaction.commit();
            LOG.info("Load all products by Invoice");
        } catch (HibernateException e) {
            LOG.error("HibernateException findAllProductByInvoiceId()", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method findAllProductByInvoiceId() ", e);
            rollback(transaction);
        }
        return list;
    }

    public void editServicesHasProduct(ServiceOrderHasProductId id) {
        Transaction transaction = null;

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

            CriteriaUpdate<ServiceOrderHasProduct> update = builder.createCriteriaUpdate(ServiceOrderHasProduct.class);
            Root<ServiceOrderHasProduct> root = update.from(ServiceOrderHasProduct.class);

            update.set("cobrado", BasicType.ENEBLED);
            update.set("paymentClient",id.getPaymentClient());
            update.set("payCreatedBy",id.getPayCreatedBy());
            update.set("payDate",id.getPayDate());

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

            session.createQuery(update).executeUpdate();

            LOG.info("The ServiceOrderHasProduct was edited");

            transaction.commit();
        } catch (HibernateException e) {
            LOG.error("The ServiceOrderHasProduct can not be saved", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method editServicesHasProduct", e);
            rollback(transaction);
        }
    }
    
    public void editServicesHasProductFinance(ServiceOrderHasProductId id) {
        Transaction transaction = null;

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

            CriteriaUpdate<ServiceOrderHasProduct> update = builder.createCriteriaUpdate(ServiceOrderHasProduct.class);
            Root<ServiceOrderHasProduct> root = update.from(ServiceOrderHasProduct.class);

            update.set("financiado", BasicType.ENEBLED);
            update.set("paymentClientFinance",id.getPaymentClient());
            update.set("financeCreatedBy",id.getFinanceCreatedBy());
            update.set("financeDate",id.getFinanceDate());

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

            session.createQuery(update).executeUpdate();

            LOG.info("The ServiceOrderHasProduct was edited");

            transaction.commit();
        } catch (HibernateException e) {
            LOG.error("The ServiceOrderHasProduct can not be saved", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method editServicesHasProduct", e);
            rollback(transaction);
        }
    }
    
    public void editExpenseToPay(Expense expense) {
        Transaction transaction = null;

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

            CriteriaUpdate<Expense> update = builder.createCriteriaUpdate(Expense.class);
            Root<Expense> root = update.from(Expense.class);

            update.set("paid", BasicType.ENEBLED);
            update.set("paymentClient",expense.getPaymentClient());
            update.set("paymentDate",expense.getPaymentDate());

            update.where(builder.equal(root.get("id"), expense.getId()));

            session.createQuery(update).executeUpdate();

            LOG.info("The Expense was edited");

            transaction.commit();
        } catch (HibernateException e) {
            LOG.error("The ServiceOrderHasProduct can not be saved", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method editServicesHasProduct", e);
            rollback(transaction);
        }
    }
    
    public void editExpenseToFinance(Expense expense) {
        Transaction transaction = null;

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

            CriteriaUpdate<Expense> update = builder.createCriteriaUpdate(Expense.class);
            Root<Expense> root = update.from(Expense.class);

            update.set("finance", BasicType.ENEBLED);
            update.set("paymentClientFinance",expense.getPaymentClientFinance());
            update.set("financeDate",expense.getFinanceDate());

            update.where(builder.equal(root.get("id"), expense.getId()));

            session.createQuery(update).executeUpdate();

            LOG.info("The Expense was edited");

            transaction.commit();
        } catch (HibernateException e) {
            LOG.error("The ServiceOrderHasProduct can not be saved", e);
            rollback(transaction);
        } catch (Exception e) {
            LOG.error("Method editServicesHasProduct", e);
            rollback(transaction);
        }
    }

    private static final long serialVersionUID = 3405798902357776578L;

    final Logger LOG = LogManager.getLogger(ReportCustomerPayController.class);

    private final String diasEnBancaSQL = "(SELECT \n"
            + "IFNULL("
            + "SUM(\n"
            + "(CASE\n"
            + "	   -- start_date   = 2022-04-11	end_date	= null\n"
            + "    -- fecha_inicio = 2022-03-21	fecha_fin	= 2022-05-01\n"
            + "	WHEN DATE(start_date) >= STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NULL\n"
            + "		THEN  totalDaysInARangeOfDates(DATE(start_date), STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/, TRUE)\n"
            + "	    -- start_date   = 2022-04-11	end_date	= 2022-04-13\n"
            + "    -- fecha_inicio = 2022-03-21	fecha_fin	= 2022-05-01\n"
            + "    WHEN DATE(start_date) >= STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NOT NULL AND DATE(end_date) <= STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/\n"
            + "		THEN totalDaysInARangeOfDates(DATE(start_date), DATE(end_date), TRUE)\n"
            + "	   -- start_date   = 2022-04-11	end_date	= 2022-05-06\n"
            + "    -- fecha_inicio = 2022-03-21	fecha_fin	= 2022-05-01\n"
            + "	WHEN DATE(start_date) >= STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NOT NULL AND DATE(end_date) > STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/\n"
            + "		THEN \n"
            + "			CASE \n"
            + "				WHEN DATEDIFF(DATE(STR_TO_DATE(:endDate,'%Y-%m-%d')/*:endDate*/), DATE(start_date)) > 0\n"
            + "					THEN  totalDaysInARangeOfDates(DATE(start_date), STR_TO_DATE(:endDate,'%Y-%m-%d')/*:endDate*/, TRUE)\n"
            + "				ELSE 0\n"
            + "			END\n"
            + "    -- start_date   = 2022-04-30	end_date	= null\n"
            + "    -- fecha_inicio = 2022-05-01	fecha_fin	= 2022-05-15\n"
            + "	WHEN DATE(start_date) < STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NULL\n"
            + "		THEN  \n"
            + "			CASE\n"
            + "				WHEN DATEDIFF(DATE(STR_TO_DATE(:endDate,'%Y-%m-%d')/*:endDate*/), STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/) > 0\n"
            + "					THEN totalDaysInARangeOfDates(STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/, STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/, TRUE)\n"
            + "				ELSE 0\n"
            + "            END\n"
            + "	   -- start_date   = 2022-04-30	end_date	= 2022-05-03\n"
            + "    -- fecha_inicio = 2022-05-01	fecha_fin	= 2022-05-06\n"
            + "    WHEN  DATE(start_date) < STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NOT NULL AND DATE(end_date) <= STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/\n"
            + "		THEN  \n"
            + "			CASE\n"
            + "				WHEN DATEDIFF(DATE(end_date),STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/) > 0\n"
            + "					THEN totalDaysInARangeOfDates(STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/, DATE(end_date), TRUE)\n"
            + "				ELSE 0\n"
            + "            END\n"
            + "	   -- start_date   = 2022-04-30	end_date	= 2022-05-07\n"
            + "    -- fecha_inicio = 2022-05-01	fecha_fin	= 2022-05-06\n"
            + "	WHEN  DATE(start_date) < STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/ AND DATE(end_date) IS NOT NULL AND DATE(end_date) > STR_TO_DATE(:endDate,'%Y-%m-%d') /*:endDate*/\n"
            + "		THEN \n"
            + "			CASE \n"
            + "				WHEN  DATEDIFF(DATE(STR_TO_DATE(:endDate,'%Y-%m-%d')/*:endDate*/), STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/) > 0\n"
            + "					THEN  totalDaysInARangeOfDates(STR_TO_DATE(:starDate,'%Y-%m-%d') /*:starDate*/, STR_TO_DATE(:endDate,'%Y-%m-%d')/*:endDate*/, TRUE)\n"
            + "				ELSE 0\n"
            + "			END\n"
            + "    ELSE 0\n"
            + "END\n"
            + ")),0) as diff\n"
            + "FROM RELEASE_RESOURCE \n"
            + "WHERE taxi_id = :idTaxi\n"
            + "AND DATEDIFF(IFNULL(DATE(end_date),:endDate), DATE(start_date)) > 0) AS dias_en_banca_del_taxi ";

    private final String queryMySQL = "SELECT  "
            + "t.economic_number, "
            + "concat(cstmr.first_name, ' ', cstmr.second_name, ' ', cstmr.last_name, ' ', cstmr.middle_name) as customer_name, "
            + "IF(ISNULL(drvr.id), '', concat(drvr.first_name, ' ', drvr.second_name, ' ', drvr.last_name, ' ', drvr.middle_name)) as driver_name, "
            + "(select COUNT(DISTINCT(pay_date)) from SALE where taxi_id = t.id and DATE_ADD(DATE(pay_date), interval 1 day) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) as worked_days, "
            + "IF(ISNULL( "
            + "(select SUM(pay_day) from SALE where taxi_id = t.id and DATE_ADD(DATE(pay_date), interval 1 day) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d') and LOWER(DAYNAME(DATE_ADD(DATE(pay_date), interval 1 day))) not in ('sunday')) "
            + "),0, "
            + "(select SUM(pay_day) from SALE where taxi_id = t.id and DATE_ADD(DATE(pay_date), interval 1 day) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d') and LOWER(DAYNAME(DATE_ADD(DATE(pay_date), interval 1 day))) not in ('sunday')) "
            + ") AS total_worked_to_pay_days, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('BILL','NOTE','ELECTRICO','MANDADOS','APOYO_VIAL') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('BILL','NOTE','ELECTRICO','MANDADOS','APOYO_VIAL') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_electric_expense, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'TORNO' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "), 0, (select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'TORNO' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_torno_expense, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'SOLDADURA' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'SOLDADURA' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_soldadura_expense, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'ESTETICO' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'ESTETICO' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS  total_estetico_expense, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'GRUA' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type = 'GRUA' and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_grua_expense, "
            + "IF(ISNULL( "
            + "(select sum(subtotal) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(subtotal) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_service_order, "
            + "IF(ISNULL( "
            + "(select GROUP_CONCAT(concat(' ',name)) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),'', "
            + "(select GROUP_CONCAT(concat(' ',name)) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS service_order_folios, "
            + "IF(ISNULL( "
            + "(select GROUP_CONCAT(concat(' ',description)) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),'', "
            + "(select GROUP_CONCAT(concat(' ',description)) from SERVICE_ORDER where taxi_id = t.id and service_order_type = 'FINISHED' and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS service_order_desc, "
            + "IF(ISNULL( "
            + "(select GROUP_CONCAT(concat(' ',srvc.name)) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + "),'', "
            + "(select GROUP_CONCAT(concat(' ',srvc.name)) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + ") AS contract_service, "
            + "IF(ISNULL( "
            + "(select sum(srvc.charge) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + "),0, "
            + "(select sum(srvc.charge) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + ") AS total_contract_service, "
            + "(select  "
            + "CASE  "
            + "WHEN sum(TIMESTAMPDIFF(MINUTE, progress_date, finish_date)) > 1080 THEN sum(TIMESTAMPDIFF(MINUTE, progress_date, finish_date))/1080 "
            + "WHEN sum(TIMESTAMPDIFF(MINUTE, progress_date, finish_date)) > 540 and sum(TIMESTAMPDIFF(MINUTE, progress_date, finish_date)) < 1080 THEN 0.5 "
            + "ELSE 0 "
            + "END "
            + "from SERVICE_ORDER  "
            + "where taxi_id = t.id and service_order_type = 'FINISHED'  "
            + "and DATE(finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d') "
            + ") as total_pays_to_discount, "
            + "( "
            //+ "SELECT datediff(STR_TO_DATE(:endDate,'%Y-%m-%d'), STR_TO_DATE(:starDate, '%Y-%m-%d')) DIV 7 + (CASE WHEN (CASE WHEN DAYOFWEEK(STR_TO_DATE(:starDate, '%Y-%m-%d'))-1 = 0 THEN 7 ELSE DAYOFWEEK(STR_TO_DATE(:starDate, '%Y-%m-%d'))-1 END) = 7 THEN 1 ELSE 0 END) "
            + "totalDaysInARangeOfDates(STR_TO_DATE(:starDate,'%Y-%m-%d'), STR_TO_DATE(:endDate, '%Y-%m-%d'), TRUE)"
            + ") AS to_collect_days, "
            + "t.payment_car AS payment_car, "
            + "IF(ISNULL( "
            + "(select SUM(pay_day) from SALE where taxi_id = t.id and DATE_ADD(DATE(pay_date), interval 1 day) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d') and LOWER(DAYNAME(DATE_ADD(DATE(pay_date), interval 1 day))) in ('sunday')) "
            + "),0, "
            + "(select SUM(pay_day) from SALE where taxi_id = t.id and DATE_ADD(DATE(pay_date), interval 1 day) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d') and LOWER(DAYNAME(DATE_ADD(DATE(pay_date), interval 1 day))) in ('sunday')) "
            + ") AS total_worked_to_pay_days_sunday, "
            + "(totalDaysInARangeOfDates(STR_TO_DATE(:starDate,'%Y-%m-%d'), STR_TO_DATE(:endDate, '%Y-%m-%d'), FALSE)) as total_days_include_sundays, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('OTRAS_ENTRADAS') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('OTRAS_ENTRADAS') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_otras_entradas, "
            + "IF(ISNULL( "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('OTRAS_SALIDAS') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(amount_menudeo) from EXPENSE where taxi_id = t.id and expense_type IN ('OTRAS_SALIDAS') and DATE(payment_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_otras_salidas, "
            + "IF(ISNULL( "
            + "(select sum(srvc.discount_fix) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + "),0, "
            + "(select sum(srvc.discount_fix) from CONTRACT cntrct inner join CONTRACT_HAS_SERVICE chs on cntrct.id = chs.contract_id inner join SERVICE srvc on chs.service_id = srvc.id where cntrct.taxi_id = t.id and cntrct.active = 1) "
            + ") AS total_discount_contract_service, "
            + "IF(ISNULL( "
            + "(select sum(sohp.total) from SERVICE_ORDER_HAS_PRODUCT sohp inner join SERVICE_ORDER chs on sohp.service_order_id = chs.id inner join PRODUCT p on sohp.product_id = p.id where chs.taxi_id = t.id and chs.active = 1 and p.brand_id = '5d70cb1e-c545-4f87-9d2d-99f9d172992f' AND DATE(chs.finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + "),0, "
            + "(select sum(sohp.total) from SERVICE_ORDER_HAS_PRODUCT sohp inner join SERVICE_ORDER chs on sohp.service_order_id = chs.id inner join PRODUCT p on sohp.product_id = p.id where chs.taxi_id = t.id and chs.active = 1 and p.brand_id = '5d70cb1e-c545-4f87-9d2d-99f9d172992f' AND DATE(chs.finish_date) between STR_TO_DATE(:starDate, '%Y-%m-%d') AND STR_TO_DATE(:endDate,'%Y-%m-%d')) "
            + ") AS total_car_driver, "
            + "t.pay_day as pagoDiario, "
            +"t.work_days as weekDays, "
            + diasEnBancaSQL
            + "FROM TAXI t INNER JOIN PERSON cstmr ON t.customer_id = cstmr.id LEFT JOIN PERSON drvr ON t.driver_id = drvr.id "
            + "WHERE t.active = 1 and t.id = :idTaxi and cstmr.active = 1";
}
