/*
 * 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.admin;

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.Taxi;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.BoxType;
import com.arrebol.taxiservicios.model.enums.ExpenseCatalogType;
import com.arrebol.taxiservicios.model.enums.ExpenseIncomeType;
import com.arrebol.taxiservicios.model.enums.ExpenseStatusType;
import com.arrebol.taxiservicios.model.enums.ExpenseType;
import com.arrebol.taxiservicios.model.enums.ServiceOrderType;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrder;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderHasProduct;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
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 oscarvargas
 */
public class ExpenseController extends ConnectionManager implements Serializable {

   private static final String EMPTY = "";

   @Deprecated
   public List<Expense> fillExpenseDatatable() {

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

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

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

         Path<String> idPath = root.get("id");
         Path<String> folioPath = root.get("folio");
         Path<String> paymentPath = root.get("payment");
         Path<String> paymentDatePath = root.get("paymentDate");
         Path<String> descriptionPath = root.get("description");
         Path<String> typePath = root.get("type");
         Path<String> statusPath = root.get("status");
         Path<String> taxiPath = root.get("taxi");

         criteria.select(
                 builder.construct(Expense.class, idPath, folioPath, paymentPath, paymentDatePath,
                         descriptionPath, typePath, statusPath, taxiPath
                 ));

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

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

      return result;
   }

   /**
    * Use a left join, query = select * from EXPENSE exp left join TAXI tax on
    * exp.TAXI_ID = tax.ID left join PERSON per on exp.DRIVER_ID = per.ID order
    * by exp.CREATED_ON;
    *
    * @return List of all expense.
    */
   public List<Expense> fillExpenseDatatableLeftJoin() {
      logger.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 "
                 + "LEFT JOIN Taxi tax ON exp.taxi = tax.id "
                 + "LEFT JOIN Person per ON exp.driver = per.id "
                 + "WHERE exp.type NOT IN ('INICIO')"
                 + "ORDER BY exp.createdOn DESC";

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

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

      return result;
   }

