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

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClientBuilder;
import com.amazonaws.services.simpleemail.model.Body;
import com.amazonaws.services.simpleemail.model.Content;
import com.amazonaws.services.simpleemail.model.Destination;
import com.amazonaws.services.simpleemail.model.Message;
import com.amazonaws.services.simpleemail.model.SendEmailRequest;
import com.amazonaws.services.simpleemail.model.SendEmailResult;
import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.CustomerController;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
import com.arrebol.taxiservicios.controller.catalog.EtapasJuridicoController;
import com.arrebol.taxiservicios.controller.catalog.UserLocationController;
import com.arrebol.taxiservicios.controller.cobranza.CobranzaController;
import com.arrebol.taxiservicios.controller.juridicas.DetalleLoteEtapaController;
import com.arrebol.taxiservicios.controller.predio.AbonoLoteController;
import com.arrebol.taxiservicios.controller.predio.DetalleLoteUrbanizacionController;
import com.arrebol.taxiservicios.controller.predio.LoteController;
import com.arrebol.taxiservicios.controller.predio.DevolucionAbonoController;
import com.arrebol.taxiservicios.controller.predio.PreventaController;
import com.arrebol.taxiservicios.controller.predio.UrbanizacionController;
import com.arrebol.taxiservicios.controller.stocktaking.ServiceOrderSingletonController;
import com.arrebol.taxiservicios.controller.system.UserController;
import com.arrebol.taxiservicios.model.catalog.EtapasJuridico;
import com.arrebol.taxiservicios.model.catalog.UserLocation;
import com.arrebol.taxiservicios.model.core.ContactNumber;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.DeliveryStatusType;
import com.arrebol.taxiservicios.model.enums.EstatusLote;
import com.arrebol.taxiservicios.model.enums.EstatusPagoMultiple;
import com.arrebol.taxiservicios.model.enums.EstatusSolicitud;
import com.arrebol.taxiservicios.model.enums.GenericEnumType;
import com.arrebol.taxiservicios.model.enums.PeriodoPago;
import com.arrebol.taxiservicios.model.enums.PersonType;
import com.arrebol.taxiservicios.model.enums.ServiceOrderActionType;
import com.arrebol.taxiservicios.model.enums.TipoAbono;
import com.arrebol.taxiservicios.model.juridicas.DetalleLoteEtapa;
import com.arrebol.taxiservicios.model.predio.AbonoLote;
import com.arrebol.taxiservicios.model.predio.AbonoLoteDetalle;
import com.arrebol.taxiservicios.model.predio.AbonoLoteView;
import com.arrebol.taxiservicios.model.predio.AbonosView;
import com.arrebol.taxiservicios.model.predio.ComentarioLote;
import com.arrebol.taxiservicios.model.predio.DetalleLoteUrbanizacion;
import com.arrebol.taxiservicios.model.predio.HitorialAbonoMultiple;
import com.arrebol.taxiservicios.model.predio.Lote;
import com.arrebol.taxiservicios.model.predio.SolicitudDevolucionAbono;
import com.arrebol.taxiservicios.model.predio.SolicitudDevolucionAbonoMultiple;
import com.arrebol.taxiservicios.model.predio.Urbanizacion;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderNotification;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderNotificationDeliveryTo;
import com.arrebol.taxiservicios.model.view.PersonListView;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.text.SimpleDateFormat;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.imageio.ImageIO;
import javax.inject.Named;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 *
 * @author Usuario
 */
@Named("cobranzaBean")
@ViewScoped
public class CobranzaBean extends TaxiGenericBean implements Serializable {

    private static final long serialVersionUID = -2400590341745672164L;
    final Logger logger = LogManager.getLogger(CobranzaBean.class);
    private PreventaController controladorPreventa;
    private Urbanizacion selectedUrbanizacion;
    private CobranzaController cobranzaController;
    private UserLocationController userLocationController;
    private LoteController loteController;
    private CustomerController customerController;
    private ServiceOrderSingletonController serviceOrderSingletonController;
    private Double pagoUrbanizacion;
    private Double saldoAnteriorUrbanizacion;
    private Double saldoNuevoUrbanizacion;

    private Double totalJuridico;
    private Double pagoJuridicoDado;
    private Double pagoCuentasJuridico;
    private String etapaJuridicoComentario;
    private List<Urbanizacion> listaUrbanizacion;
    private String idEtapa;
    private UrbanizacionController urbanizacionController;
    private Urbanizacion selectUrbanizacion;
    private DetalleLoteUrbanizacion nuevoDetalleLoteUrbanizacion;
    private DetalleLoteUrbanizacionController detalleLoteUrbanizacionController;
    private GenericValidationController genericController;
    private Boolean comboMandados;
    private Boolean comboCobranza;
    private Double totalDado;
    private Double totalPagar;
    private DetalleLoteEtapaController detalleLoteEtapaController;
    private Double totalPagarUrbanizacion;
    private List<EtapasJuridico> listaEtapasJuridico;
    private EtapasJuridico etapaJuridicoSeleccionada;
    private EtapasJuridicoController etapaJuridicoController;

    private DetalleLoteEtapa nuevoDetalleLoteEtapa;
    private List<Lote> lotes;
    private Lote selectedLote;
    private List<PersonListView> personas;
    private String selectUser;
    private String folioLote;
    private List<AbonoLote> abonos;
    private AbonoLote selectAbono;
    private Double pagoDado;
    private Double mandadoDado;
    private Double cobranzaDada;
    private Date FechaPago;
    private Date fechaPagoUrbanizacion;
    private String descripcionPago;
    private String descipcionJuridico;
    private Boolean pagoExitoso;

    private AbonoLoteController abonoLoteController;
    private Double totalAbonosRestantes;
    private List<AbonoLote> abonosRestantes;
    private List<DetalleLoteUrbanizacion> listDetalleLoteUrbanizacion;
    private List<ComentarioLote> comentarioLote;
    private Double newPagoPorConvenio;
    private Double residuoReajuste;
    private Double actualizarPago;

    private DevolucionAbonoController devolucionAbonoController;
    private String comentario;
    private String nuevoComentario;
    private String imagen;

    private Double pagoMultiple;
    private List<AbonoLote> lotesSinPagar;
    private List<AbonoLote> lotesSinPagarIncompletos;
    private String lotesPagoMultiple;
    private boolean pagoMultipleIncompletos;
    private boolean pagoMultipleExitoso;
    private String fechasPagadas;
    private String cantidadPagadaPagoMultiple;
    private Date fechaPagoMultiple;
    private String clientePagoMultiple;
    private String lotePagoMultiple;
    private String predioPagoMultiple;
    private String manzanaPagoMultiple;
    private String usuarioCobroPagoMultiple;
    private String tipoProyectoPagoMultiple;
    private String comentarioMultiple;

    private JasperPrint print;
    private Date fechaActual;
    private List<AbonoLoteView> ListAbonoLoteView;
    private List<String> folios;
    private String foliosImprimir;

    private String detallesAbonoMul;
    private Double cobranza;
    private Double mandado;
    private List<HitorialAbonoMultiple> pagosMultiples;
    private HitorialAbonoMultiple selectPagoMultiple;

    private String ultimoAbonoPagado;
    private String ultimoAbonoMultiplePagado;

    @PostConstruct
    public void init() {
        logger.info("init CobranzaBean");
        try {
            setCobranza(0.0);
            setMandado(0.0);
            setNuevoDetalleLoteEtapa(new DetalleLoteEtapa());
            setTotalJuridico(0D);
            setPagoCuentasJuridico(0D);
            setTotalPagar(0d);
            setDetalleLoteEtapaController(new DetalleLoteEtapaController());
            setDescripcionPago("");
            setPagoJuridicoDado(0d);
            setEtapaJuridicoController(new EtapasJuridicoController());
            setEtapaJuridicoSeleccionada(new EtapasJuridico());
            setListaEtapasJuridico(getEtapaJuridicoController().fillAllEtapasJuridicas(getLoggedUser().getLocation()));
            setMandadoDado(0D);
            setPagoUrbanizacion(0D);
            setNuevoDetalleLoteUrbanizacion(new DetalleLoteUrbanizacion());
            setTotalPagarUrbanizacion(0D);
            setFechaPagoUrbanizacion(new Date());
            setTotalDado(0D);
            setDetalleLoteUrbanizacionController(new DetalleLoteUrbanizacionController());
            setUrbanizacionController(new UrbanizacionController());
            setSelectUrbanizacion(new Urbanizacion());
            setDetalleLoteUrbanizacionController(new DetalleLoteUrbanizacionController());
            setCobranzaDada(0D);
            loadBundlePropertyFile();
            setComboCobranza(false);
            setComboMandados(false);
            setSelectedUrbanizacion(new Urbanizacion());
            setGenericController(new GenericValidationController());
            setControladorPreventa(new PreventaController());
            setLoteController(new LoteController());
            setPersonas(getControladorPreventa().findListOfPersonsByType(PersonType.CUSTOMER, getLoggedUser().getLocation()));
            setFechaActual(new Date());
        } catch (Exception e) {
            logger.error("CobranzaBean init", e);
        }
    }

