/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.arrebol.taxiservicios.controller.stocktaking;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.admin.Taxes;
import com.arrebol.taxiservicios.model.admin.Taxi;
import com.arrebol.taxiservicios.model.catalog.Brand;
import com.arrebol.taxiservicios.model.catalog.Color;
import com.arrebol.taxiservicios.model.catalog.Location;
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.ExpenseStatusType;
import com.arrebol.taxiservicios.model.enums.PersonType;
import com.arrebol.taxiservicios.model.enums.StatusType;
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.ProductInvoiceBk;
import com.arrebol.taxiservicios.model.stocktaking.view.StocktakingInvoiceView;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.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 oscarvargas
 */
public class InvoiceController extends ConnectionManager implements Serializable {
    
    /**
     * 
     * @param economicNumber
     * @return 
     */
    public List<String> autoCompleVehicle(String economicNumber) {
        logger.info("autoCompleVehicle");

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

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

            results = session.createQuery("SELECT DISTINCT(economicNumber) FROM StocktakingInvoiceView WHERE economicNumber LIKE :economicNumber")
                    .setParameter("economicNumber", economicNumber)
                    .getResultList();

            transaction.commit();
            logger.info("Total of vehicles founds in auto complete search " + results.size());
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of vehicles", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method autoCompleVehicle", e);
        }

        return results;
    }
    
    public List<InvoiceHasProduct> findAllProductByInvoiceId(String id) {
        logger.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();
            logger.info("Load all products by Invoice");
        } catch (HibernateException e) {
            logger.error("HibernateException findAllProductByInvoiceId()", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findAllProductByInvoiceId() ", e);
            rollback(transaction);
        }
        return list;
    }

    /**
     * 
     * @param starDate
     * @param endDate
     * @return 
     */
    public List<StocktakingInvoiceView> fillDataTableBetweenDates(Date starDate, Date endDate) {
        logger.info("autoCompleVehicle");

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

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

            results = session.createQuery("FROM StocktakingInvoiceView WHERE DATE(createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) ORDER BY createdOn DESC")
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .getResultList();

            transaction.commit();
            logger.info("Total of vehicles founds in auto complete search " + results.size());
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of vehicles", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method autoCompleVehicle", e);
        }

        return results;
    }
    public List<Invoice> fillDataTableDepositPending(String idLocation) {
        logger.info("autoCompleVehicle");

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

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

           
            Predicate pending = builder.equal(root.get("depositStatus"), ExpenseStatusType.PENDING);
            Predicate bankCardNotNull = builder.isNotNull(root.get("bankCard"));

            Predicate locationPredicate = builder.equal(root.get("location"), new Location(idLocation));

            //query.select(builder.construct(Taxes.class, id, amount, description, createdOn, createdByPath, locationPath, activeStatusPath, taxesTypePath));
            query.where(builder.and(
                    pending, bankCardNotNull, locationPredicate
            ));
            query.orderBy(builder.desc(root.get("createdOn")));

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

            transaction.commit();

            logger.info("Total of vehicles founds in auto complete search " + results.size());
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of vehicles", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method autoCompleVehicle", e);
        }

        return results;
    }
    
    public List<StocktakingInvoiceView> fillDataTableBetweenDatesByLocation(Date starDate, Date endDate, String idLocation) {
        logger.info("fillDataTableBetweenDatesByLocation");

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

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

            results = session.createQuery("FROM StocktakingInvoiceView WHERE DATE(createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate) AND location = :location ORDER BY createdOn DESC")
                    .setParameter("starDate", starDate)
                    .setParameter("endDate", endDate)
                    .setParameter("location", idLocation)
                    .getResultList();

            transaction.commit();
            logger.info("Total of vehicles founds in auto complete search " + results.size());
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of vehicles", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method autoCompleVehicle", e);
        }

        return results;
    }

    /**
     *
     * @param economicNumber
     * @return
     */
    public List<StocktakingInvoiceView> findAllInvoicesByEconomicNumber(String economicNumber) {
        logger.info("autoCompleVehicle");

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

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

            results = session.createQuery("FROM StocktakingInvoiceView WHERE economicNumber = :economicNumber ORDER BY createdOn, provider")
                    .setParameter("economicNumber", economicNumber)
                    .getResultList();

            transaction.commit();
            logger.info("Total of vehicles founds in auto complete search " + results.size());
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load auto complete list of vehicles", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findAllInvoicesByEconomicNumber", e);
        }

        return results;
    }

    /**
     *
     * @param id
     * @return
     */
    public StocktakingInvoiceView findStocktakingInvoiceById(String id) {
        StocktakingInvoiceView result = null;
        Transaction transaction = null;

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

            result = session.find(StocktakingInvoiceView.class, id);

            transaction.commit();
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not found stocktaking invoice by id", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method findStocktakingInvoiceById", e);
        }

        return result;
    }

    /**
     * Get invoice by Identify Number.
     *
     * @param id Identify primary key.
     * @return Invoice if id exist otherwise null.
     */
    public Invoice loadInvoicebyId(String id) {
        logger.info("loadInvoicebyId, id: " + id);
        Transaction transaction = null;
        Invoice invoice = null;

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

            invoice = session.get(Invoice.class, id);

            transaction.commit();

            logger.info(invoice);
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not load list of invoices ", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method fillInvoiceDatatable of Invoice", e);
        }

        return invoice;
    }

    public List<Invoice> fillInvoiceDatatableLeftJoin() {
        logger.info("Searching all invoice..");

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

            String query = "SELECT exp FROM Invoice exp "
                    + "LEFT JOIN Taxi tax ON exp.taxi = tax.id "
                    + "ORDER BY exp.createdOn DESC";

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

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

        return result;
    }

    public List<StocktakingInvoiceView> fillInvoiceFromStocktakinfInvoiceView() {
        logger.info("Searching all invoice from view..");

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

            String query = "FROM StocktakingInvoiceView";

            result = session.createQuery(query, StocktakingInvoiceView.class).getResultList();

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

        return result;
    }

    /**
     *
     * Searching all invoices for list.
     *
     * @return
     */
    public List<Invoice> fillInvoiceDatatable() {

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

        try {
            logger.info("Searching all invoices..");
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

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

            Path<String> idPath = root.get("id");
            Path<String> folioPath = root.get("folio");
            Path<String> buyDatePath = root.get("buyDate");
            Path<String> personPath = root.get("person");
            Path<String> subtotalPath = root.get("subtotal");
            Path<String> ivaPath = root.get("iva");
            Path<String> totalPath = root.get("total");
            Path<String> statusTypePath = root.get("statusType");
            Path<String> createdOnPath = root.get("createdOn");
            Path<String> commentPath = root.get("comment");
            Path<String> taxiPath = root.get("taxi");

            criteria.select(
                    builder.construct(Invoice.class, idPath, folioPath, buyDatePath, personPath, subtotalPath, ivaPath, totalPath, statusTypePath, createdOnPath,
                            commentPath, taxiPath));

            criteria.where(builder.equal(root.get("active"), Boolean.TRUE));
            result = session.createQuery(criteria).getResultList();

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

        return result;
    }

    /**
     * Do a logical delete from an invoice in the system.
     *
     * @param invoiceId Invoice Identify number.
     * @param productInvoiceBks Backup product's list.
     * @return True if the invoice was logical deleted otherwise false.
     */
    public boolean deleteInvoiceById(String invoiceId, List<ProductInvoiceBk> productInvoiceBks) {
        logger.info("deleteInvoiceById");

        boolean success = false;

        Transaction transaction = null;

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

            // Do backup for each product and delete backup record.
            productInvoiceBks.forEach((ProductInvoiceBk backupProduct) -> {
                Product productToBackup = session.get(Product.class, backupProduct.getProduct().getId());

                Integer quantity = productToBackup.getQuantity() - backupProduct.getQuantity();

                productToBackup.setAmount(backupProduct.getAmount());
                productToBackup.setQuantity(quantity);

                session.update(productToBackup);

                ProductInvoiceBk productToDelete = session.get(ProductInvoiceBk.class, backupProduct.getId());

                session.delete(productToDelete);
            });

            // Get for delete all InvoiceHasProduct of invoice.
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<InvoiceHasProduct> criteria = builder.createQuery(InvoiceHasProduct.class);
            Root<InvoiceHasProduct> root = criteria.from(InvoiceHasProduct.class);

            criteria.where(builder.equal(root.get("invoice"), new Invoice(invoiceId)));

            session.createQuery(criteria).getResultList().forEach((InvoiceHasProduct result) -> {
                session.delete(result);
            });

            //Get for delete invoice.
            Invoice invoice = session.get(Invoice.class, invoiceId);

            session.delete(invoice);
            transaction.commit();

            success = true;
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Can not delete the invoice", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method deleteInvoiceById", e);
        }

        return success;
    }

    /**
     * Get a list of providers availables is system.
     *
     * @return List of providers details.
     */
    public List<Person> fillProviderComboBox() {
        logger.info("Searching all providers to select..");

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

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

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

            Path<String> idPath = root.get("id");
            Path<String> firstNamePath = root.get("firstName");
            Path<String> secondNamePath = root.get("secondName");
            Path<String> lastNamePath = root.get("lastName");
            Path<String> middleNamePath = root.get("middleName");

            criteria.select(
                    builder.construct(Person.class, idPath, firstNamePath, secondNamePath, lastNamePath, middleNamePath
                    ));

            criteria.where(builder.equal(root.get("personType"), PersonType.PROVIDER));

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

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

        return result;
    }
    
    public List<Person> fillDriversComboBox() {
        logger.info("Searching all drivers to select..");

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

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

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

            Path<String> idPath = root.get("id");
            Path<String> firstNamePath = root.get("firstName");
            Path<String> secondNamePath = root.get("secondName");
            Path<String> lastNamePath = root.get("lastName");
            Path<String> middleNamePath = root.get("middleName");

            criteria.select(
                    builder.construct(Person.class, idPath, firstNamePath, secondNamePath, lastNamePath, middleNamePath
                    ));

            criteria.where(builder.equal(root.get("personType"), PersonType.DRIVER));

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

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

        return result;
    }

    /**
     * Save Invoice and Its product's list.
     *
     * @param invoice Invoice to be saved.
     * @param products List of product.
     * @return true is saved was succesful otherwise false.
     */
    public boolean saveInvoice(Invoice invoice, List<InvoiceHasProduct> products) {
        logger.info("saveInvoice");

        boolean success = false;
        Transaction transaction = null;

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

            session.save(invoice);
            logger.info("Invoice saved " + invoice.getId());
            logger.info("Provider saved " + invoice.getPerson().getId());

            products.forEach((InvoiceHasProduct invoiceHasProduct) -> {
                session.save(invoiceHasProduct);
            });

            //Backup product details before to update stocktaking.
            products.forEach((InvoiceHasProduct prdct) -> {
                Product productToBackup = session.get(Product.class, prdct.getId().getProductId());

                ProductInvoiceBk backup = new ProductInvoiceBk(
                        UUID.randomUUID().toString(),
                        invoice,
                        new Product(prdct.getId().getProductId()),
                        productToBackup.getAmount(),
                        productToBackup.getQuantity(),
                        prdct.getCreatedBy(),
                        new Date(),
                        productToBackup.getUtility());

                session.save(backup);
            });

            logger.info("Backup product details: " + products.size());

            //Update product details from invoice.
            products.forEach((prdct) -> {
                Product productFromDB = session.get(Product.class, prdct.getId().getProductId());
                int totalQuantity = 0;
                if(invoice.getLocation().getId().equalsIgnoreCase("4d0859be-e31a-4acb-a690-2a5c2cb027a7"))
                {
                   totalQuantity = prdct.getQuantity() + productFromDB.getQuantity();
                   productFromDB.setQuantity(totalQuantity);
                   productFromDB.setAmount(prdct.getPriceMenudeo().doubleValue());
                   productFromDB.setUtility(prdct.getPrice().doubleValue());
                }
                else
                {
                    totalQuantity = prdct.getQuantity() + productFromDB.getQuantity2();
                    productFromDB.setQuantity2(totalQuantity);
                    productFromDB.setAmount2(prdct.getPriceMenudeo().doubleValue());
                    productFromDB.setUtility2(prdct.getPrice().doubleValue());
                }
                
                productFromDB.setLastUpdatedBy(prdct.getLastUpdatedBy());
                productFromDB.setLastUpdatedOn(new Date());

                session.save(prdct);
            });

            transaction.commit();

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

    /**
     * Update follow Invoice details: folio, buy date, provider and comments
     *
     * @param invoice Invoice to be saved.
     * @return true is edit was succesful otherwise false.
     */
    public boolean updateInvoice(Invoice invoice) {
        logger.info("updateInvoice");

        boolean success = false;
        Transaction transaction = null;

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

            //Get Invoice object into hibernate persistance.
            Invoice invoicetoUpdate = session.get(Invoice.class, invoice.getId());

            //Prepare update details for invoice.
            invoicetoUpdate.setFolio(invoice.getFolio());
            invoicetoUpdate.setBuyDate(invoice.getBuyDate());
            invoicetoUpdate.setPerson(invoice.getPerson());
            invoicetoUpdate.setComment(invoice.getComment());
            invoicetoUpdate.setLastUpdatedBy(invoice.getLastUpdatedBy());
            invoicetoUpdate.setLastUpdatedOn(invoice.getLastUpdatedOn());

            //Update invoice.
            session.update(invoicetoUpdate);
            transaction.commit();

            success = true;
        } catch (HibernateException e) {
            logger.error("Invoice can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateInvoice() ", e);
            rollback(transaction);
        }
        return success;
    }
    
     public boolean authorizeInvoice(StocktakingInvoiceView invoice, User user) {
        logger.info("authorizeInvoice");
        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            //Get Invoice object into hibernate persistance.
            Invoice invoicetoUpdate = session.get(Invoice.class, invoice.getId());
            //Prepare update details for invoice.
            invoicetoUpdate.setAuthorize(StatusType.APPROVED);
            invoicetoUpdate.setLastUpdatedBy(user);
            invoicetoUpdate.setLastUpdatedOn(new Date());
            //Update invoice.
            session.update(invoicetoUpdate);
            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Invoice can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateInvoice() ", e);
            rollback(transaction);
        }
        return success;
    }
     
     public boolean authorizeInvoiceDeposit(Invoice invoice, User user) {
        logger.info("authorizeInvoice");
        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            //Get Invoice object into hibernate persistance.
            
            //Prepare update details for invoice.
            invoice.setDepositStatus(ExpenseStatusType.AUTHORIZED);
            invoice.setLastUpdatedBy(user);
            invoice.setLastUpdatedOn(new Date());
            //Update invoice.
            session.update(invoice);
            transaction.commit();
            success = true;
        } catch (HibernateException e) {
            logger.error("Invoice can not be updated ", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateInvoice() ", e);
            rollback(transaction);
        }
        return success;
    }
     
      

    /**
     * Get all products available to
     *
     * @return
     */
    public List<Product> fillProductsComboBox() {

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

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

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

            Path<String> idPath = root.get("id");
            Path<String> namePath = root.get("name");
            Path<String> codePath = root.get("code");
            Path<Brand> brandPath = root.get("brand");

            criteria.select(
                    builder.construct(Product.class, idPath, namePath, codePath, brandPath
                    ));
            criteria.where(builder.equal(root.get("activeStatus"), BasicType.ENEBLED));

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

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

        return result;
    }

    /**
     * Load all product details that an invoice has.
     *
     * @param invoiceId Invoice Identify number.
     * @return A list of invoice product details if match by id otherwise null.
     */
    public List<InvoiceHasProduct> fillInvoiceHasProductDatatable(String invoiceId) {
        logger.info("Searching all InvoiceHasProduct for datatable..");

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

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

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

            Path<String> idPath = root.get("id");
            Path<String> productPath = root.get("product");
            Path<String> pricePath = root.get("price");
            Path<String> quantityPath = root.get("quantity");

            criteria.select(
                    builder.construct(InvoiceHasProduct.class, idPath, productPath, pricePath, quantityPath
                    ));

            criteria.where(builder.equal(root.get("invoice"), new Invoice(invoiceId)));

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

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

        return result;
    }

    /**
     * Search in backup tables if Invoice has details.
     *
     * @param invoiceId Invoice Identify number.
     * @return Retur a list of invoice backup detail.
     */
    public List<ProductInvoiceBk> seachInvoiceInBackupById(String invoiceId) {
        logger.info("seachInvoiceInBackupById");

        List<ProductInvoiceBk> invoiceBks = null;
        Transaction transaction = null;

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

            CriteriaBuilder builder = session.getCriteriaBuilder();

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

            Path<String> idPath = root.get("id");
            Path<Product> productPath = root.get("product");
            Path<Double> amountPath = root.get("amount");
            Path<Integer> quantityPath = root.get("quantity");

            criteria.select(
                    builder.construct(ProductInvoiceBk.class, idPath, productPath, amountPath, quantityPath
                    ));

            criteria.where(builder.equal(root.get("invoice"), new Invoice(invoiceId)));

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

            transaction.commit();
        } catch (HibernateException e) {
            rollback(transaction);
            logger.error("Error searching for a invoice in Bakup table", e);
        } catch (Exception e) {
            rollback(transaction);
            logger.error("Method seachInvoiceInBackupById", e);
        }
        return invoiceBks;
    }

    public List<Taxi> fillTaxisComboBox() {

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

        try {
            logger.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> idPath = root.get("id");
            Path<String> economicNumberPath = root.get("economicNumber");

            criteria.select(
                    builder.construct(Taxi.class, idPath, economicNumberPath
                    ));

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

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

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

        return result;
    }
    
    public List<Taxi> fillTaxisComboBox2() {

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

        try {
            logger.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> idPath = root.get("id");
            Path<String> economicNumberPath = root.get("economicNumber");
            Path<Color> colorPath = root.get("color");
            Path<Vehicle> vehiclePath = root.get("vehicle");
            Path<Person> personPath = root.get("customer");

            criteria.select(
                    builder.construct(Taxi.class, idPath, personPath, economicNumberPath, colorPath, vehiclePath
                    ));

            criteria.where(builder.and(builder.equal(root.get("active"), Boolean.TRUE), builder.equal(root.get("gps"), BasicType.ENEBLED)));

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

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

        return result;
    }

    private static final long serialVersionUID = -793156951909596418L;

    final Logger logger = LogManager.getLogger(InvoiceController.class);
    private final float iva = .16f;

    public InvoiceController() {
    }
}