   public List<Expense> fillExpenseDataTableBetweenDates(Date starDate, Date endDate, Location location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

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

         Predicate searchType = builder.notEqual(root.get("type"), ExpenseType.INICIO);
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localStartDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn").as(LocalDate.class), localEndDate);
         Predicate locationPredicate = builder.equal(root.get("location"), location);

         query.where(builder.and(
                 searchType, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTablePendingDeposit(Location location) {
      logger.info("fillExpenseDataTablePendingDeposit");

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

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

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

         Predicate searchType = builder.notEqual(root.get("type"), ExpenseType.INICIO);
         Predicate pending = builder.equal(root.get("depositStatus"), ExpenseStatusType.PENDING);
         Predicate bankCardNotNull = builder.isNotNull(root.get("bankCard"));

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

         query.where(builder.and(
                 searchType, locationPredicate, pending, bankCardNotNull
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public boolean autorizarExpense(String expenseId, User user) {
      logger.info("autorizar");

      boolean success = false;
      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> rootUpdate = update.from(Expense.class);

         update.set("depositStatus", ExpenseStatusType.AUTHORIZED);
         update.set("lastUpdatedBy", user);
         update.set("lastUpdatedOn", new Date());
         update.where(builder.equal(rootUpdate.get("id"), expenseId));

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

         if (1 == total) {
            transaction.commit();
            success = true;
            logger.info("Sale " + expenseId + " updated");
         } else {
            transaction.rollback();
            logger.error("Error Sale updated total: " + total);
         }
      } catch (HibernateException e) {
         logger.error("Sale can not be updated ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method autorizar() ", e);
         rollback(transaction);
      }
      return success;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesAbono(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate searchType = builder.equal(root.get("type"), ExpenseType.ABONO_FINANCIAMIENTO);
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 searchType, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesIngresosCajaChica(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate predicateType = builder.equal(root.get("idExpenseType").get("expenseIncomeCatalogType"), ExpenseIncomeType.EARNING);
         Predicate predicateAffects = builder.equal(root.get("idExpenseType").get("activePaymentCustomer"), BasicType.DISABLED);
         Predicate predicateBox = builder.or(builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.SMALL), builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.BOTH));
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 predicateBox, predicateType, predicateAffects, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesIngresosGeneral(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate predicateType = builder.equal(root.get("idExpenseType").get("expenseIncomeCatalogType"), ExpenseIncomeType.EARNING);
         Predicate predicateBox = builder.or(builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.GENERAL), builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.BOTH));
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 predicateBox, predicateType, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesEgresosCajaChica(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate predicateType = builder.equal(root.get("idExpenseType").get("expenseIncomeCatalogType"), ExpenseIncomeType.EXPENSE);
         Predicate predicateInversion = builder.equal(root.get("idExpenseType").get("expenseCatalogType"), ExpenseCatalogType.EXPENSE);
         Predicate predicateBox = builder.or(builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.SMALL), builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.BOTH));
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 predicateBox, predicateType, predicateInversion, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesEgresosCajaChicaInversion(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate predicateType = builder.equal(root.get("idExpenseType").get("expenseIncomeCatalogType"), ExpenseIncomeType.EXPENSE);
         Predicate predicateInversion = builder.equal(root.get("idExpenseType").get("expenseCatalogType"), ExpenseCatalogType.INVESTMENT);
         Predicate predicateBox = builder.or(builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.SMALL), builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.BOTH));
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 predicateBox, predicateType, predicateInversion, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseDataTableBetweenDatesEgresosGeneral(Date starDate, Date endDate, String location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

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

         Predicate predicateType = builder.equal(root.get("idExpenseType").get("expenseIncomeCatalogType"), ExpenseIncomeType.EXPENSE);
         Predicate predicateBox = builder.or(builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.GENERAL), builder.equal(root.get("idExpenseType").get("activeBox"), BoxType.BOTH));
         Predicate startDatePredicate = builder.greaterThanOrEqualTo(root.get("createdOn"), starDate);
         Predicate endDatePredicate = builder.lessThanOrEqualTo(root.get("createdOn"), endDate);
         Predicate locationPredicate = builder.equal(root.get("location").get("id"), location);

         query.where(builder.and(
                 predicateBox, predicateType, startDatePredicate, endDatePredicate, locationPredicate
         ));
         query.orderBy(builder.asc(root.get("createdOn")));

         results = session.createQuery(query).getResultList();
         transaction.commit();
         logger.info("Total of Expense founds in auto complete search " + results.size());
      } catch (HibernateException e) {
         rollback(transaction);
         logger.error("Can not load auto complete list of Expense", e);
      } catch (Exception e) {
         rollback(transaction);
         logger.error("Method fillExpenseDataTableBetweenDates", e);
      }

      return results;
   }

   public List<Expense> fillExpenseIniciosDataTableBetweenDates(Date starDate, Date endDate, Location location) {
      logger.info("fillExpenseDataTableBetweenDates");

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

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

         results = session.createQuery("SELECT exp FROM Expense exp "
                 + "LEFT JOIN Taxi tax ON exp.taxi = tax.id "
                 + "LEFT JOIN Person per ON exp.driver = per.id "
                 + "WHERE exp.type IN ('INICIO') AND "
                 + "(DATE(exp.createdOn) BETWEEN DATE(:starDate) AND DATE(:endDate)) AND "
                 + "exp.location.id = :location ORDER BY exp.createdOn DESC")
                 .setParameter("starDate", starDate)
                 .setParameter("endDate", endDate)
                 .setParameter("location", location.getId())
                 .getResultList();

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

      return results;
   }

   /**
    *
    * @return
    */
   public List<Expense> fillExpenseInicios(String idLocation) {
      logger.info("Searching all inicios expenses..");

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

         String query = "SELECT exp FROM Expense exp WHERE exp.type = 'INICIO' AND exp.location.id = '" + idLocation + "' ORDER BY exp.createdOn DESC";

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

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

      return result;
   }

   public List<User> findAllSystemUser() {
      logger.info("Searching all findAllSystemUser..");

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

         String query = "SELECT usr FROM User usr "
                 + " WHERE "
                 + " usr.userStatusType = 'ENABLED' "
                 + " AND usr.active = true "
                 + " ORDER BY usr.createdOn DESC";

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

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

      return result;
   }

   public List<User> findAllSystemUserByLocation(Location location) {
      logger.info("Searching all findAllSystemUser..");

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

         String query = "SELECT usr FROM User usr "
                 + " WHERE "
                 + " usr.userStatusType = 'ENABLED' "
                 + " AND usr.active = true AND usr.location.id = '" + location.getId() + "' "
                 + " ORDER BY usr.createdOn DESC";

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

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

      return result;
   }

   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 boolean addExpense(Expense expense, String userId, String taxiId) {
      logger.info("addExpense");
      logger.info("taxiId " + taxiId);

      Person idDriver = null;

      if (null != taxiId) {
         idDriver = getDriverByTaxi(taxiId);
      }

      boolean success = false;

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

         expense.setCreatedBy(new User(userId, ""));

         if (null != idDriver) {
            expense.setDriver(idDriver);
         }

         if (null != taxiId) {
            expense.setTaxi(new Taxi(taxiId));
         }
         session.save(expense);
         logger.info("Expense saved " + expense.getId());
         transaction.commit();

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

   public Person getDriverByTaxi(String taxiId) {

      Transaction transaction = null;
      Person result = null;

      try {
         logger.info("Searching driver by taxi..");
         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> driverPath = root.get("driver");

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

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

         result = session.createQuery(criteria).uniqueResult().getDriver();
         transaction.commit();
         logger.info("Taxi found");
      } catch (HibernateException e) {
         logger.error("Can not load the taxi by driver ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method getTaxiByDriver of Sale", e);
         rollback(transaction);
      }

      return result;
   }

   public void updateAdeudoTaxi(Taxi taxi) {
      logger.info("deleteById");

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

         CriteriaBuilder builder = session.getCriteriaBuilder();

         builder = session.getCriteriaBuilder();
         CriteriaUpdate<Taxi> update = builder.createCriteriaUpdate(Taxi.class);
         Root<Taxi> root = update.from(Taxi.class);

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

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

         session.createQuery(update).executeUpdate();

         transaction.commit();

         logger.info("Adeudo actualizado");

      } catch (HibernateException e) {
         logger.error("PaymentCliente can not be deleted ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method deleteSanctionById() ", e);
         rollback(transaction);
      }

   }

   public void returnServiceOrder(Expense expense, User user) {
      logger.info("deleteById");

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

         CriteriaBuilder builder = session.getCriteriaBuilder();

         builder = session.getCriteriaBuilder();
         CriteriaUpdate<ServiceOrder> update = builder.createCriteriaUpdate(ServiceOrder.class);
         Root<ServiceOrder> root = update.from(ServiceOrder.class);

         update.set("serviceOrderType", ServiceOrderType.FINISHED);
         update.set("payUser", null);
         update.set("payDate", null);
         update.set("lastUpdatedBy", user);
         update.set("lastUpdatedOn", new Date());

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

         session.createQuery(update).executeUpdate();

         transaction.commit();

         logger.info("ServiceOrder actualizado");

      } catch (HibernateException e) {
         logger.error("Service Order can not be deleted ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("returnServiceOrder ", e);
         rollback(transaction);
      }

   }

   public void returnServiceOrderHasProduct(Expense expense, User user) {
      logger.info("deleteById");

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

         CriteriaBuilder builder = session.getCriteriaBuilder();

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

         update.set("cobrado", BasicType.DISABLED);

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

         update.set("lastUpdatedBy", user);
         update.set("lastUpdatedOn", new Date());

         session.createQuery(update).executeUpdate();

         transaction.commit();

         logger.info("ServiceOrder actualizado");

      } catch (HibernateException e) {
         logger.error("Service Order can not be deleted ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("returnServiceOrder ", e);
         rollback(transaction);
      }

   }

   public boolean deleteExpenseById(String expenseId) {
      logger.info("deleteExpenseById");

      boolean success = false;
      Transaction transaction = null;
      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         CriteriaBuilder builder = session.getCriteriaBuilder();
         CriteriaDelete<Expense> delete = builder.createCriteriaDelete(Expense.class);
         Root<Expense> root = delete.from(Expense.class);

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

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

         if (1 == total) {
            transaction.commit();
            success = true;
            logger.info("Expense " + expenseId + " deleted");
         } else {
            transaction.rollback();
            logger.error("Error Expense deleted total: " + total);
         }
      } catch (HibernateException e) {
         logger.error("Expense can not be deleted ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method deleteExpenseById() ", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean disabledExpense(Expense expense, User user) {
      logger.info("disabledExpense");
      boolean success = false;
      Transaction transaction = null;
      try {
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         transaction = session.beginTransaction();
         expense.setStatus(ExpenseStatusType.DISABLED);
         expense.setLastUpdatedBy(user);
         expense.setLastUpdatedOn(correcciónDeHr(new Date(), -7));
         session.update(expense);
         transaction.commit();
         success = true;
      } catch (HibernateException e) {
         logger.error("Can not disabled expense", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method disabledExpense()", e);
         rollback(transaction);
      }
      return success;
   }

   public boolean autorizarExpenseById(String expenseId) {
      logger.info("autorizarExpenseById");

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

         CriteriaBuilder builder = session.getCriteriaBuilder();

         builder = session.getCriteriaBuilder();
         CriteriaUpdate<Expense> update = builder.createCriteriaUpdate(Expense.class);
         Root<Expense> rootUpdate = update.from(Expense.class);

         update.set("status", ExpenseStatusType.AUTHORIZED);
         update.where(builder.equal(rootUpdate.get("id"), expenseId));

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

         if (1 == total) {
            transaction.commit();
            success = true;
            logger.info("Expense " + expenseId + " autorizhed");
         } else {
            transaction.rollback();
            logger.error("Error Expense autorizhed total: " + total);
         }
      } catch (HibernateException e) {
         logger.error("Expense can not be autorizhed ", e);
         rollback(transaction);
      } catch (Exception e) {
         logger.error("Method autorizarExpenseById() ", e);
         rollback(transaction);
      }
      return success;
   }

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

   private static final long serialVersionUID = -4436342523608482137L;

   final Logger logger = LogManager.getLogger(ExpenseController.class);

   public ExpenseController() {
   }

}