    public void reimprimirTicket() {
        setPagoExitoso(true);
        setPagoDado(getSelectAbono().getCantidadPagada());
        setCobranzaDada(getSelectAbono().getCobranzaPagada());
        setMandadoDado(getSelectAbono().getMandadoPagado());
        setDescripcionPago(getSelectAbono().getDescripcion());
        setTotalPagar(getPagoDado() + getCobranzaDada() + getMandadoDado());
        // se valida si un abono se pagó por partes para colocar la fecha de pago de último sub abono realizado 
        List<AbonoLoteDetalle> subAbonos = getAbonoLoteController().buscarAbonoLoteDetalleByAbonoLote(getSelectAbono());

        if (!subAbonos.isEmpty()) {
            getSelectAbono().setLastUpdatedOn(subAbonos.get(subAbonos.size() - 1).getCreatedOn());
        }
        setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
            setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
        }

    }

    public void reimprimirTicketUR() {
        setPagoExitoso(true);
        setPagoUrbanizacion(getNuevoDetalleLoteUrbanizacion().getSaldoPagado());
        setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
            setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
        }
    }

    public void calcularTotal() {
        setTotalPagar(getPagoDado());
        if (getComboCobranza() == true) {
            setTotalPagar(getTotalPagar() + getCobranzaDada());
        }
        if (getComboMandados() == true) {
            setTotalPagar(getTotalPagar() + getMandadoDado());
        }
    }

    public void calcularTotalJuridico() {
        setTotalJuridico(getPagoCuentasJuridico() - getPagoJuridicoDado());

    }

    public void calcularTotalUrbanizacion() {
        setTotalPagarUrbanizacion(getPagoUrbanizacion());
    }

    public void paidUrbanizacion() {
        try {
            if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
                showMessage(FacesMessage.SEVERITY_WARN,
                        "Error",
                        "No se puede hacer ninguna acción si existe un corte del día");
                setPagoExitoso(false);
                return;
            }
            if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
                showMessage(FacesMessage.SEVERITY_WARN,
                        "Dia cerrado",
                        "No se pueden eliminar más registros porque ya existe un cuadre de caja chica del día");
                setPagoExitoso(false);
                return;
            }

            // Se valida que la cantidad pagada no sea mayor al restante por pagar de la urbanización 
            List<DetalleLoteUrbanizacion> detalleUrbanizacion = getDetalleLoteUrbanizacionController().buscarDetallesLotesPorLotes(getSelectedLote().getId(), getSelectUrbanizacion().getId());
            if (detalleUrbanizacion.isEmpty()) {
                if (getPagoUrbanizacion() > getSelectUrbanizacion().getCostoPorLote()) {
                    showMessage(FacesMessage.SEVERITY_WARN, "Error", "El pago de urbanización es mayor a la cantidad restante a pagar");
                    setPagoExitoso(false);
                    return;
                }
            } else if (getPagoUrbanizacion() > detalleUrbanizacion.get(0).getSaldoNuevo()) {
                showMessage(FacesMessage.SEVERITY_WARN, "Error", "El pago de urbanización es mayor a la cantidad restante a pagar");
                setPagoExitoso(false);
                return;
            }

            // Se valida si el proyecto del lote cuenta con una abreviación
            String abreviacion = getSelectedLote().getManzana().getPredio().getAbreviatura();
            if (abreviacion == null || abreviacion.isEmpty()) {
                showMessage(FacesMessage.SEVERITY_WARN, "Error", "Debe de definir una abreviación para el proyecto, ya que es requerida para crear el folio");
                setPagoExitoso(false);
                return;
            }

            abreviacion = "UR" + "-" + abreviacion + "-";

            setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
            getNuevoDetalleLoteUrbanizacion().setLote(getSelectedLote());
            getNuevoDetalleLoteUrbanizacion().setCreatedOn(new Date());
            getNuevoDetalleLoteUrbanizacion().setSaldoAnterior(getSelectUrbanizacion().getCostoPorLote());
            getNuevoDetalleLoteUrbanizacion().setSaldoPagado(getPagoUrbanizacion());
            getNuevoDetalleLoteUrbanizacion().setSaldoNuevo(getSelectUrbanizacion().getCostoPorLote() - getPagoUrbanizacion());
            getNuevoDetalleLoteUrbanizacion().setUrbanizacion(getSelectUrbanizacion());

            // Se cargan los abonos para validar el folio
            AbonosView ultimoFolio = getCobranzaController().fillURBANIZACIONAbonosViewByFolioAndProyecto(getSelectedLote().getManzana().getPredio().getId(), abreviacion);

            // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
            int consecutivo = 0;
            if (ultimoFolio != null) {
                String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                // Dividir el folio en partes utilizando el guion como separador
                String[] partes = folior.split("-");
                // Obtener la parte del consecutivo
                String consecutivoParte = partes[5];
                // Convertir el consecutivo a un entero
                consecutivo = Integer.parseInt(consecutivoParte);
            }

            // se formatea la fecha                
            SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
            String fechaFormateada = formatoF.format(new Date());

            // se formatea el consecutivo                                         
            String numeroFormateado = String.format("%06d", consecutivo + 1);
            String folio;
            if (consecutivo == 0) {
                folio = abreviacion + fechaFormateada + "-" + "000001";
                getNuevoDetalleLoteUrbanizacion().setFolio(folio);
            } else {
                folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                getNuevoDetalleLoteUrbanizacion().setFolio(folio);
            }

            boolean success = getDetalleLoteUrbanizacionController().addDetalleLoteUrbanizacion(getNuevoDetalleLoteUrbanizacion(), getLoggedUser());

            if (success) {
                setPagoExitoso(true);
                showMessage(FacesMessage.SEVERITY_INFO, "Pago obras y reparaciones", "El pago de guardo de manera correcta.");
                if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
                    setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
                }

            } else {
                setPagoExitoso(false);
                showMessage(FacesMessage.SEVERITY_INFO, "Pago obras y reparaciones", "El pago no se guardo de manera correcta.");
            }

            // Enviar tiked                        
            // Formato de fecha 
            SimpleDateFormat formato = new SimpleDateFormat("dd-MM-yyyy");
            //fecha de pago
            String fechaPago = formato.format(getNuevoDetalleLoteUrbanizacion().getCreatedOn());

            String HTMLBODY = "<h1>Recibo de pago urbanización " + getLoggedUser().getLocation().getBusinessName() + "</h1>"
                    + "<p>Esta es una notificación automática - Favor de NO responder (reply) a este email</p>"
                    + "<div style='padding: 0.5em; border: solid 1px; display: inline-block;'>"
                    + "<p><b>Folio: </b>" + getNuevoDetalleLoteUrbanizacion().getFolio() + "</p>"
                    + "<p><b>Fecha: </b>" + fechaPago + "</p>"
                    + "<p><b>CLIENTE: </b>" + (getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getFirstName() + " "
                    + ((getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getSecondName() != null && !getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getSecondName().isEmpty())
                    ? getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getSecondName() : "") + " " + getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getLastName()) + "</p>"
                    + "<p><b>PREDIO: </b>" + getNuevoDetalleLoteUrbanizacion().getLote().getManzana().getPredio().getNombreProyecto() + "</p>"
                    + "<p><b>MANZANA: </b>" + getNuevoDetalleLoteUrbanizacion().getLote().getManzana().getNombre() + "</p>"
                    + "<p>"
                    + getNuevoDetalleLoteUrbanizacion().getLote().getManzana().getPredio().getTipoProyecto() + ": "
                    + getNuevoDetalleLoteUrbanizacion().getLote().getFolio() + ""
                    + "</p>"
                    + "<p><b>SALDO ANTERIOR: </b>" + getNuevoDetalleLoteUrbanizacion().getSaldoAnterior() + "</p>"
                    + "<p><b>PAGO: </b>" + getNuevoDetalleLoteUrbanizacion().getSaldoPagado() + "</p>"
                    + "<p><b>SALDO NUEVO: </b>" + getNuevoDetalleLoteUrbanizacion().getSaldoNuevo() + "</p>"
                    + "<p><b>COBRO: </b>" + (getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getFirstName() + " "
                    + ((getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getSecondName() != null)
                    ? getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getSecondName() : "") + " "
                    + ((getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getLastName() != null)
                    ? getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getLastName() : "") + " "
                    + ((getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getMiddleName() != null)
                    ? getNuevoDetalleLoteUrbanizacion().getCreatedBy().getPerson().getMiddleName() : "")) + "</p>"
                    + "<br/>"
                    + "<p><b>" + getLoggedUser().getLocation().getBusinessName() + "</b></p>"
                    + "<p><b>AGRADECE SU PREFERENCIA</b></p>"
                    + "<br/>"
                    + "<p>" + getLoggedUser().getLocation().getCompleteAddress()
                    + " " + getLoggedUser().getLocation().getMunicipality()
                    + " " + getLoggedUser().getLocation().getState()
                    + " " + getLoggedUser().getLocation().getPostalCode()
                    + "</p><br/>"
                    + "<p><b>RFC: </b>" + getLoggedUser().getLocation().getRfc() + "</p>"
                    + "<p><b>TEL: </b>" + getLoggedUser().getLocation().getPhone() + "</p>"
                    + "</div>";

            if (validarCorreo(getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getMail())) {
                showMessage(FacesMessage.SEVERITY_ERROR, "Error", "No se pudo enviar el recibo por correo al cliente verifique el correo del cliente");
                logger.error("No se encontró un correo registrado para cliente");
            } else if (setEmailRecibo(getNuevoDetalleLoteUrbanizacion().getLote().getCliente().getMail(), HTMLBODY)) {
                showMessage(FacesMessage.SEVERITY_INFO, "Recibo enviado por correo", "El recibo se envió correctamente al cliente");
                logger.info("El recibo se envió correctamente al cliente ");
            } else {
                showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                logger.error("Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
            }

        } catch (NumberFormatException e) {
            setPagoExitoso(false);
            logger.error("Error al convertir el consecutivo en número " + e);
            showMessage(FacesMessage.SEVERITY_INFO, "Pago obras y reparaciones", "El pago no se guardo de manera correcta.");
        } catch (Exception e) {
            setPagoExitoso(false);
            logger.error("El pago no se guardo de manera correcta " + e);
            showMessage(FacesMessage.SEVERITY_INFO, "Pago obras y reparaciones", "El pago no se guardo de manera correcta.");
        }
    }

    public void addDetalleLoteEtapa() {
        setEtapaJuridicoSeleccionada(getEtapaJuridicoController().fillEtapaJuridicoById(getIdEtapa()));
        getNuevoDetalleLoteEtapa().setDescripcion(getDescipcionJuridico());
        getNuevoDetalleLoteEtapa().setDeudaTotal(getPagoCuentasJuridico());
        getNuevoDetalleLoteEtapa().setEstapaJuridico(getEtapaJuridicoSeleccionada());
        getNuevoDetalleLoteEtapa().setLote(getSelectedLote());
        getNuevoDetalleLoteEtapa().setEstatusActivo(GenericEnumType.ENABLED);
        try {
            getDetalleLoteEtapaController().addDetalleLoteEtapa(getNuevoDetalleLoteEtapa(), getLoggedUser());
            limpiarLotesJuridico();
            showMessage(FacesMessage.SEVERITY_INFO,
                    "Detalle lote estapa",
                    "Se guardo de manera correcta");
        } catch (Exception e) {
            showMessage(FacesMessage.SEVERITY_INFO,
                    "Detalle lote estapa",
                    "No se guardo de manera correcta.");
        }
    }

    private void limpiarLotesJuridico() {
        for (int i = 0; i <= getLotes().size() - 1; i++) {
            long numero = getDetalleLoteEtapaController().contarLoteEtapabyLote(getLotes().get(i), getLoggedUser().getLocation());
            if (numero != 0) {
                getLotes().remove(i);
                i--;
            }
        }
    }

    public void actionNull() {

    }

    public void actualizarTotal() {
        setComboCobranza(false);
        if (selectAbono.getPagoEstatus().equals(GenericEnumType.INCOMPLETE)) {
            setPagoDado(getSelectAbono().getDiferenciaPago());
            setTotalPagar(getSelectAbono().getDiferenciaPago());
        } else {
            setPagoDado(getSelectAbono().getPago());
            setTotalPagar(getSelectAbono().getPago());
        }
        setComboMandados(false);

        setMandadoDado(getSelectAbono().getLote().getManzana().getPredio().getMandado());
        setCobranzaDada(getSelectAbono().getLote().getManzana().getPredio().getCobranzaAtraso());
    }

    public void updateLotes() {
        if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Error",
                    "No se puede hacer ninguna acción si existe un corte del día");
            return;
        }
        setLoteController(new LoteController());
        setCobranzaController(new CobranzaController());
        setLotes(getCobranzaController().fillLoteByFolioOrCliente(getFolioLote(), getSelectUser()));
        limpiarLotesJuridico();
        List<String> listaIdsLotes = new ArrayList<>();
        for (int i = 0; i <= getLotes().size() - 1; i++) {
            listaIdsLotes.add(getLotes().get(i).getManzana().getPredio().getId());
            Double totalPagado = 0.0;
            // se realiza la actualización del total pagado solo a los lotes que estén vendidos y el total pagos sea diferente del monto pagado
            if (getLotes().get(i).getTotalPago() == null || getLotes().get(i).getMontoPagado() == null) {
                logger.error("Cantidad pagada o monto pagado es null");
            } else if (getLotes().get(i).getEstatusLote().equals(EstatusLote.VENDIDO) && !Objects.equals(getLotes().get(i).getTotalPago(), getLotes().get(i).getMontoPagado())) {
                // Se obtienen el total de todos los pagos del tipo ABONO que estén pagados
                setAbonoLoteController(new AbonoLoteController());
                List<AbonoLote> valAbLPago = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(getLotes().get(i), TipoAbono.ABONO, GenericEnumType.ENABLED);
                for (AbonoLote valAbLP : valAbLPago) {
                    totalPagado = totalPagado + valAbLP.getCantidadPagada();
                }
                // Se obtienen el total de todos los pagos del tipo ABONO que estén incompletos
                List<AbonoLote> valAbLPagoIn = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(getLotes().get(i), TipoAbono.ABONO, GenericEnumType.INCOMPLETE);
                for (AbonoLote valAbLPin : valAbLPagoIn) {
                    totalPagado = totalPagado + valAbLPin.getCantidadPagada();
                }
                // Se actualiza el total pagado de cada lote                
                getLotes().get(i).setMontoPagado(totalPagado);
                getLoteController().updateMontoPagado(getLotes().get(i), getLoggedUser());
            }

        }

        Set<String> conjunto = new HashSet<>(listaIdsLotes);
        List<String> listaUnicaIdsLotes = new ArrayList<>(conjunto);
        Map<String, Boolean> validacionLotes = new HashMap<>();
        for (int i = 0; i <= listaUnicaIdsLotes.size() - 1; i++) {
            boolean comprobar = getUrbanizacionController().checkIfUrbanizacionExistsByPredio(listaUnicaIdsLotes.get(i));
            validacionLotes.put(listaUnicaIdsLotes.get(i), comprobar);
        }
        for (String key : validacionLotes.keySet()) {
            Boolean value = validacionLotes.get(key);
            for (int i = 0; i <= getLotes().size() - 1; i++) {
                if (getLotes().get(i).getManzana().getPredio().getId().equals(key)) {
                    getLotes().get(i).setCargarUrbanizacion(value);
                }
            }
        }
             
    }

    public void fillAbonoLoteByLote() {
        setPagoMultiple(null);
        setCobranzaController(new CobranzaController());
        setAbonos(getCobranzaController().fillAbonoLoteByLote(getSelectedLote()));
        setPagosMultiples(getCobranzaController().fillHitorialAbonoMultipleByLote(getSelectedLote().getId(), getLoggedUser().getLocation().getId()));

        // se valida el ultimo abono pagado 
        String idUltimoAbonoLote = null;
        for (AbonoLote abono : getAbonos()) {
            if (abono.getPagoEstatus().equals(GenericEnumType.ENABLED)) {
                idUltimoAbonoLote = abono.getId();
            }
        }
        setUltimoAbonoPagado(idUltimoAbonoLote);

        // se valida el ultimo abono multiple pagado 
        String idUltimoAbonoMultiple = null;
        for (HitorialAbonoMultiple abonoM : getPagosMultiples()) {
            idUltimoAbonoMultiple = abonoM.getId();
        }
        setUltimoAbonoMultiplePagado(idUltimoAbonoMultiple);

        try {
            for (int i = 0; i <= getAbonos().size() - 1; i++) {
                Integer suma = i + 1;
                getAbonos().get(i).setNumeroAbono(String.valueOf(suma));
            }
        } catch (Exception e) {
            System.out.println("error: " + e);
        }

    }

    public void fillAbonoLoteByLoteAndObrasReparaciones() {
        setPagoMultiple(null);
        setCobranzaController(new CobranzaController());
        setUrbanizacionController(new UrbanizacionController());
        // Lista de abonos lote
        setAbonos(getCobranzaController().fillAbonoLoteByLoteAndTipo(getSelectedLote(), TipoAbono.ABONO));
        // Lista de abonos urbanización
        setListDetalleLoteUrbanizacion(getUrbanizacionController().fillAllDetalleLoteUrbanizacionByLote(getSelectedLote()));

        try {
            // Corrección del saldo nuevo y el saldo esperado y asignación de consecutivo
            Double costo = getSelectedLote().getCosto();
            List<AbonoLoteView> abonosAndSub = getCobranzaController().fillAbonoLoteAndSubAbonoByLoteAndTipo(getSelectedLote(), TipoAbono.ABONO);
            // Corrección del saldo nuevo y el saldo anterior con base en la cantidad pagada 
            int i = 0;
            for (AbonoLoteView abono : abonosAndSub) {
                if (abono.getTipoAbono().equals(TipoAbono.ABONO)) {
                    i++;
                    abono.setSaldoAnterior(costo);
                    abono.setNumeroAbono(String.valueOf(i));
                    // Validación de la cantidad por valores nulos 
                    try {
                        costo = costo - abono.getCantidadPagada();
                    } catch (Exception e) {
                        costo = costo - 0;
                    }
                    abono.setSaldoNuevo(costo);
                } else {
                    abono.setNumeroAbono(String.valueOf(i));
                }
            }
            setListAbonoLoteView(abonosAndSub);
        } catch (Exception e) {
            logger.error("fillAbonoLoteByLoteAndObrasReparaciones " + e);
        }

    }

    public void fillAbonoLoteByLoteJuridico() {
        setCobranzaController(new CobranzaController());
        setAbonos(getCobranzaController().fillAbonoLoteByLote(getSelectedLote()));
        setTotalJuridico();
        setPagoCuentasJuridico(getTotalJuridico());
    }

    public void consultarAbonosRestantes() {
        setCobranzaController(new CobranzaController());
        // extraigo los abonos extra que no este pagados
        List<AbonoLote> abonosRestantesExtra = getCobranzaController().fillAbonoLoteExtraByLoteAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, getSelectedLote().getMensualidad());
        // se ectraen los abonos lote que no estenten pagados
        List<AbonoLote> abonosRestantes;
        // verifico si existen pagos extra
        if (abonosRestantesExtra.isEmpty()) {
            abonosRestantes = getCobranzaController().fillAbonoLoteByLoteNoExtraAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, 0.0);
        } else {
            abonosRestantes = getCobranzaController().fillAbonoLoteByLoteNoExtraAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, abonosRestantesExtra.get(0).getPago());
        }
        Double total = 0.0;
        if (!abonosRestantes.isEmpty()) {
            for (AbonoLote abonosR : abonosRestantes) {
                total = total + abonosR.getPago();
            }
        }
        setTotalAbonosRestantes(total);
    }

    public void consultarComentariosLote() {
        setCobranzaController(new CobranzaController());
        // extraigo los abonos extra que no este pagados
        setComentarioLote(getCobranzaController().fillComentariosLote(getSelectedLote()));
    }

    public void generarConvenio() {
        logger.info("Generando convenio");
        try {
            setCobranzaController(new CobranzaController());
            setAbonoLoteController(new AbonoLoteController());
            // extraigo los abonos extra que no este pagados
            List<AbonoLote> abonosRestantesExtra = getCobranzaController().fillAbonoLoteExtraByLoteAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, getSelectedLote().getMensualidad());
            // se ectraen los abonos lote que no estenten pagados
            List<AbonoLote> abonosRestantes;
            // verifico si existen pagos extra
            if (!abonosRestantesExtra.isEmpty()) {
                abonosRestantes = getCobranzaController().fillAbonoLoteByLoteNoExtraAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, abonosRestantesExtra.get(0).getPago());
            } else {
                abonosRestantes = getCobranzaController().fillAbonoLoteByLoteNoExtraAndPagoEstatusAndMensualidad(getSelectedLote(), GenericEnumType.DISABLED, -1.0);
            }
            // se valida que existan abonos lote
            if (!abonosRestantes.isEmpty()) {
                Double total = 0.0;
                for (AbonoLote abonosR : abonosRestantes) {
                    total = total + abonosR.getPago();
                }
                //Definición de la fecha de inicio y numero de pagos
                Calendar fechaInicial = Calendar.getInstance();
                fechaInicial.setTime(abonosRestantes.get(0).getFechaAPagar());
                // Se genera la lista de fechas
                List<Calendar> fechasDePago = generarFechasDePago(fechaInicial, getNewPagoPorConvenio(), total, getSelectedLote().getPeriodoPago() == PeriodoPago.MENSUAL);
                // SE ELIMINAN LOS ABONOS RESTANTES ANTES DE INSERTAR LOS DE REAJUSTADOS
                logger.info("Eliminado abono no pagados del lote ");
                for (AbonoLote abonosR : abonosRestantes) {
                    try {
                        getAbonoLoteController().deleteAbonoLote(abonosR);
                    } catch (Exception e) {
                        logger.error("Ocurrió un error al eliminar el abono lote: " + abonosR.getId());
                    }
                }
                // CREACIÓN DE PAGOS POR FECHA
                setActualizarPago(total);
                recorrerFechas(fechasDePago, getSelectedLote(), getNewPagoPorConvenio());
                showMessage(FacesMessage.SEVERITY_INFO, "Restructuración completada", "Los abonos se estructuraron correctamente a abonos de: $" + getNewPagoPorConvenio());
            } else {
                logger.error("No se encontraron abonos restantes");
                showMessage(FacesMessage.SEVERITY_WARN, "Error", "No se puede generar un convenio para un lote sin abonos restantes");
            }
        } catch (Exception e) {
            logger.error("generarConvenio()");
            showMessage(FacesMessage.SEVERITY_WARN, "Error", "Error al generar el convenio");
        }
    }

    private void recorrerFechas(List<Calendar> fechas, Lote lote, Double pagoPorMes) {
        logger.info("Insertando abonos por fecha");
        // Usamos Collections.sort() para ordenar la lista de fechas
        Collections.sort(fechas, new Comparator<Calendar>() {
            @Override
            public int compare(Calendar fecha1, Calendar fecha2) {
                // Comparamos las fechas usando el método compareTo()
                return fecha1.compareTo(fecha2);
            }
        });

        // recorre las fechas ordenadas
        int contador = 0;
        for (Calendar fecha : fechas) {
            contador++;
            try {
                setAbonoLoteController(new AbonoLoteController());
                AbonoLote abono = new AbonoLote();
                abono.setLote(lote);
                abono.setCliente(lote.getCliente());
                abono.setTipoAbono(TipoAbono.ABONO);
                abono.setEstatusActivo(GenericEnumType.ENABLED);
                abono.setPagoEstatus(GenericEnumType.DISABLED);
                abono.setConvenio(1);
                abono.setFechaAPagar(fecha.getTime());
                abono.setSaldoAnterior(getActualizarPago());
                // se valida si es el ultimo abono para colocar el rediduo de reajuste
                if (contador == fechas.size() && getResiduoReajuste() > 0) {
                    abono.setPago(getResiduoReajuste());
                    setActualizarPago(getActualizarPago() - getResiduoReajuste());
                    abono.setSaldoNuevo(getActualizarPago());
                } else {
                    abono.setPago(pagoPorMes);
                    setActualizarPago(getActualizarPago() - pagoPorMes);
                    abono.setSaldoNuevo(getActualizarPago());
                }
                abono.setSaldoNuevo(getActualizarPago());
                abono.setCreatedBy(getLoggedUser());
                abono.setCreatedOn(new Date());
                getAbonoLoteController().addAbonoLote(abono, getLoggedUser());
            } catch (Exception e) {
                logger.error("Error al capturar el abono del dia: (" + fecha + ") " + e);
                showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al capturar el abono del dia (" + fecha + ")");
            }
        }
    }

    public List<Calendar> generarFechasDePago(Calendar fechaInicial, Double montoconvenio, Double totalAbonos, Boolean mensual) {
        logger.info("Generación fechas");
        // Lista de fechas vacia
        List<Calendar> fechasDePago = new ArrayList<>();
        // Se introduse la fecha de inicio
        fechasDePago.add(fechaInicial);
        Calendar fechaActual = (Calendar) fechaInicial.clone();
        // Captura el dia de una fecha en caso de que no se encuntre en le mes siguinte 
        boolean detenerFecha = false;
        Calendar fechaDetenida = Calendar.getInstance();

        Integer numeroPagos = (int) Math.floor(totalAbonos / montoconvenio);
        Double residuo = totalAbonos % montoconvenio;
        setResiduoReajuste(residuo);

        // se agrega una fecha mas para el residuo
        if (residuo > 0) {
            numeroPagos++;
        }
        // se generan la lista de fechas        
        if (mensual) {
            for (int i = 1; i < numeroPagos; i++) {
                Calendar fechaSiguiente = (Calendar) fechaActual.clone();
                fechaSiguiente.add(Calendar.MONTH, 1);
                if (detenerFecha == false) {
                    if (fechaActual.get(Calendar.DAY_OF_MONTH) > fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                        detenerFecha = true;
                        fechaDetenida = (Calendar) fechaActual.clone();
                        fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
                    }
                } else {
                    if (fechaSiguiente.get(Calendar.DAY_OF_MONTH) <= fechaDetenida.get(Calendar.DAY_OF_MONTH)) {
                        detenerFecha = false;
                        fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaDetenida.get(Calendar.DAY_OF_MONTH));
                    } else {
                        fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
                    }
                }
                fechasDePago.add(fechaSiguiente);
                fechaActual = fechaSiguiente;
            }
        } else {
            for (int i = 0; i < numeroPagos;) {
                Calendar fechaSiguiente = (Calendar) fechaActual.clone();
                fechaSiguiente.set(Calendar.DAY_OF_MONTH, 15);
                fechasDePago.add(fechaSiguiente);
                i++;

                if (i < numeroPagos) {
                    fechaSiguiente = (Calendar) fechaActual.clone();
                    fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
                    fechasDePago.add(fechaSiguiente);
                    i++;
                }
                fechaActual.add(Calendar.MONTH, 1);
            }
        }
        return fechasDePago;
    }

    public void fillUrbanizacionByProyect() {
        setListaUrbanizacion(getUrbanizacionController().fillAllUrbanizacionesByPredio(getSelectedLote().getManzana().getPredio()));
        for (int i = 0; i <= getListaUrbanizacion().size() - 1; i++) {
            List<DetalleLoteUrbanizacion> detalleUrbanizacion = getDetalleLoteUrbanizacionController().buscarDetallesLotesPorLotes(getSelectedLote().getId(), getListaUrbanizacion().get(i).getId());
            getListaUrbanizacion().get(i).setCostoInicial(getListaUrbanizacion().get(i).getCostoPorLote());
            if (detalleUrbanizacion.size() != 0) {
                getListaUrbanizacion().get(i).setCostoPorLote(detalleUrbanizacion.get(0).getSaldoNuevo());
            }
        }

    }

    private void setTotalJuridico() {
        for (int i = 0; i <= getAbonos().size() - 1; i++) {
            if (getAbonos().get(i).getPagoEstatus().equals(GenericEnumType.ENABLED)) {

            } else {
                setTotalJuridico(getTotalJuridico() + getAbonos().get(i).getPago());
            }
        }
    }

    public void payAbono() {
        logger.info("init payAbono");
        setPagoExitoso(false);

        if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Error",
                    "No se puede hacer ninguna acción si existe un corte del día");
            return;
        }
        if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Dia cerrado",
                    "No se pueden eliminar más registros porque ya existe un cuadre de caja chica del día");
            return;
        }

        setCobranzaController(new CobranzaController());
        if (getCobranzaController().existsIncompleteBefore(getSelectAbono())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Abonos  incompletos",
                    "No se puede realizar este abono por que existen abonos incompletos en fechas anteriores");
            return;
        }

        setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        try {

            // Se valida si el proyecto del lote cuenta con una abreviación
            String abreviacion = getSelectAbono().getLote().getManzana().getPredio().getAbreviatura();
            if (abreviacion == null || abreviacion.isEmpty()) {
                showMessage(FacesMessage.SEVERITY_WARN, "Error",
                        "Debe de definir una abreviación para el proyecto, ya que es requerida para crear el folio");
                return;
            }

            abreviacion = abreviacion + "-";

            // Redondeo el pago esperado a 2 decimales para verificar que el pago dado no sea mayor al esperado
            BigDecimal bd = new BigDecimal(getSelectAbono().getPago());
            bd = bd.setScale(2, RoundingMode.HALF_UP);
            double pagoRedondeado = bd.doubleValue();
            //double pagoSinCoMA = getPagoDado()-(getCobranzaDada()!=null?getCobranzaDada():0.0)-(getMandadoDado()!=null?getMandadoDado():0.0);

            if (getPagoDado() < pagoRedondeado) {
                setCobranzaController(new CobranzaController());

                getSelectAbono().setPagoEstatus(GenericEnumType.INCOMPLETE);

                //Verificar si ahi una diferencia de pago en el ultimo abono actualizado                 
                //AbonoLote ultimoBonoActulizado = getCobranzaController().fillLastUpdateAbonoLoteByLote(getSelectAbono().getLote());          
                getSelectAbono().setDiferenciaPago(pagoRedondeado - getPagoDado());

                getSelectAbono().setCantidadPagada(getPagoDado());
                getSelectAbono().setDescripcion(getDescripcionPago());
                setUrbanizacionController(new UrbanizacionController());

                setTotalDado(getPagoDado());

                AbonoLoteDetalle abonoLoteDetalle = new AbonoLoteDetalle();
                if (getComboCobranza() == true) {
                    getSelectAbono().setCobranzaPagar(getSelectedLote().getManzana().getPredio().getCobranzaAtraso());
                    abonoLoteDetalle.setCobranza(getCobranzaDada());
                } else {
                    setCobranzaDada(0D);
                    getSelectAbono().setCobranzaPagada(0D);
                    getSelectAbono().setCobranzaPagar(0D);
                    abonoLoteDetalle.setCobranza(0D);
                }
                if (getComboMandados() == true) {
                    getSelectAbono().setMandadoPagar(getSelectedLote().getManzana().getPredio().getMandado());
                    abonoLoteDetalle.setMandado(getMandadoDado());

                } else {
                    getSelectAbono().setMandadoPagar(0D);
                    getSelectAbono().setMandadoPagado(0D);
                    abonoLoteDetalle.setMandado(0D);
                    setMandadoDado(0D);
                }
                getCobranzaController().addAbonoLote(getSelectAbono(), getLoggedUser(), false);
                Lote tempLote = getSelectAbono().getLote();

                tempLote.setMontoPagado(tempLote.getMontoPagado() + getSelectAbono().getCantidadPagada());

                getLoteController().updateMontoPagado(tempLote, getLoggedUser());

                abonoLoteDetalle.setPago(getPagoDado());
                abonoLoteDetalle.setAbonoLote(selectAbono);

                // Se cargan los abonos para validar el folio
                AbonosView ultimoFolio = getCobranzaController().fillAbonosViewByFolioAndProyecto(getSelectAbono().getLote().getManzana().getPredio().getId(), abreviacion);

                // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
                int consecutivo = 0;
                if (ultimoFolio != null) {
                    String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                    // Dividir el folio en partes utilizando el guion como separador
                    String[] partes = folior.split("-");
                    // Obtener la parte del consecutivo
                    String consecutivoParte = partes[4];
                    // Convertir el consecutivo a un entero
                    consecutivo = Integer.parseInt(consecutivoParte);
                }

                // se formatea la fecha                
                SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
                String fechaFormateada = formatoF.format(new Date());

                // se formatea el consecutivo                                         
                String numeroFormateado = String.format("%06d", consecutivo + 1);
                String folio;
                if (consecutivo == 0) {
                    folio = abreviacion + fechaFormateada + "-" + "000001";
                    abonoLoteDetalle.setFolio(folio);
                } else {
                    folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                    abonoLoteDetalle.setFolio(folio);
                }

                getCobranzaController().addAbonoLoteDetalle(abonoLoteDetalle, getLoggedUser());

                // Se le coloca el folio del sub abono al abono seleccionado para mostrarlo en le tiked
                getSelectAbono().setFolio(folio);
                getSelectAbono().setLastUpdatedOn(new Date());

                DecimalFormat formato = new DecimalFormat("#.##");
                String resultado = formato.format(getTotalPagar());
                setTotalPagar(Double.valueOf(resultado));
                setPagoExitoso(true);
                if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
                    setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
                }

                showMessage(FacesMessage.SEVERITY_INFO, "Pagado", "Abono pagado correctamente");

                // Enviar tiked                        
                // Formato de fecha 
                SimpleDateFormat formato2 = new SimpleDateFormat("dd-MM-yyyy");
                //fecha de pago
                String fechaPago = formato2.format(new Date());

                String HTMLBODY = "<h1>Recibo de pago " + getLoggedUser().getLocation().getBusinessName() + "</h1>"
                        + "<p>Esta es una notificación automática - Favor de NO responder (reply) a este email</p>"
                        + "<div style='padding: 0.5em; border: solid 1px; display: inline-block;'>"
                        + "<p><b>No.Abono: </b>" + getSelectAbono().getNumeroAbono() + "</p>"
                        + "<p><b>Folio: </b>" + getSelectAbono().getFolio() + "</p>"
                        + "<p><b>Fecha: </b>" + fechaPago + "</p>"
                        + "<p><b>CLIENTE: </b>" + (getSelectAbono().getCliente().getFirstName() + " "
                        + ((getSelectAbono().getCliente().getSecondName() != null && !getSelectAbono().getCliente().getSecondName().isEmpty())
                        ? getSelectAbono().getCliente().getSecondName() : "") + " " + getSelectAbono().getCliente().getLastName()) + "</p>"
                        + "<p><b>PREDIO: </b>" + getSelectAbono().getLote().getManzana().getPredio().getNombreProyecto() + "</p>"
                        + "<p><b>MANZANA: </b>" + getSelectAbono().getLote().getManzana().getNombre() + "</p>"
                        + "<p><b>LOTE: </b>" + getSelectAbono().getLote().getFolio() + "</p>"
                        + "<p><b>PAGO: </b>" + getPagoDado() + "</p>"
                        + "<p><b>GASTO POR COBRANZA: </b>" + getCobranzaDada() + "</p>"
                        + "<p><b>MANDADO: </b>" + getMandadoDado() + "</p>"
                        + "<p><b>TOTAL: </b>" + getTotalPagar() + "</p>"
                        + "<p><b>COMENTARIOS: </b>" + getDescripcionPago() + "</p>"
                        + "<p><b>COBRO: </b>" + (getSelectAbono().getLastUpdatedBy().getPerson().getFirstName() + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getLastName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getLastName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() : "")) + "</p>"
                        + "<br/>"
                        + "<p><b>" + getLoggedUser().getLocation().getBusinessName() + "</b></p>"
                        + "<p><b>AGRADECE SU PREFERENCIA</b></p>"
                        + "<br/>"
                        + "<p>" + getLoggedUser().getLocation().getCompleteAddress()
                        + " " + getLoggedUser().getLocation().getMunicipality()
                        + " " + getLoggedUser().getLocation().getState()
                        + " " + getLoggedUser().getLocation().getPostalCode()
                        + "</p><br/>"
                        + "<p><b>RFC: </b>" + getLoggedUser().getLocation().getRfc() + "</p>"
                        + "<p><b>TEL: </b>" + getLoggedUser().getLocation().getPhone() + "</p>"
                        + "</div>";

                if (validarCorreo(getSelectAbono().getCliente().getMail())) {
                    showMessage(FacesMessage.SEVERITY_ERROR, "Error", "No se pudo enviar el recibo por correo al cliente verifique el correo del cliente");
                    logger.error("No se encontró un correo registrado para cliente");
                } else if (setEmailRecibo(getSelectAbono().getCliente().getMail(), HTMLBODY)) {
                    showMessage(FacesMessage.SEVERITY_INFO, "Recibo enviado por correo", "El recibo se envió correctamente al cliente");
                    logger.info("El recibo se envió correctamente al cliente ");
                } else {
                    showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                    logger.error("Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                }

            } else if (getPagoDado() == pagoRedondeado) {
                setCobranzaController(new CobranzaController());
                getSelectAbono().setPagoEstatus(GenericEnumType.ENABLED);

                //Verificar si ahi una diferencia de pago en el ultimo abono actualizado                 
                //AbonoLote ultimoBonoActulizado = getCobranzaController().fillLastUpdateAbonoLoteByLote(getSelectAbono().getLote());          
                getSelectAbono().setDiferenciaPago(pagoRedondeado - getPagoDado());

                getSelectAbono().setCantidadPagada(getPagoDado());
                getSelectAbono().setDescripcion(getDescripcionPago());
                setUrbanizacionController(new UrbanizacionController());

                setTotalDado(getPagoDado());
                getSelectAbono().setLastUpdatedOn(new Date());
                if (getComboCobranza() == true) {
                    getSelectAbono().setCobranzaPagar(getSelectedLote().getManzana().getPredio().getCobranzaAtraso());
                    getSelectAbono().setCobranzaPagada(getCobranzaDada());
                } else {
                    setCobranzaDada(0D);
                    getSelectAbono().setCobranzaPagada(0D);
                    getSelectAbono().setCobranzaPagar(0D);
                }
                if (getComboMandados() == true) {
                    getSelectAbono().setMandadoPagar(getSelectedLote().getManzana().getPredio().getMandado());
                    getSelectAbono().setMandadoPagado(getMandadoDado());
                } else {
                    getSelectAbono().setMandadoPagar(0D);
                    getSelectAbono().setMandadoPagado(0D);
                    setMandadoDado(0D);
                }

                // Se cargan los abonos para validar el folio
                AbonosView ultimoFolio = getCobranzaController().fillAbonosViewByFolioAndProyecto(getSelectAbono().getLote().getManzana().getPredio().getId(), abreviacion);

                // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
                int consecutivo = 0;
                if (ultimoFolio != null) {
                    String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                    // Dividir el folio en partes utilizando el guion como separador
                    String[] partes = folior.split("-");
                    // Obtener la parte del consecutivo
                    String consecutivoParte = partes[4];
                    // Convertir el consecutivo a un entero
                    consecutivo = Integer.parseInt(consecutivoParte);
                }

                // se formatea la fecha                
                SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
                String fechaFormateada = formatoF.format(new Date());

                // se formatea el consecutivo                                         
                String numeroFormateado = String.format("%06d", consecutivo + 1);
                String folio;
                if (consecutivo == 0) {
                    folio = abreviacion + fechaFormateada + "-" + "000001";
                    getSelectAbono().setFolio(folio);
                } else {
                    folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                    getSelectAbono().setFolio(folio);
                }

                getCobranzaController().addAbonoLote(getSelectAbono(), getLoggedUser(), false);

                // Se actualiza el lote
                Lote tempLote = getSelectAbono().getLote();
                tempLote.setMontoPagado(tempLote.getMontoPagado() + getSelectAbono().getCantidadPagada());
                // Se valida si se está dando el último abono en caso de serlo se cambia el lote ha liquidado
                setAbonoLoteController(new AbonoLoteController());
                List<AbonoLote> valAbLTotal = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbono(getSelectAbono().getLote(), TipoAbono.ABONO);
                List<AbonoLote> valAbLPagodos = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(getSelectAbono().getLote(), TipoAbono.ABONO, GenericEnumType.ENABLED);
                if (valAbLPagodos.size() == valAbLTotal.size()) {
                    tempLote.setEstatusLote(EstatusLote.LIQUIDADO);
                    // Se actualiza la lista de lotes
                    updateLotes();
                }
                getLoteController().updateMontoPagado(tempLote, getLoggedUser());

                DecimalFormat formato = new DecimalFormat("#.##");
                String resultado = formato.format(getTotalPagar());
                setTotalPagar(Double.valueOf(resultado));
                setPagoExitoso(true);
                if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
                    setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
                }
                
                // se actualiza el listado de abonos
                fillAbonoLoteByLote();

                showMessage(FacesMessage.SEVERITY_INFO, "Pagado", "Abono pagado correctamente");

                // Enviar tiked                        
                // Formato de fecha 
                SimpleDateFormat formato2 = new SimpleDateFormat("dd-MM-yyyy");
                //fecha de pago
                String fechaPago = formato2.format(getSelectAbono().getLastUpdatedOn());

                String HTMLBODY = "<h1>Recibo de pago " + getLoggedUser().getLocation().getBusinessName() + "</h1>"
                        + "<p>Esta es una notificación automática - Favor de NO responder (reply) a este email</p>"
                        + "<div style='padding: 0.5em; border: solid 1px; display: inline-block;'>"
                        + "<p><b>No.Abono: </b>" + getSelectAbono().getNumeroAbono() + "</p>"
                        + "<p><b>Folio: </b>" + getSelectAbono().getFolio() + "</p>"
                        + "<p><b>Fecha: </b>" + fechaPago + "</p>"
                        + "<p><b>CLIENTE: </b>" + (getSelectAbono().getCliente().getFirstName() + " "
                        + ((getSelectAbono().getCliente().getSecondName() != null && !getSelectAbono().getCliente().getSecondName().isEmpty())
                        ? getSelectAbono().getCliente().getSecondName() : "") + " " + getSelectAbono().getCliente().getLastName()) + "</p>"
                        + "<p><b>PREDIO: </b>" + getSelectAbono().getLote().getManzana().getPredio().getNombreProyecto() + "</p>"
                        + "<p><b>MANZANA: </b>" + getSelectAbono().getLote().getManzana().getNombre() + "</p>"
                        + "<p><b>LOTE: </b>" + getSelectAbono().getLote().getFolio() + "</p>"
                        + "<p><b>PAGO: </b>" + getPagoDado() + "</p>"
                        + "<p><b>GASTO POR COBRANZA: </b>" + getCobranzaDada() + "</p>"
                        + "<p><b>MANDADO: </b>" + getMandadoDado() + "</p>"
                        + "<p><b>TOTAL: </b>" + getTotalPagar() + "</p>"
                        + "<p><b>COMENTARIOS: </b>" + getDescripcionPago() + "</p>"
                        + "<p><b>COBRO: </b>" + (getSelectAbono().getLastUpdatedBy().getPerson().getFirstName() + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getLastName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getLastName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() : "")) + "</p>"
                        + "<br/>"
                        + "<p><b>" + getLoggedUser().getLocation().getBusinessName() + "</b></p>"
                        + "<p><b>AGRADECE SU PREFERENCIA</b></p>"
                        + "<br/>"
                        + "<p>" + getLoggedUser().getLocation().getCompleteAddress()
                        + " " + getLoggedUser().getLocation().getMunicipality()
                        + " " + getLoggedUser().getLocation().getState()
                        + " " + getLoggedUser().getLocation().getPostalCode()
                        + "</p><br/>"
                        + "<p><b>RFC: </b>" + getLoggedUser().getLocation().getRfc() + "</p>"
                        + "<p><b>TEL: </b>" + getLoggedUser().getLocation().getPhone() + "</p>"
                        + "</div>";

                if (validarCorreo(getSelectAbono().getCliente().getMail())) {
                    showMessage(FacesMessage.SEVERITY_ERROR, "Error", "No se pudo enviar el recibo por correo al cliente verifique el correo del cliente");
                    logger.error("No se encontró un correo registrado para cliente");
                } else if (setEmailRecibo(getSelectAbono().getCliente().getMail(), HTMLBODY)) {
                    showMessage(FacesMessage.SEVERITY_INFO, "Recibo enviado por correo", "El recibo se envió correctamente al cliente");
                    logger.info("El recibo se envió correctamente al cliente ");
                } else {
                    showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                    logger.error("Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                }

            } else {
                setPagoExitoso(false);
                showMessage(FacesMessage.SEVERITY_ERROR, "Error", "El pago dado no puede ser mayor al pago predefinido");
            }

        } catch (NumberFormatException e) {
            setPagoExitoso(false);
            logger.error("PayAbono Error al convertir el consecutivo en número" + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al pagar");
        } catch (Exception e) {
            setPagoExitoso(false);
            logger.error("payAbono: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al pagar");
        }

    }

    private boolean setEmailRecibo(String mail, String HTMLBODY) {
        logger.info("setBienvenidaEmail");
        String ACCESS_KEY = getBundlePropertyFile().getString("aws.access.key");
        String SECRET_KEY = getBundlePropertyFile().getString("aws.secret.access.key");

        // Remitente y destinatario
        String sender = "soporte@crovonline.com";
        String recipient = mail;

        // Configurar credenciales de AWS
        BasicAWSCredentials awsCredentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
        AmazonSimpleEmailService client = AmazonSimpleEmailServiceClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .withRegion(getBundlePropertyFile().getString("aws.region")) // Cambia la región según tus necesidades
                .build();

        String SUBJECT = "Recibo de pago CROV Inmobiliaria";

        String TEXTBODY = "Este mensaje ha sido enviado automáticamente desde CROV Inmobiliaria.\n\n";

        // Crear el mensaje
        SendEmailRequest request = new SendEmailRequest()
                .withDestination(new Destination().withToAddresses(recipient))
                .withMessage(new Message()
                        .withBody(new Body()
                                .withHtml(new Content()
                                        .withCharset("UTF-8").withData(HTMLBODY))
                                .withText(new Content()
                                        .withCharset("UTF-8").withData(TEXTBODY)))
                        .withSubject(new Content()
                                .withCharset("UTF-8").withData(SUBJECT)))
                .withSource(sender);

        // Enviar el correo
        try {
            SendEmailResult result = client.sendEmail(request);
            logger.info("El correo se ha enviado correctamente. ID del mensaje: " + result.getMessageId());
            return true;
        } catch (AmazonServiceException ex) {
            logger.error("Error al enviar el correo: " + ex.getMessage());
            return false;
        }
    }

    public void payAbonoIncomplete() {
        logger.info("init payAbono");

        setPagoExitoso(false);
        if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Error",
                    "No se puede hacer ninguna acción si existe un corte del día");
            return;
        }
        if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Dia cerrado",
                    "No se pueden eliminar más registros porque ya existe un cuadre de caja chica del día");
            return;
        }
        setCobranzaController(new CobranzaController());

        if (getCobranzaController().existsIncompleteBefore(getSelectAbono())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Abonos  incompletos",
                    "No se puede realizar este abono por que existen abonos incompletos en fechas anteriores");
            return;
        }

        setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        try {

            // Se valida si el proyecto del lote cuenta con una abreviación
            String abreviacion = getSelectAbono().getLote().getManzana().getPredio().getAbreviatura();
            if (abreviacion == null || abreviacion.isEmpty()) {
                showMessage(FacesMessage.SEVERITY_WARN, "Error",
                        "Debe de definir una abreviación para el proyecto, ya que es requerida para crear el folio");
                return;
            }
            abreviacion = abreviacion + "-";

            // Redondeo el pago esperado a 2 decimales para verificar que el pago dado no sea mayor al esperado
            BigDecimal bd = new BigDecimal(getSelectAbono().getDiferenciaPago());
            bd = bd.setScale(2, RoundingMode.HALF_UP);
            double pagoRedondeado = bd.doubleValue();
            //double pagoSinCoMA = getPagoDado()-(getCobranzaDada()!=null?getCobranzaDada():0.0)-(getMandadoDado()!=null?getMandadoDado():0.0);

            if (getPagoDado() <= pagoRedondeado) {
                setCobranzaController(new CobranzaController());

                //Verificar si ahi una diferencia de pago en el ultimo abono actualizado                 
                //AbonoLote ultimoBonoActulizado = getCobranzaController().fillLastUpdateAbonoLoteByLote(getSelectAbono().getLote());          
                getSelectAbono().setDiferenciaPago(pagoRedondeado - getPagoDado());

                // se valida si el abono se pago completamente 
                if (getSelectAbono().getDiferenciaPago() == 0) {
                    // Se cargan los abonos para validar el folio
                    AbonosView ultimoFolio = getCobranzaController().fillAbonosViewByFolioAndProyecto(getSelectAbono().getLote().getManzana().getPredio().getId(), abreviacion);

                    // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
                    int consecutivo = 0;
                    if (ultimoFolio != null) {
                        String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                        // Dividir el folio en partes utilizando el guion como separador
                        String[] partes = folior.split("-");
                        // Obtener la parte del consecutivo
                        String consecutivoParte = partes[4];
                        // Convertir el consecutivo a un entero
                        consecutivo = Integer.parseInt(consecutivoParte);
                    }

                    // se formatea la fecha                
                    SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
                    String fechaFormateada = formatoF.format(new Date());

                    // se formatea el consecutivo                                         
                    String numeroFormateado = String.format("%06d", consecutivo + 1);
                    String folio;
                    if (consecutivo == 0) {
                        folio = abreviacion + fechaFormateada + "-" + "000001";
                    } else {
                        folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                    }

                    // se le coloca un folio al lote liquidado por pago incompleto
                    getSelectAbono().setFolio(folio);
                }

                getSelectAbono().setCantidadPagada(getSelectAbono().getCantidadPagada() + getPagoDado());
                getSelectAbono().setDescripcion(getDescripcionPago());
                setUrbanizacionController(new UrbanizacionController());

                setTotalDado(getPagoDado());
                AbonoLoteDetalle abonoLoteDetalle = new AbonoLoteDetalle();
                if (getComboCobranza() == true) {
                    getSelectAbono().setCobranzaPagar(getSelectedLote().getManzana().getPredio().getCobranzaAtraso());
                    abonoLoteDetalle.setCobranza(getCobranzaDada());
                } else {
                    setCobranzaDada(0D);

                    abonoLoteDetalle.setCobranza(0D);
                }
                if (getComboMandados() == true) {
                    getSelectAbono().setMandadoPagar(getSelectedLote().getManzana().getPredio().getMandado());
                    abonoLoteDetalle.setMandado(getMandadoDado());

                } else {

                    abonoLoteDetalle.setMandado(0D);
                    setMandadoDado(0D);
                }
                getCobranzaController().addAbonoLote(getSelectAbono(), getLoggedUser(), false);
                Lote tempLote = getSelectAbono().getLote();

                tempLote.setMontoPagado(tempLote.getMontoPagado() + getSelectAbono().getCantidadPagada());
                if (getSelectAbono().getDiferenciaPago() == 0) {
                    // Se valida si se está dando el último abono en caso de serlo se cambia el lote ha liquidado
                    setAbonoLoteController(new AbonoLoteController());
                    List<AbonoLote> valAbLTotal = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbono(getSelectAbono().getLote(), TipoAbono.ABONO);
                    List<AbonoLote> valAbLPagodos = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(getSelectAbono().getLote(), TipoAbono.ABONO, GenericEnumType.ENABLED);
                    if (valAbLPagodos.size() == valAbLTotal.size()) {
                        tempLote.setEstatusLote(EstatusLote.LIQUIDADO);
                        // Se actualiza la lista de lotes
                        updateLotes();
                    }
                }
                getLoteController().updateMontoPagado(tempLote, getLoggedUser());

                abonoLoteDetalle.setPago(getPagoDado());
                abonoLoteDetalle.setAbonoLote(selectAbono);

                // Se cargan los abonos para validar el folio
                AbonosView ultimoFolio = getCobranzaController().fillAbonosViewByFolioAndProyecto(getSelectAbono().getLote().getManzana().getPredio().getId(), abreviacion);

                // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
                int consecutivo = 0;
                if (ultimoFolio != null) {
                    String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                    // Dividir el folio en partes utilizando el guion como separador
                    String[] partes = folior.split("-");
                    // Obtener la parte del consecutivo
                    String consecutivoParte = partes[4];
                    // Convertir el consecutivo a un entero
                    consecutivo = Integer.parseInt(consecutivoParte);
                }

                // se formatea la fecha                
                SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
                String fechaFormateada = formatoF.format(new Date());

                // se formatea el consecutivo                                         
                String numeroFormateado = String.format("%06d", consecutivo + 1);
                String folio;
                if (consecutivo == 0) {
                    folio = abreviacion + fechaFormateada + "-" + "000001";
                    abonoLoteDetalle.setFolio(folio);
                } else {
                    folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                    abonoLoteDetalle.setFolio(folio);
                }

                getCobranzaController().addAbonoLoteDetalle(abonoLoteDetalle, getLoggedUser());

                // Se le coloca el folio del sub abono al abono seleccionado para mostrarlo en le tiked
                getSelectAbono().setFolio(folio);
                getSelectAbono().setLastUpdatedOn(new Date());

                DecimalFormat formato = new DecimalFormat("#.##");
                String resultado = formato.format(getTotalPagar());
                setTotalPagar(Double.valueOf(resultado));
                setPagoExitoso(true);
                if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
                    setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
                }
                
                // se actualiza el listado de abonos
                fillAbonoLoteByLote();

                showMessage(FacesMessage.SEVERITY_INFO, "Pagado", "Abono pagado correctamente");

                // Enviar tiked                        
                // Formato de fecha 
                SimpleDateFormat formato2 = new SimpleDateFormat("dd-MM-yyyy");
                //fecha de pago
                String fechaPago = formato2.format(new Date());

                String HTMLBODY = "<h1>Recibo de pago " + getLoggedUser().getLocation().getBusinessName() + "</h1>"
                        + "<p>Esta es una notificación automática - Favor de NO responder (reply) a este email</p>"
                        + "<div style='padding: 0.5em; border: solid 1px; display: inline-block;'>"
                        + "<p><b>No.Abono: </b>" + getSelectAbono().getNumeroAbono() + "</p>"
                        + "<p><b>Folio: </b>" + getSelectAbono().getFolio() + "</p>"
                        + "<p><b>Fecha: </b>" + fechaPago + "</p>"
                        + "<p><b>CLIENTE: </b>" + (getSelectAbono().getCliente().getFirstName() + " "
                        + ((getSelectAbono().getCliente().getSecondName() != null && !getSelectAbono().getCliente().getSecondName().isEmpty())
                        ? getSelectAbono().getCliente().getSecondName() : "") + " " + getSelectAbono().getCliente().getLastName()) + "</p>"
                        + "<p><b>PREDIO: </b>" + getSelectAbono().getLote().getManzana().getPredio().getNombreProyecto() + "</p>"
                        + "<p><b>MANZANA: </b>" + getSelectAbono().getLote().getManzana().getNombre() + "</p>"
                        + "<p><b>LOTE: </b>" + getSelectAbono().getLote().getFolio() + "</p>"
                        + "<p><b>PAGO: </b>" + getPagoDado() + "</p>"
                        + "<p><b>GASTO POR COBRANZA: </b>" + getCobranzaDada() + "</p>"
                        + "<p><b>MANDADO: </b>" + getMandadoDado() + "</p>"
                        + "<p><b>TOTAL: </b>" + getTotalPagar() + "</p>"
                        + "<p><b>COMENTARIOS: </b>" + getDescripcionPago() + "</p>"
                        + "<p><b>COBRO: </b>" + (getSelectAbono().getLastUpdatedBy().getPerson().getFirstName() + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getSecondName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getLastName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getLastName() : "") + " "
                        + ((getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() != null)
                        ? getSelectAbono().getLastUpdatedBy().getPerson().getMiddleName() : "")) + "</p>"
                        + "<br/>"
                        + "<p><b>" + getLoggedUser().getLocation().getBusinessName() + "</b></p>"
                        + "<p><b>AGRADECE SU PREFERENCIA</b></p>"
                        + "<br/>"
                        + "<p>" + getLoggedUser().getLocation().getCompleteAddress()
                        + " " + getLoggedUser().getLocation().getMunicipality()
                        + " " + getLoggedUser().getLocation().getState()
                        + " " + getLoggedUser().getLocation().getPostalCode()
                        + "</p><br/>"
                        + "<p><b>RFC: </b>" + getLoggedUser().getLocation().getRfc() + "</p>"
                        + "<p><b>TEL: </b>" + getLoggedUser().getLocation().getPhone() + "</p>"
                        + "</div>";

                if (validarCorreo(getSelectAbono().getCliente().getMail())) {
                    showMessage(FacesMessage.SEVERITY_ERROR, "Error", "No se pudo enviar el recibo por correo al cliente verifique el correo del cliente");
                    logger.error("No se encontró un correo registrado para cliente");
                } else if (setEmailRecibo(getSelectAbono().getCliente().getMail(), HTMLBODY)) {
                    showMessage(FacesMessage.SEVERITY_INFO, "Recibo enviado por correo", "El recibo se envió correctamente al cliente");
                    logger.info("El recibo se envió correctamente al cliente ");
                } else {
                    showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                    logger.error("Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                }

            } else {
                setPagoExitoso(false);
                showMessage(FacesMessage.SEVERITY_ERROR, "Error", "El pago dado no puede ser mayor al pago predefinido");
            }

        } catch (NumberFormatException e) {
            setPagoExitoso(false);
            logger.error("PayAbono Error al convertir el consecutivo en número" + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al pagar");
        } catch (Exception e) {
            setPagoExitoso(false);
            logger.error("payAbono: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al pagar");
        }

    }

    public void addComment() {
        logger.info("addComment");
        setCobranzaController(new CobranzaController());
        try {

            ComentarioLote nuevoComentario = new ComentarioLote();

            nuevoComentario.setLote(selectedLote);
            nuevoComentario.setComentario(getNuevoComentario());
            getCobranzaController().addComentarioLote(nuevoComentario, getLoggedUser());
            setNuevoComentario(null);
            consultarComentariosLote();
            showMessage(FacesMessage.SEVERITY_INFO, "Comentario", "Comentario creado correctamente");

            setServiceOrderSingletonController(new ServiceOrderSingletonController());
            // crear notificasion            
            ServiceOrderNotification notificasion = new ServiceOrderNotification();
            notificasion.setId(UUID.randomUUID().toString());
            notificasion.setActionType(ServiceOrderActionType.CREATED);
            notificasion.setTitle("Nuevo comentario al lote: " + getSelectedLote().getFolio()
                    + ", manzana: " + getSelectedLote().getManzana().getNombre() + ", proyecto: " + getSelectedLote().getManzana().getPredio().getNombreProyecto());
            notificasion.setMessage(nuevoComentario.getComentario());
            notificasion.setCreatedOn(new Date());
            getServiceOrderSingletonController().saveServiceOrderNotification(notificasion);

            setUserLocationController(new UserLocationController());
            List<UserLocation> listUseUserLocation = getUserLocationController().fillAllUserLocationByLocation(getLoggedUser().getLocation());
            for (UserLocation userLocation : listUseUserLocation) {
                // vincular notificación  con el usuario destino            
                List<ServiceOrderNotificationDeliveryTo> notiList = new ArrayList<>();
                ServiceOrderNotificationDeliveryTo notiUSer = new ServiceOrderNotificationDeliveryTo();
                notiUSer.setId(UUID.randomUUID().toString());
                notiUSer.setServiceOrderNotification(notificasion);
                notiUSer.setStatusType(DeliveryStatusType.ENABLED);
                notiUSer.setUser(userLocation.getUser());
                notiList.add(notiUSer);
                getServiceOrderSingletonController().sendNotifications(notiList);
            }

        } catch (Exception e) {
            setPagoExitoso(false);
            logger.error("payAbono: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al pagar");
        }

    }

    public void resetTotalJuridico() {
        setTotalJuridico(0.0);
    }

    public void devolverPago() {
        logger.info("devolverPago");

        if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Error",
                    "No se puede hacer ninguna acción si existe un corte del día");
            return;
        }
        if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Dia cerrado",
                    "No se pueden eliminar más registros porque ya existe un cuadre de caja chica del día");
            return;
        }
        try {
            setAbonoLoteController(new AbonoLoteController());
            setDevolucionAbonoController(new DevolucionAbonoController());
            List<SolicitudDevolucionAbono> valSolicitud = getDevolucionAbonoController().fillAllSolicitudDevolucionAbonoByLocationAndAbonoLoteAndEstatusSolicitud(getLoggedUser().getLocation(), getSelectAbono(), EstatusSolicitud.PENDIENTE);
            if (valSolicitud.isEmpty()) {
                // Se actualiza el abono a cancelar 
                getSelectAbono().setPagoEstatus(GenericEnumType.CANCELED);
                getAbonoLoteController().updateAbonoLote2(getSelectAbono(), getLoggedUser());
                // Se crea una nueva solicitud de cancelación 
                SolicitudDevolucionAbono solisitud = new SolicitudDevolucionAbono();
                solisitud.setAbonoLote(getSelectAbono());
                solisitud.setLocation(getLoggedUser().getLocation());
                solisitud.setEstatusSolicitud(EstatusSolicitud.PENDIENTE);
                solisitud.setEstatusActivo(GenericEnumType.ENABLED);
                solisitud.setMontoDevolucion(getSelectAbono().getCantidadPagada());
                solisitud.setComentario(getComentario());
                getDevolucionAbonoController().addSolicitudDevolucionAbono(solisitud, getLoggedUser(), true);
                logger.info("Solicitud realizada correctamente");
                showMessage(FacesMessage.SEVERITY_INFO, "Solicitud realizada correctamente", "La solicitud para regresar el abono se realizó correctamente");
            } else {
                showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ya ahí una solicitud de devolución para este pago");
            }
        } catch (Exception e) {
            logger.info("Ocurrió un error al realizar la solicitud de devolución" + e);
            showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al realizar la solicitud de devolución");
        }
    }

    public boolean compararFechasAbonoLote(Date fecha) {
        Calendar cal1 = Calendar.getInstance();

        cal1.setTime(fecha);

        cal1.add(Calendar.DAY_OF_MONTH, 1);

        Calendar cal2 = Calendar.getInstance();

        cal1.setTime(new Date());

        LocalDate localDate1 = cal1.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate2 = cal2.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        return localDate1.compareTo(localDate2) == 1;

    }

    public void addPagoMultiple() {

        if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Error",
                    "No se puede hacer ninguna acción si existe un corte del día");
            return;
        }
        if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_WARN,
                    "Dia cerrado",
                    "No se pueden eliminar más registros porque ya existe un cuadre de caja chica del día");
            return;
        }

        setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        setLotesSinPagar(getCobranzaController().fillAbonoLoteByLoteNoPay(selectedLote));

        Lote tempLote = getLotesSinPagar().get(0).getLote();

        // se valida que el total del pago múltiple no sea mayor que la cantidad restante a pagar del lote
        setAbonoLoteController(new AbonoLoteController());
        List<AbonoLote> valAbLPago = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(tempLote, TipoAbono.ABONO, GenericEnumType.DISABLED);
        Double totalRestante = 0.0;
        for (AbonoLote valAbLP : valAbLPago) {
            totalRestante = totalRestante + valAbLP.getPago();
        }
        if (getPagoMultiple() > totalRestante) {
            showMessage(FacesMessage.SEVERITY_WARN, "Error", "El monto del pago múltiple es mayor del adeudo réstente del lote  " + totalRestante);
            return;
        }

        tempLote.setMontoPagado(tempLote.getMontoPagado() + pagoMultiple);
        setCantidadPagadaPagoMultiple(pagoMultiple.toString());

        try {

            // Se valida si el proyecto del lote cuenta con una abreviación
            String abreviacion = tempLote.getManzana().getPredio().getAbreviatura();
            if (abreviacion == null || abreviacion.isEmpty()) {
                showMessage(FacesMessage.SEVERITY_WARN, "Error",
                        "Debe de definir una abreviación para el proyecto, ya que es requerida para crear el folio");
                return;
            }
            abreviacion = abreviacion + "-";

            setFolios(new ArrayList<>());
            String detallesAbonoMultiple = "";

            // sé crear el registro para vincular los abonos múltiples 
            HitorialAbonoMultiple abonoMultiple = new HitorialAbonoMultiple();
            String idPM = UUID.randomUUID().toString();
            abonoMultiple.setId(idPM);
            abonoMultiple.setLote(tempLote);
            abonoMultiple.setLocation(getLoggedUser().getLocation());
            abonoMultiple.setTotalPago(getPagoMultiple());
            abonoMultiple.setEstatus(EstatusPagoMultiple.PAGADO);
            abonoMultiple.setFechaPago(new Date());
            abonoMultiple.setCliente(tempLote.getCliente());
            getCobranzaController().addHitorialAbonoMultiple(abonoMultiple, getLoggedUser(), true);

            int n = 0;
            for (int i = 0; i < getLotesSinPagar().size(); i++) {

                // Crear un objeto DecimalFormat para definir el formato de redondeo
                DecimalFormat formatoDecimal = new DecimalFormat("#.##");

                // Se cargan los abonos para validar el folio
                AbonosView ultimoFolio = getCobranzaController().fillAbonosViewByFolioAndProyecto(tempLote.getManzana().getPredio().getId(), abreviacion);

                // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
                int consecutivo = 0;
                if (ultimoFolio != null) {
                    String folior = ultimoFolio.getFolio(); // Reemplaza con tu variable que contiene el folio
                    // Dividir el folio en partes utilizando el guion como separador
                    String[] partes = folior.split("-");
                    // Obtener la parte del consecutivo
                    String consecutivoParte = partes[4];
                    // Convertir el consecutivo a un entero
                    consecutivo = Integer.parseInt(consecutivoParte);
                }

                // se formatea la fecha                
                SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yyyy");
                String fechaFormateada = formatoF.format(new Date());

                // se formatea el consecutivo                                         
                String numeroFormateado = String.format("%06d", consecutivo + 1);
                String folio;
                if (consecutivo == 0) {
                    folio = abreviacion + fechaFormateada + "-" + "000001";
                } else {
                    folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                }

                //se cargan la lista de los folios creados para cargarlos en el tiked                
                getFolios().add(folio);

                AbonoLote abonoLoteObj = getLotesSinPagar().get(i);
                abonoLoteObj.setCobranzaPagada(0D);
                abonoLoteObj.setCobranzaPagar(0D);
                abonoLoteObj.setMandadoPagado(0D);
                abonoLoteObj.setMandadoPagar(0D);
                abonoLoteObj.setDescripcion(getComentarioMultiple());
                abonoLoteObj.setAbonoMultiple(abonoMultiple);

                if (abonoLoteObj.getPagoEstatus().equals(GenericEnumType.INCOMPLETE)) {

                    if (abonoLoteObj.getDiferenciaPago() > getPagoMultiple()) {
                        // Se actualiza el abono lote incompleto con al cantidad restante del pago múltiple 
                        abonoLoteObj.setCantidadPagada(abonoLoteObj.getCantidadPagada() + getPagoMultiple());
                        abonoLoteObj.setDiferenciaPago(abonoLoteObj.getPago() - abonoLoteObj.getCantidadPagada());
                        getCobranzaController().addAbonoLote(abonoLoteObj, getLoggedUser(), false);

                        // se crea un nuevo abono lote detalle con el restante                         
                        AbonoLoteDetalle abonoLoteDetalle = new AbonoLoteDetalle();
                        // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                        if (n == 0 && getCobranza() > 0.0) {
                            abonoLoteDetalle.setCobranza(getCobranza());
                        } else {
                            abonoLoteDetalle.setCobranza(0D);
                        }
                        // Se valida si el primer abono de la lista para agregar la mandado si la hubo
                        if (n == 0 && getMandado() > 0.0) {
                            abonoLoteDetalle.setMandado(getMandado());
                        } else {
                            abonoLoteDetalle.setMandado(0D);
                        }
                        abonoLoteDetalle.setPago(getPagoMultiple());
                        abonoLoteDetalle.setAbonoLote(abonoLoteObj);
                        abonoLoteDetalle.setFolio(folio);
                        abonoLoteDetalle.setAbonoMultiple(abonoMultiple);
                        getCobranzaController().addAbonoLoteDetalle(abonoLoteDetalle, getLoggedUser());

                        // Se actualiza el detalle del abono múltiple
                        // Se convierte la fecha a string y se le da formato
                        String fechaApagarFormateada = formatoF.format(abonoLoteObj.getFechaAPagar());
                        // Se convierte la cantidad pagada String y se da formato         
                        String catidadPagadaFormateada = formatoDecimal.format(abonoLoteDetalle.getPago());
                        detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada;

                        // se actualiza el pago múltiple a 0
                        pagoMultiple = 0D;

                        break;
                    } else {
                        //se guarad la diferencia del abono imcompleto ates de actulisar el abono lote 
                        Double diferencia = abonoLoteObj.getDiferenciaPago();
                        // Se liquida el pago completo
                        abonoLoteObj.setCantidadPagada(abonoLoteObj.getPago());
                        abonoLoteObj.setDiferenciaPago(0D);
                        abonoLoteObj.setFolio(folio);
                        getCobranzaController().addAbonoLote(abonoLoteObj, getLoggedUser(), false);

                        // se actulia el detalle del abono multiple
                        // se comvierte la fecha a estring y se le da formato
                        String fechaApagarFormateada = formatoF.format(abonoLoteObj.getFechaAPagar());
                        // se comveirto la cantidad pagada String y se daformato         
                        String catidadPagadaFormateada = formatoDecimal.format(abonoLoteObj.getPago());
                        detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada;

                        //Se genera un nuevo abono detalle con la cantidad requerida para liquidar el abono 
                        AbonoLoteDetalle abonoLoteDetalle = new AbonoLoteDetalle();
                        // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                        if (n == 0 && getCobranza() > 0.0) {
                            abonoLoteDetalle.setCobranza(getCobranza());
                        } else {
                            abonoLoteDetalle.setCobranza(0D);
                        }
                        // Se valida si el primer abono de la lista para agregar la mandado si la hubo
                        if (n == 0 && getMandado() > 0.0) {
                            abonoLoteDetalle.setMandado(getMandado());
                        } else {
                            abonoLoteDetalle.setMandado(0D);
                        }
                        abonoLoteDetalle.setPago(diferencia);
                        abonoLoteDetalle.setAbonoLote(abonoLoteObj);
                        //se crea un folio extra para el abono lote detalle liquidado
                        numeroFormateado = String.format("%06d", consecutivo + 2);
                        folio = abreviacion + fechaFormateada + "-" + numeroFormateado;
                        getFolios().add(folio);
                        abonoLoteDetalle.setFolio(folio);
                        abonoLoteDetalle.setAbonoMultiple(abonoMultiple);

                        // se actulia el detalle del abono multiple
                        // se comveirto la cantidad pagada String y se daformato         
                        String catidadPagadaFormateada2 = formatoDecimal.format(abonoLoteDetalle.getPago());
                        detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada2;

                        // se guarda el abono lote detalle 
                        getCobranzaController().addAbonoLoteDetalle(abonoLoteDetalle, getLoggedUser());

                        // se actulisa la cantidad restante del pago multiple 
                        pagoMultiple = pagoMultiple - diferencia;
                    }

                } else if (abonoLoteObj.getPago() < getPagoMultiple()) {

                    abonoLoteObj.setCantidadPagada(abonoLoteObj.getPago());
                    abonoLoteObj.setDiferenciaPago(0D);
                    abonoLoteObj.setPagoEstatus(GenericEnumType.ENABLED);

                    // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                    if (n == 0 && getCobranza() > 0.0) {
                        abonoLoteObj.setCobranzaPagada(getCobranza());
                    } else {
                        abonoLoteObj.setCobranzaPagada(0D);
                    }
                    // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                    if (n == 0 && getMandado() > 0.0) {
                        abonoLoteObj.setMandadoPagado(getMandado());
                    } else {
                        abonoLoteObj.setMandadoPagado(0D);
                    }

                    // se coloca el folio
                    abonoLoteObj.setFolio(folio);

                    // se actulia el detalle del abono multiple
                    // se comvierte la fecha a estring y se le da formato
                    String fechaApagarFormateada = formatoF.format(abonoLoteObj.getFechaAPagar());
                    // se comveirto la cantidad pagada String y se daformato         
                    String catidadPagadaFormateada = formatoDecimal.format(abonoLoteObj.getPago());
                    detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada;

                    pagoMultiple = pagoMultiple - abonoLoteObj.getCantidadPagada();
                    getCobranzaController().addAbonoLote(abonoLoteObj, getLoggedUser(), false);

                } else if (pagoMultiple > 0) {

                    abonoLoteObj.setCantidadPagada(getPagoMultiple());
                    abonoLoteObj.setDiferenciaPago(abonoLoteObj.getPago() - abonoLoteObj.getCantidadPagada());
                    abonoLoteObj.setDescripcion(getComentarioMultiple());

                    // se valida si se a liquidado el abono con el restante del pago multiple 
                    if (abonoLoteObj.getDiferenciaPago() == 0) {
                        abonoLoteObj.setPagoEstatus(GenericEnumType.ENABLED);
                        // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                        if (n == 0 && getCobranza() > 0.0) {
                            abonoLoteObj.setCobranzaPagada(getCobranza());
                        } else {
                            abonoLoteObj.setCobranzaPagada(0D);
                        }
                        if (n == 0 && getMandado() > 0.0) {
                            abonoLoteObj.setMandadoPagado(getMandado());
                        } else {
                            abonoLoteObj.setMandadoPagado(0D);
                        }
                        // se coloca el folio
                        abonoLoteObj.setFolio(folio);
                        // se actulia el detalle del abono multiple
                        // se comvierte la fecha a estring y se le da formato
                        String fechaApagarFormateada = formatoF.format(abonoLoteObj.getFechaAPagar());
                        // se comveirto la cantidad pagada String y se daformato         
                        String catidadPagadaFormateada = formatoDecimal.format(abonoLoteObj.getPago());
                        detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada;
                    } else {

                        abonoLoteObj.setPagoEstatus(GenericEnumType.INCOMPLETE);
                        abonoLoteObj.setAbonoMultiple(abonoMultiple);

                        AbonoLoteDetalle abonoLoteDetalle = new AbonoLoteDetalle();
                        // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                        if (n == 0 && getCobranza() > 0.0) {
                            abonoLoteDetalle.setCobranza(getCobranza());
                        } else {
                            abonoLoteDetalle.setCobranza(0D);
                        }
                        // Se valida si el primer abono de la lista para agregar la cobranza si la hubo
                        if (n == 0 && getMandado() > 0.0) {
                            abonoLoteDetalle.setMandado(getMandado());
                        } else {
                            abonoLoteDetalle.setMandado(0D);
                        }
                        abonoLoteDetalle.setMandado(0D);
                        abonoLoteDetalle.setPago(pagoMultiple);
                        abonoLoteDetalle.setAbonoLote(abonoLoteObj);
                        // se coloca el folio
                        abonoLoteDetalle.setFolio(folio);
                        abonoLoteDetalle.setAbonoMultiple(abonoMultiple);

                        // se actulia el detalle del abono multiple
                        // se comvierte la fecha a estring y se le da formato
                        String fechaApagarFormateada = formatoF.format(abonoLoteObj.getFechaAPagar());
                        // se comveirto la cantidad pagada String y se daformato         
                        String catidadPagadaFormateada = formatoDecimal.format(abonoLoteDetalle.getPago());
                        detallesAbonoMultiple = detallesAbonoMultiple + " | " + folio + ", " + fechaApagarFormateada + ", " + catidadPagadaFormateada;

                        getCobranzaController().addAbonoLoteDetalle(abonoLoteDetalle, getLoggedUser());
                    }
                    pagoMultiple = 0D;
                    getCobranzaController().addAbonoLote(abonoLoteObj, getLoggedUser(), false);
                    break;

                }
                n++;
            }

            // se actulisa el detalle del abono multiple 
            setDetallesAbonoMul(detallesAbonoMultiple);

            // Se recorre la lista de folios y se colocan en una variable del tipo strig para imprimirla en el tiked
            StringBuilder sb = new StringBuilder();
            for (String folio : folios) {
                sb.append(folio).append(", ");
            }
            // Elimina la última coma y espacio si existen
            if (sb.length() > 0) {
                sb.setLength(sb.length() - 2);
            }
            setFoliosImprimir(sb.toString());

            // actulizar abono multiple             
            abonoMultiple.setFolios(sb.toString());
            abonoMultiple.setDetalle(detallesAbonoMultiple);
            abonoMultiple.setCometario(getComentarioMultiple());
            getCobranzaController().addHitorialAbonoMultiple(abonoMultiple, getLoggedUser(), false);

            // Se valida si se está dando el último abono en caso de serlo se cambia el lote ha liquidado            
            List<AbonoLote> valAbLTotal = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbono(tempLote, TipoAbono.ABONO);
            List<AbonoLote> valAbLPagodos = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbonoAndEstatus(tempLote, TipoAbono.ABONO, GenericEnumType.ENABLED);
            if (valAbLPagodos.size() == valAbLTotal.size()) {
                tempLote.setEstatusLote(EstatusLote.LIQUIDADO);
                // Se actualiza la lista de lotes
                updateLotes();
            }

            getLoteController().updateMontoPagado(tempLote, getLoggedUser());
            setPagoMultipleExitoso(true);
            if (tempLote.getManzana().getPredio().getLocation().getLogo() != null) {
                setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + tempLote.getManzana().getPredio().getLocation().getLogo());
            }
            setLotePagoMultiple(tempLote.getFolio());
            setManzanaPagoMultiple(tempLote.getManzana().getNombre());
            setPredioPagoMultiple(tempLote.getManzana().getPredio().getNombreProyecto());
            setClientePagoMultiple(tempLote.getCliente().getFirstName() + " " + tempLote.getCliente().getSecondName() + " " + tempLote.getCliente().getLastName() + " " + tempLote.getCliente().getMiddleName());
            setFechaPagoMultiple(new Date());
            setTipoProyectoPagoMultiple(tempLote.getManzana().getPredio().getTipoProyecto().toString());
            setUsuarioCobroPagoMultiple(getLoggedUser().getPerson().getFirstName() + " " + getLoggedUser().getPerson().getSecondName() + " " + getLoggedUser().getPerson().getLastName() + " " + getLoggedUser().getPerson().getMiddleName());
            showMessage(FacesMessage.SEVERITY_INFO, "Pagos correctos", "Pagos hechos correctamente");
            
            // se actualiza el listado de abonos
            fillAbonoLoteByLote();
            
            // Enviar tiked                        
            // Formato de fecha 
            SimpleDateFormat formato = new SimpleDateFormat("dd-MM-yyyy");
            //fecha de pago
            String fechaPago = formato.format(getFechaPagoMultiple());

            String HTMLBODY = "<h1>Recibo de pago múltiple " + getLoggedUser().getLocation().getBusinessName() + "</h1>"
                    + "<p>Esta es una notificación automática - Favor de NO responder (reply) a este email</p>"
                    + "<div style='padding: 0.5em; border: solid 1px; display: inline-block;'>"
                    + "<p><b>Folio: </b>" + getFoliosImprimir() + "</p>"
                    + "<p><b>Fecha: </b>" + fechaPago + "</p>"
                    + "<p><b>CLIENTE: </b>" + getClientePagoMultiple() + "</p>"
                    + "<p><b>PREDIO: </b>" + getPredioPagoMultiple() + "</p>"
                    + "<p><b>MANZANA: </b>" + getManzanaPagoMultiple() + "</p>"
                    + "<p>"
                    + getTipoProyectoPagoMultiple() + ": "
                    + getLotePagoMultiple() + ""
                    + "</p>"
                    + "<p><b>TOTAL: </b>" + getCantidadPagadaPagoMultiple() + "</p>"
                    + "<p><b>COBRO: </b>" + getUsuarioCobroPagoMultiple() + "</p>"
                    + "<p><b>DETALLE: </b>" + getDetallesAbonoMul() + "</p>"
                    + "<p><b>COMENTARIO: </b>" + getComentarioMultiple() + "</p>"
                    + "<br/>"
                    + "<p><b>" + getLoggedUser().getLocation().getBusinessName() + "</b></p>"
                    + "<p><b>AGRADECE SU PREFERENCIA</b></p>"
                    + "<br/>"
                    + "<p>" + getLoggedUser().getLocation().getCompleteAddress()
                    + " " + getLoggedUser().getLocation().getMunicipality()
                    + " " + getLoggedUser().getLocation().getState()
                    + " " + getLoggedUser().getLocation().getPostalCode()
                    + "</p><br/>"
                    + "<p><b>RFC: </b>" + getLoggedUser().getLocation().getRfc() + "</p>"
                    + "<p><b>TEL: </b>" + getLoggedUser().getLocation().getPhone() + "</p>"
                    + "</div>";

            if (validarCorreo(tempLote.getCliente().getMail())) {
                showMessage(FacesMessage.SEVERITY_ERROR, "Error", "No se pudo enviar el recibo por correo al cliente verifique el correo del cliente");
                logger.error("No se encontró un correo registrado para cliente");
            } else if (setEmailRecibo(tempLote.getCliente().getMail(), HTMLBODY)) {
                showMessage(FacesMessage.SEVERITY_INFO, "Recibo enviado por correo", "El recibo se envió correctamente al cliente");
                logger.info("El recibo se envió correctamente al cliente ");
            } else {
                showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
                logger.error("Ocurrió un error al tratar de enviar el recibo por correo al cliente ");
            }

        } catch (NumberFormatException e) {
            setPagoMultipleExitoso(false);
            logger.error("addPagoMultiple Error al convertir el consecutivo en número" + e);
        } catch (Exception e) {
            setPagoMultipleExitoso(false);
            logger.error("addPagoMultiple: " + e);
        }

    }

    public void generarReposteAbonos() throws IOException {
        //Crear reporte PDF
        //String filePathImagenEmpresa = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/resources/jasper-reports/crov-inmobiliaria-logo.jpg");
        URL url;

        if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
            url = new URL("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());

        } else {
            url = new URL("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
        }

        java.awt.Image imagenEmpresa = ImageIO.read(url);
        setCobranzaController(new CobranzaController());
        Double costo = getSelectedLote().getTotalAPagar();
        setAbonos(getCobranzaController().fillAbonoLoteByLoteAndTipo(getSelectedLote(), TipoAbono.ABONO));
        List<AbonoLoteView> abonosAndSub = getCobranzaController().fillAbonoLoteAndSubAbonoByLoteAndTipo(getSelectedLote(), TipoAbono.ABONO);

        // Corrección del saldo nuevo y el saldo anterior con base en la cantidad pagada 
        int i = 0;
        for (AbonoLoteView abono : abonosAndSub) {
            if (abono.getTipoAbono().equals(TipoAbono.ABONO)) {
                i++;
                abono.setSaldoAnterior(costo);
                abono.setNumeroAbono(String.valueOf(i));

                // Validación sub abonos para que solo sume la cantidad pagado del abono lote principal
                if (!abono.getTipoAbono().equals(TipoAbono.SUBABONO)) {
                    // Validación de la cantidad por valores nulos 
                    try {
                        costo = costo - abono.getCantidadPagada();
                    } catch (Exception e) {
                        costo = costo - 0;
                    }
                }

                abono.setSaldoNuevo(costo);
            } else {
                abono.setNumeroAbono(String.valueOf(i));
            }
        }
        Map<String, Object> parameters = new HashMap<String, Object>();
        JRBeanCollectionDataSource abonosLote = new JRBeanCollectionDataSource(abonosAndSub);
        parameters.put("abonosLote", abonosLote);
        parameters.put("imagenEmpresa", imagenEmpresa);
        parameters.put("nombreEmpresa", getLoggedUser().getLocation().getBusinessName() != null ? getLoggedUser().getLocation().getBusinessName() : "");
        parameters.put("rfcEmpresa", getLoggedUser().getLocation().getRfc() != null ? getLoggedUser().getLocation().getRfc() : "");
        parameters.put("correoEmpresa", getLoggedUser().getLocation().getMail() != null ? getLoggedUser().getLocation().getMail() : "");
        parameters.put("telefonoEmpresa", getLoggedUser().getLocation().getPhone() != null ? getLoggedUser().getLocation().getPhone() : "");
        parameters.put("regimenEmpresa", getLoggedUser().getLocation().getTaxRegime() != null ? getLoggedUser().getLocation().getTaxRegime().getNombre() : "");
        parameters.put("direccionEmpresa", getLoggedUser().getLocation().getAddress() != null ? getLoggedUser().getLocation().getAddress() : "");
        //datos de persona
        setCustomerController(new CustomerController());
        Person persona = getCustomerController().getPersonById(getSelectedLote().getCliente().getId());
        parameters.put("nombreCliente", persona.getFirstName() + " " + persona.getSecondName() + " " + persona.getLastName() + " " + persona.getMiddleName());
        setAbonoLoteController(new AbonoLoteController());
        ContactNumber contactNumber = getAbonoLoteController().finPhoneByClient(persona.getId());
        parameters.put("contactNumber", contactNumber != null ? contactNumber.getPhone() : "");

        //Datos predio, manzana, lote
        parameters.put("fecha", new Date());
        parameters.put("folioLote", getSelectedLote().getFolio() != null ? getSelectedLote().getFolio() : "");
        parameters.put("periodoPago", getSelectedLote().getPeriodoPago().name());
        parameters.put("nombreProyecto", getSelectedLote().getManzana().getPredio().getNombreProyecto());
        parameters.put("nombreManzana", getSelectedLote().getManzana().getNombre());
        parameters.put("plazos", getSelectedLote().getPlazoMeses());
        parameters.put("totalPago", getSelectedLote().getTotalPago());
        parameters.put("anticipo", getSelectedLote().getAnticipo());

        //se extraen la cantidad de pagos
        setCobranzaController(new CobranzaController());
        long pagosRestantes = getCobranzaController().countPagosByLote(getSelectedLote().getId());
        parameters.put("adeudo", Math.toIntExact(pagosRestantes));

        //se calcula el total de los pagos realizados    
        Double cantidadPagada = 0.0;
        for (AbonoLote abono : getAbonos()) {
            if (abono.getPagoEstatus().equals(GenericEnumType.ENABLED) && abono.getTipoAbono().equals(TipoAbono.ABONO)) {
                cantidadPagada = cantidadPagada + abono.getCantidadPagada();
            } else if (abono.getPagoEstatus().equals(GenericEnumType.INCOMPLETE)) {
                cantidadPagada = cantidadPagada + abono.getCantidadPagada();
            }
        }

        Double adeudo = getSelectedLote().getTotalPago() - cantidadPagada;
        parameters.put("restoPago", adeudo);

        try {
            String filePath = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/resources/jasper-reports/reportePagosLote.jrxml");
            File file = new File(filePath);
            JasperDesign jasperDesign = JRXmlLoader.load(file);
            JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
            JasperPrint printt = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource());
            JasperExportManager.exportReportToPdfFile(printt, "pagos.pdf");
            setPrint(printt);
        } catch (JRException e) {
            logger.error("Error al generar el reporte de compra : " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al generar el reporte de compra.");
        }
    }

    public void descargarArchivo() {
        try {
            HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
            response.addHeader("content-disposition", "attachment;filename = archivo.pdf");
            ServletOutputStream stream = response.getOutputStream();
            JasperExportManager.exportReportToPdfStream(getPrint(), stream);
            FacesContext.getCurrentInstance().responseComplete();
        } catch (IOException | JRException e) {
            logger.error("Error al descargar el reporte de compra : " + e);
        }
    }

    public void resetSelectAbono() {
        setSelectAbono(null);
        setSelectPagoMultiple(null);
    }

    public String validarColor(GenericEnumType estatus, Date fechaPagar) {
        Date fechaHoy = new Date();

        // Crea un formato para establecer la hora, minutos y segundos en 00:00:00
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            fechaPagar = sdf.parse(sdf.format(fechaPagar));
            fechaHoy = sdf.parse(sdf.format(fechaHoy));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Calcula la diferencia en días
        long diferenciaEnMillis = fechaPagar.getTime() - fechaHoy.getTime();
        long diferenciaEnDias = diferenciaEnMillis / (24 * 60 * 60 * 1000);

        if (estatus.equals(GenericEnumType.ENABLED)) {
            return "rowGreen";
        } else if (estatus.equals(GenericEnumType.CANCELED)) {
            return "rowYellow";
        } else if (fechaPagar.before(fechaHoy)) {
            return "rowRed";
        } else if (diferenciaEnDias > 0 && diferenciaEnDias <= 3) {
            return "rowOrange";
        } else {
            return "";
        }
    }

    public void cagarAbonosUrbanizacion() {
        try {
            setDetalleLoteUrbanizacionController(new DetalleLoteUrbanizacionController());
            setListDetalleLoteUrbanizacion(getDetalleLoteUrbanizacionController().buscarDetallesLotesPorLotes(getSelectedLote().getId(), getSelectUrbanizacion().getId()));
        } catch (Exception e) {
            logger.error("Error al cargar la lista de pagos de urbanización: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al cargar la lista de pagos de urbanización.");
        }
    }

    public void devolverPagoMultiple() {
        logger.info("Solicitando devolución de abono múltiple");
        try {
            setCobranzaController(new CobranzaController());
            //Se valida que no halla solicitudes de caseación con el estatus de PENDIENTE
            List<SolicitudDevolucionAbonoMultiple> valSolsitudes = getCobranzaController().fillSolicitudDevolucionAbonoMultipleByLocationAndHitorialAbonoMultipleAndEstatus(getLoggedUser().getLocation().getId(), getSelectPagoMultiple(), EstatusSolicitud.PENDIENTE);
            if (valSolsitudes.isEmpty()) {
                SolicitudDevolucionAbonoMultiple solicitud = new SolicitudDevolucionAbonoMultiple();
                solicitud.setHitorialAbonoMultiple(getSelectPagoMultiple());
                solicitud.setLocation(getLoggedUser().getLocation());
                solicitud.setEstatusSolicitud(EstatusSolicitud.PENDIENTE);
                solicitud.setEstatusActivo(GenericEnumType.ENABLED);
                solicitud.setMontoDevolucion(getSelectPagoMultiple().getTotalPago());
                solicitud.setComentario(getComentario());
                getCobranzaController().addSolicitudDevolucionAbonoMultiple(solicitud, getLoggedUser(), true);
                logger.info("Se solicitó la devolución del abono correctamente.");
                showMessage(FacesMessage.SEVERITY_INFO, "Solicitud realizada", "Se solicitó la devolución del abono correctamente.");
            } else {
                showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ahí una solicitud de caseación pendiente para este pago múltiple.");
            }
        } catch (Exception e) {
            logger.error("devolverPagoMultiple: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Ocurrió un error al realizar la solicitud de devolución.");
        }
    }

    public void reimprimirPagoMultiple() {
        logger.info(getSelectPagoMultiple().getId());
        try {
            setPagoMultipleExitoso(true);
            setCantidadPagadaPagoMultiple(getSelectPagoMultiple().getTotalPago().toString());
            setFechaPagoMultiple(getSelectPagoMultiple().getFechaPago());
            setClientePagoMultiple(getSelectPagoMultiple().getCliente() != null ? getSelectPagoMultiple().getCliente().getFirstName() + " " + getSelectPagoMultiple().getCliente().getSecondName() + " " + getSelectPagoMultiple().getCliente().getLastName() + " " + getSelectPagoMultiple().getCliente().getMiddleName() : "");
            setLotePagoMultiple(getSelectPagoMultiple().getLote().getFolio());
            setPredioPagoMultiple(getSelectPagoMultiple().getLote().getManzana().getNombre());
            setManzanaPagoMultiple(getSelectPagoMultiple().getLote().getManzana().getPredio().getNombreProyecto());
            setUsuarioCobroPagoMultiple(getSelectPagoMultiple().getCreatedBy().getPerson().getFirstName() + " " + getSelectPagoMultiple().getCreatedBy().getPerson().getSecondName() + " " + getSelectPagoMultiple().getCreatedBy().getPerson().getLastName() + " " + getSelectPagoMultiple().getCreatedBy().getPerson().getMiddleName());
            setTipoProyectoPagoMultiple(getSelectPagoMultiple().getLote().getManzana().getPredio().getTipoProyecto().toString());
            setComentarioMultiple(getSelectPagoMultiple().getCometario());
            setFoliosImprimir(getSelectPagoMultiple().getFolios());
            setDetallesAbonoMul(getSelectPagoMultiple().getDetalle());
            setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/crov-inmobiliaria-logo.png");
            if (getSelectedLote().getManzana().getPredio().getLocation().getLogo() != null) {
                setImagen("https://crov-inmobiliaria.s3.us-east-2.amazonaws.com/" + getSelectedLote().getManzana().getPredio().getLocation().getLogo());
            }
        } catch (Exception e) {
            setPagoMultipleExitoso(true);
            logger.error("Error al cargar el pago múltiple: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al cargar el pago múltiple.");
        }
    }

    public void cargarAbonosPagoMultiple() {
        logger.info("cargando abonos");
        try {
            setCobranzaController(new CobranzaController());
            setListAbonoLoteView(getCobranzaController().fillAbonoLoteViewByAbonoMultiple(getSelectPagoMultiple().getId()));
        } catch (Exception e) {
            logger.error("Error al cargar los abonos del pago múltiple: " + e);
            showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al cargar los abonos del pago múltiple.");
        }
    }

    private boolean validarCorreo(String correo) {
        try {
            // valida si el correo es null
            if (correo == null) {

                return false;
            } else {
                // Patrón de expresión regular para validar un correo electrónico
                String patron = "^[A-Za-z0-9+_.-]+@(.+)$";

                // Compila el patrón en un objeto Pattern
                Pattern pattern = Pattern.compile(patron);

                // Crea un objeto Matcher para la cadena de texto
                Matcher matcher = pattern.matcher(correo);

                // Comprueba si el correo electrónico coincide con el patrón
                if (matcher.matches()) {
                    return true;
                } else {

                    return false;
                }
            }
        } catch (Exception e) {
            logger.error("validarCorreo: ", e);
            return false;
        }

    }

    public List<HitorialAbonoMultiple> getPagosMultiples() {
        return pagosMultiples;
    }

    public void setPagosMultiples(List<HitorialAbonoMultiple> pagosMultiples) {
        this.pagosMultiples = pagosMultiples;
    }

    public HitorialAbonoMultiple getSelectPagoMultiple() {
        return selectPagoMultiple;
    }

    public void setSelectPagoMultiple(HitorialAbonoMultiple selectPagoMultiple) {
        this.selectPagoMultiple = selectPagoMultiple;
    }

    public PreventaController getControladorPreventa() {
        return controladorPreventa;
    }

    public void setControladorPreventa(PreventaController controladorPreventa) {
        this.controladorPreventa = controladorPreventa;
    }

    public List<Lote> getLotes() {
        return lotes;
    }

    public void setLotes(List<Lote> lotes) {
        this.lotes = lotes;
    }

    public List<PersonListView> getPersonas() {
        return personas;
    }

    public void setPersonas(List<PersonListView> personas) {
        this.personas = personas;
    }

    public String getSelectUser() {
        return selectUser;
    }

    public void setSelectUser(String selectUser) {
        this.selectUser = selectUser;
    }

    public String getFolioLote() {
        return folioLote;
    }

    public void setFolioLote(String folioLote) {
        this.folioLote = folioLote;
    }

    public Lote getSelectedLote() {
        return selectedLote;
    }

    public void setSelectedLote(Lote selectedLote) {
        this.selectedLote = selectedLote;
    }

    public List<AbonoLote> getAbonos() {
        return abonos;
    }

    public void setAbonos(List<AbonoLote> abonos) {
        this.abonos = abonos;
    }

    public AbonoLote getSelectAbono() {
        return selectAbono;
    }

    public void setSelectAbono(AbonoLote selectAbono) {
        this.selectAbono = selectAbono;
    }

    public CobranzaController getCobranzaController() {
        return cobranzaController;
    }

    public void setCobranzaController(CobranzaController cobranzaController) {
        this.cobranzaController = cobranzaController;
    }

    public Double getPagoDado() {
        return pagoDado;
    }

    public void setPagoDado(Double pagoDado) {
        this.pagoDado = pagoDado;
    }

    public Date getFechaPago() {
        return FechaPago;
    }

    public Boolean getComboMandados() {
        return comboMandados;
    }

    public void setComboMandados(Boolean comboMandados) {
        this.comboMandados = comboMandados;
    }

    public Boolean getComboCobranza() {
        return comboCobranza;
    }

    public void setComboCobranza(Boolean comboCobranza) {
        this.comboCobranza = comboCobranza;
    }

    public Double getMandadoDado() {
        return mandadoDado;
    }

    public void setMandadoDado(Double mandadoDado) {
        this.mandadoDado = mandadoDado;
    }

    public Double getCobranzaDada() {
        return cobranzaDada;
    }

    public void setCobranzaDada(Double cobranzaDada) {
        this.cobranzaDada = cobranzaDada;
    }

    public void setFechaPago(Date FechaPago) {
        this.FechaPago = FechaPago;
    }

    public GenericValidationController getGenericController() {
        return genericController;
    }

    public void setGenericController(GenericValidationController genericController) {
        this.genericController = genericController;
    }

    public Double getTotalPagar() {
        return totalPagar;
    }

    public void setTotalPagar(Double totalPagar) {
        this.totalPagar = totalPagar;
    }

    public String getDescripcionPago() {
        return descripcionPago;
    }

    public void setDescripcionPago(String descripcionPago) {
        this.descripcionPago = descripcionPago;
    }

    public Double getTotalDado() {
        return totalDado;
    }

    public void setTotalDado(Double totalDado) {
        this.totalDado = totalDado;
    }

    public List<Urbanizacion> getListaUrbanizacion() {
        return listaUrbanizacion;
    }

    public void setListaUrbanizacion(List<Urbanizacion> listaUrbanizacion) {
        this.listaUrbanizacion = listaUrbanizacion;
    }

    public UrbanizacionController getUrbanizacionController() {
        return urbanizacionController;
    }

    public void setUrbanizacionController(UrbanizacionController urbanizacionController) {
        this.urbanizacionController = urbanizacionController;
    }

    public Urbanizacion getSelectedUrbanizacion() {
        return selectedUrbanizacion;
    }

    public void setSelectedUrbanizacion(Urbanizacion selectedUrbanizacion) {
        this.selectedUrbanizacion = selectedUrbanizacion;
    }

    public DetalleLoteUrbanizacionController getDetalleLoteUrbanizacionController() {
        return detalleLoteUrbanizacionController;
    }

    public void setDetalleLoteUrbanizacionController(DetalleLoteUrbanizacionController detalleLoteUrbanizacionController) {
        this.detalleLoteUrbanizacionController = detalleLoteUrbanizacionController;
    }

    public Urbanizacion getSelectUrbanizacion() {
        return selectUrbanizacion;
    }

    public void setSelectUrbanizacion(Urbanizacion selectUrbanizacion) {
        this.selectUrbanizacion = selectUrbanizacion;
    }

    public Double getPagoUrbanizacion() {
        return pagoUrbanizacion;
    }

    public void setPagoUrbanizacion(Double pagoUrbanizacion) {
        this.pagoUrbanizacion = pagoUrbanizacion;
    }

    public Double getTotalPagarUrbanizacion() {
        return totalPagarUrbanizacion;
    }

    public void setTotalPagarUrbanizacion(Double totalPagarUrbanizacion) {
        this.totalPagarUrbanizacion = totalPagarUrbanizacion;
    }

    public DetalleLoteUrbanizacion getNuevoDetalleLoteUrbanizacion() {
        return nuevoDetalleLoteUrbanizacion;
    }

    public void setNuevoDetalleLoteUrbanizacion(DetalleLoteUrbanizacion nuevoDetalleLoteUrbanizacion) {
        this.nuevoDetalleLoteUrbanizacion = nuevoDetalleLoteUrbanizacion;
    }

    public Date getFechaPagoUrbanizacion() {
        return fechaPagoUrbanizacion;
    }

    public void setFechaPagoUrbanizacion(Date fechaPagoUrbanizacion) {
        this.fechaPagoUrbanizacion = fechaPagoUrbanizacion;
    }

    public List<EtapasJuridico> getListaEtapasJuridico() {
        return listaEtapasJuridico;
    }

    public void setListaEtapasJuridico(List<EtapasJuridico> listaEtapasJuridico) {
        this.listaEtapasJuridico = listaEtapasJuridico;
    }

    public EtapasJuridico getEtapaJuridicoSeleccionada() {
        return etapaJuridicoSeleccionada;
    }

    public void setEtapaJuridicoSeleccionada(EtapasJuridico etapaJuridicoSeleccionada) {
        this.etapaJuridicoSeleccionada = etapaJuridicoSeleccionada;
    }

    public EtapasJuridicoController getEtapaJuridicoController() {
        return etapaJuridicoController;
    }

    public void setEtapaJuridicoController(EtapasJuridicoController etapaJuridicoController) {
        this.etapaJuridicoController = etapaJuridicoController;
    }

    public String getEtapaJuridicoComentario() {
        return etapaJuridicoComentario;
    }

    public void setEtapaJuridicoComentario(String etapaJuridicoComentario) {
        this.etapaJuridicoComentario = etapaJuridicoComentario;
    }

    public Double getTotalJuridico() {
        return totalJuridico;
    }

    public void setTotalJuridico(Double totalJuridico) {
        this.totalJuridico = totalJuridico;
    }

    public Double getPagoJuridicoDado() {
        return pagoJuridicoDado;
    }

    public void setPagoJuridicoDado(Double pagoJuridicoDado) {
        this.pagoJuridicoDado = pagoJuridicoDado;
    }

    public Double getPagoCuentasJuridico() {
        return pagoCuentasJuridico;
    }

    public void setPagoCuentasJuridico(Double pagoCuentasJuridico) {
        this.pagoCuentasJuridico = pagoCuentasJuridico;
    }

    public DetalleLoteEtapa getNuevoDetalleLoteEtapa() {
        return nuevoDetalleLoteEtapa;
    }

    public void setNuevoDetalleLoteEtapa(DetalleLoteEtapa nuevoDetalleLoteEtapa) {
        this.nuevoDetalleLoteEtapa = nuevoDetalleLoteEtapa;
    }

    public String getDescipcionJuridico() {
        return descipcionJuridico;
    }

    public void setDescipcionJuridico(String descipcionJuridico) {
        this.descipcionJuridico = descipcionJuridico;
    }

    public DetalleLoteEtapaController getDetalleLoteEtapaController() {
        return detalleLoteEtapaController;
    }

    public void setDetalleLoteEtapaController(DetalleLoteEtapaController detalleLoteEtapaController) {
        this.detalleLoteEtapaController = detalleLoteEtapaController;
    }

    public String getIdEtapa() {
        return idEtapa;
    }

    public void setIdEtapa(String idEtapa) {
        this.idEtapa = idEtapa;
    }

    public Double getTotalAbonosRestantes() {
        return totalAbonosRestantes;
    }

    public void setTotalAbonosRestantes(Double totalAbonosRestantes) {
        this.totalAbonosRestantes = totalAbonosRestantes;
    }

    public List<AbonoLote> getAbonosRestantes() {
        return abonosRestantes;
    }

    public void setAbonosRestantes(List<AbonoLote> abonosRestantes) {
        this.abonosRestantes = abonosRestantes;
    }

    public Double getNewPagoPorConvenio() {
        return newPagoPorConvenio;
    }

    public void setNewPagoPorConvenio(Double newPagoPorConvenio) {
        this.newPagoPorConvenio = newPagoPorConvenio;
    }

    public Double getResiduoReajuste() {
        return residuoReajuste;
    }

    public void setResiduoReajuste(Double residuoReajuste) {
        this.residuoReajuste = residuoReajuste;
    }

    public Double getActualizarPago() {
        return actualizarPago;
    }

    public void setActualizarPago(Double actualizarPago) {
        this.actualizarPago = actualizarPago;
    }

    public AbonoLoteController getAbonoLoteController() {
        return abonoLoteController;
    }

    public void setAbonoLoteController(AbonoLoteController abonoLoteController) {
        this.abonoLoteController = abonoLoteController;
    }

    public Boolean getPagoExitoso() {
        return pagoExitoso;
    }

    public void setPagoExitoso(Boolean pagoExitoso) {
        this.pagoExitoso = pagoExitoso;
    }

    public LoteController getLoteController() {
        return loteController;
    }

    public void setLoteController(LoteController loteController) {
        this.loteController = loteController;
    }

    public DevolucionAbonoController getDevolucionAbonoController() {
        return devolucionAbonoController;
    }

    public void setDevolucionAbonoController(DevolucionAbonoController devolucionAbonoController) {
        this.devolucionAbonoController = devolucionAbonoController;
    }

    public String getComentario() {
        return comentario;
    }

    public void setComentario(String comentario) {
        this.comentario = comentario;
    }

    public List<ComentarioLote> getComentarioLote() {
        return comentarioLote;
    }

    public void setComentarioLote(List<ComentarioLote> comentarioLote) {
        this.comentarioLote = comentarioLote;
    }

    public String getNuevoComentario() {
        return nuevoComentario;
    }

    public void setNuevoComentario(String nuevoComentario) {
        this.nuevoComentario = nuevoComentario;
    }

    public String getImagen() {
        return imagen;
    }

    public void setImagen(String imagen) {
        this.imagen = imagen;
    }

    public Double getPagoMultiple() {
        return pagoMultiple;
    }

    public void setPagoMultiple(Double pagoMultiple) {
        this.pagoMultiple = pagoMultiple;
    }

    public List<AbonoLote> getLotesSinPagar() {
        return lotesSinPagar;
    }

    public void setLotesSinPagar(List<AbonoLote> lotesSinPagar) {
        this.lotesSinPagar = lotesSinPagar;
    }

    public String getLotesPagoMultiple() {
        return lotesPagoMultiple;
    }

    public void setLotesPagoMultiple(String lotesPagoMultiple) {
        this.lotesPagoMultiple = lotesPagoMultiple;
    }

    public List<AbonoLote> getLotesSinPagarIncompletos() {
        return lotesSinPagarIncompletos;
    }

    public void setLotesSinPagarIncompletos(List<AbonoLote> lotesSinPagarIncompletos) {
        this.lotesSinPagarIncompletos = lotesSinPagarIncompletos;
    }

    public boolean isPagoMultipleIncompletos() {
        return pagoMultipleIncompletos;
    }

    public void setPagoMultipleIncompletos(boolean pagoMultipleIncompletos) {
        this.pagoMultipleIncompletos = pagoMultipleIncompletos;
    }

    public boolean isPagoMultipleExitoso() {
        return pagoMultipleExitoso;
    }

    public void setPagoMultipleExitoso(boolean pagoMultipleExitoso) {
        this.pagoMultipleExitoso = pagoMultipleExitoso;
    }

    public String getFechasPagadas() {
        return fechasPagadas;
    }

    public void setFechasPagadas(String fechasPagadas) {
        this.fechasPagadas = fechasPagadas;
    }

    public String getCantidadPagadaPagoMultiple() {
        return cantidadPagadaPagoMultiple;
    }

    public void setCantidadPagadaPagoMultiple(String cantidadPagadaPagoMultiple) {
        this.cantidadPagadaPagoMultiple = cantidadPagadaPagoMultiple;
    }

    public Date getFechaPagoMultiple() {
        return fechaPagoMultiple;
    }

    public void setFechaPagoMultiple(Date fechaPagoMultiple) {
        this.fechaPagoMultiple = fechaPagoMultiple;
    }

    public String getClientePagoMultiple() {
        return clientePagoMultiple;
    }

    public void setClientePagoMultiple(String clientePagoMultiple) {
        this.clientePagoMultiple = clientePagoMultiple;
    }

    public String getLotePagoMultiple() {
        return lotePagoMultiple;
    }

    public void setLotePagoMultiple(String lotePagoMultiple) {
        this.lotePagoMultiple = lotePagoMultiple;
    }

    public String getPredioPagoMultiple() {
        return predioPagoMultiple;
    }

    public void setPredioPagoMultiple(String predioPagoMultiple) {
        this.predioPagoMultiple = predioPagoMultiple;
    }

    public String getManzanaPagoMultiple() {
        return manzanaPagoMultiple;
    }

    public void setManzanaPagoMultiple(String manzanaPagoMultiple) {
        this.manzanaPagoMultiple = manzanaPagoMultiple;
    }

    public String getUsuarioCobroPagoMultiple() {
        return usuarioCobroPagoMultiple;
    }

    public void setUsuarioCobroPagoMultiple(String usuarioCobroPagoMultiple) {
        this.usuarioCobroPagoMultiple = usuarioCobroPagoMultiple;
    }

    public String getTipoProyectoPagoMultiple() {
        return tipoProyectoPagoMultiple;
    }

    public void setTipoProyectoPagoMultiple(String tipoProyectoPagoMultiple) {
        this.tipoProyectoPagoMultiple = tipoProyectoPagoMultiple;
    }

    public CustomerController getCustomerController() {
        return customerController;
    }

    public void setCustomerController(CustomerController customerController) {
        this.customerController = customerController;
    }

    public JasperPrint getPrint() {
        return print;
    }

    public void setPrint(JasperPrint print) {
        this.print = print;
    }

    public List<DetalleLoteUrbanizacion> getListDetalleLoteUrbanizacion() {
        return listDetalleLoteUrbanizacion;
    }

    public void setListDetalleLoteUrbanizacion(List<DetalleLoteUrbanizacion> listDetalleLoteUrbanizacion) {
        this.listDetalleLoteUrbanizacion = listDetalleLoteUrbanizacion;
    }

    public Date getFechaActual() {
        return fechaActual;
    }

    public void setFechaActual(Date fechaActual) {
        this.fechaActual = fechaActual;
    }

    public List<AbonoLoteView> getListAbonoLoteView() {
        return ListAbonoLoteView;
    }

    public void setListAbonoLoteView(List<AbonoLoteView> ListAbonoLoteView) {
        this.ListAbonoLoteView = ListAbonoLoteView;
    }

    public String getComentarioMultiple() {
        return comentarioMultiple;
    }

    public void setComentarioMultiple(String comentarioMultiple) {
        this.comentarioMultiple = comentarioMultiple;
    }

    public List<String> getFolios() {
        return folios;
    }

    public void setFolios(List<String> folios) {
        this.folios = folios;
    }

    public String getFoliosImprimir() {
        return foliosImprimir;
    }

    public void setFoliosImprimir(String foliosImprimir) {
        this.foliosImprimir = foliosImprimir;
    }

    public String getDetallesAbonoMul() {
        return detallesAbonoMul;
    }

    public void setDetallesAbonoMul(String detallesAbonoMul) {
        this.detallesAbonoMul = detallesAbonoMul;
    }

    public Double getSaldoAnteriorUrbanizacion() {
        return saldoAnteriorUrbanizacion;
    }

    public void setSaldoAnteriorUrbanizacion(Double saldoAnteriorUrbanizacion) {
        this.saldoAnteriorUrbanizacion = saldoAnteriorUrbanizacion;
    }

    public Double getSaldoNuevoUrbanizacion() {
        return saldoNuevoUrbanizacion;
    }

    public void setSaldoNuevoUrbanizacion(Double saldoNuevoUrbanizacion) {
        this.saldoNuevoUrbanizacion = saldoNuevoUrbanizacion;
    }

    public Double getCobranza() {
        return cobranza;
    }

    public void setCobranza(Double cobranza) {
        this.cobranza = cobranza;
    }

    public Double getMandado() {
        return mandado;
    }

    public void setMandado(Double mandado) {
        this.mandado = mandado;
    }

    public String getUltimoAbonoPagado() {
        return ultimoAbonoPagado;
    }

    public void setUltimoAbonoPagado(String ultimoAbonoPagado) {
        this.ultimoAbonoPagado = ultimoAbonoPagado;
    }

    public String getUltimoAbonoMultiplePagado() {
        return ultimoAbonoMultiplePagado;
    }

    public void setUltimoAbonoMultiplePagado(String ultimoAbonoMultiplePagado) {
        this.ultimoAbonoMultiplePagado = ultimoAbonoMultiplePagado;
    }

    public ServiceOrderSingletonController getServiceOrderSingletonController() {
        return serviceOrderSingletonController;
    }

    public void setServiceOrderSingletonController(ServiceOrderSingletonController serviceOrderSingletonController) {
        this.serviceOrderSingletonController = serviceOrderSingletonController;
    }

    public UserLocationController getUserLocationController() {
        return userLocationController;
    }

    public void setUserLocationController(UserLocationController userLocationController) {
        this.userLocationController = userLocationController;
    }

}
