<?php

/**
 * liquidacion_cesantia actions.
 *
 * @package    nomina
 * @subpackage liquidacion_cesantia mensuales
 * @author     Your name here
 * @version    SVN: $Id: actions.class.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
 */
class liquidacion_cesantiaActions extends sfActions {

    /**
     * Liquidacion Cesantias - para no liquidar y pasar por alto y realizar base liquidacion - 20180810
     *
     * @param sfRequest $request A request object
     */
    public function executeList2(sfWebRequest $request) {

        //Revisar que sea post
        //$this->forward404Unless($request->isMethod('post'));
        //Guardar los parametros del request en el log
        $this->logMessage("---BEGIN Logging request");
        foreach ($request->getPostParameters() as $key => $value) {
            $this->logMessage("request[$key] = $value");
        }
        $this->logMessage("--------------------------------------------------* Ip: " . $_SERVER['REMOTE_ADDR']);
        foreach ($request->getGetParameters() as $key => $value) {
            $this->logMessage("request[$key] = $value");
        }
        $this->logMessage("---END Logging request");

        $progress_key = $request['progress_key'] . $request['username'];

        MemcacheHandler::getInstance()->set($progress_key, 100);

        $this->status = 0;
        $this->list_data = array();
    }

    /**
     * Liquidacion Cesantias
     *
     * @param sfRequest $request A request object
     */
    public function executeList(sfWebRequest $request) {

        //Revisar que sea post
        //$this->forward404Unless($request->isMethod('post'));
        //Guardar los parametros del request en el log
        $this->logMessage("---BEGIN Logging request");
        foreach ($request->getPostParameters() as $key => $value) {
            $this->logMessage("request[$key] = $value");
        }
        $this->logMessage("--------------------------------------------------* Ip: " . $_SERVER['REMOTE_ADDR']);
        foreach ($request->getGetParameters() as $key => $value) {
            $this->logMessage("request[$key] = $value");
        }
        $this->logMessage("---END Logging request");




        /**
         * Abrir nueva conexion con la Base de Datos
         */
        $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
        $this->conn->beginTransaction();

        /*
         * Formato de fecha
         */
        //Sql
        $sql = <<<EOD
ALTER SESSION SET NLS_DATE_FORMAT = "YYYY-MM-DD" 
EOD;
        //Ejecutar SQL
        CN_TABLE::executeSQL($sql);
        $arrayConstantes = array();

        try {


            /**
             * Consultar salario minimo
             */
            $salario_minimo = 550000;
            //Sql
            $sql = <<<EOD
(select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = extract(year from sysdate))  
EOD;
            //Ejecutar SQL
            $record_smlv = CN_TABLE::executeSQL($sql);

            if (count($record_smlv) > 0) {
                //No se debe redondear - 20130802
//                $salario_minimo = round($record_smlv[0]['valor_mensual'], -3);
                $salario_minimo = round($record_smlv[0]['valor_mensual']);
            }

            /**
             * Cargar tabla constantes
             */
            $text = '$con_';
            //Constantes 
            $sql = <<<EOD
Select cons.*, '$text'|| cons.id_constante as reemplazo from no_constante cons 
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);


            //Agrega a un array todas las constantes
            foreach ($records as $value) {

//                foreach ($value as $key => $value2) {
//                    $this->logMessage($key . " - " . $value2);
//                }

                $arrayConstantes[$value['reemplazo']] = $value;
//                $this->logMessage($value['reemplazo'] . "------------------------" . $arrayConstantes[$value['reemplazo']]);
            }

            /*
             * Anexo de variables del request para reemplazo en constantes
             */
//            $arrayConstantes[''] = '';

            /**
             * Variables de filtro
             */
            //id_periodo
            $id_periodo = $request['id_periodo_filtro'];
            $id_periodo_actual = $request['id_periodo'];
            $progress_key = $request['progress_key'] . $request['username'];

            //id_agrup_concepto
            $id_agrup_concepto = $request['id_agrup_concepto'];

            //Funcionario num_doc
            $num_doc = null;
            $whereFuncionarioNumDoc = "";
            if (isset($request['num_doc'])) {
                $num_doc = $request['num_doc'];
                $whereFuncionarioNumDoc = " AND tab0.num_doc = '" . $request['num_doc'] . "'";
            }
            //Funcionario id_tipo_doc 
            $id_tipo_doc = null;
            $whereFuncionarioTipoDoc = "";
            if (isset($request['id_tipo_doc'])) {
                $id_tipo_doc = $request['id_tipo_doc'];
                $whereFuncionarioTipoDoc = " AND tab0.id_tipo_doc = " . $request['id_tipo_doc'];
            }

            /*
             *  Borrar datos anteriores Periodo-Funcionario
             */
            //Sql
            $sql = <<<EOD
DELETE FROM NO_CESANTIA tab0 WHERE tab0.id_periodo = $id_periodo
and tab0.consolidado = 0 
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);


            /*
             * Traer funcionarios activos para el periodo
             * o que tambien esten retirados en el periodo
             * Debe tomar tambien el primer dia del siguiente mes - 20130729
             * se agregan variables para validar retiro primer dia mes - 20150219
             * Si no es periodo mensual, no genera registro - 20170502
             */
            //Sql
            $sql = <<<EOD
select distinct
    
--tab0.id_estado_func,
tab0.id_tipo_doc,
tab0.num_doc,
--tab0.id_dp,
tab0.id_anhos,
tab0.id_meses,
tab0.periodo,
--tab0.actual,
--tab0.id_ea,
--tab0.ID_CEN_OP,
nombra.id_nombramiento,
nombra.fecha_nombra,
case when extract(month from nombra.fecha_ingreso) || extract(year from nombra.fecha_ingreso) = (select id_meses || id_anhos from no_periodo where id_periodo = $id_periodo) 
then nombra.fecha_ingreso else null end as fecha_ingreso,
case when extract(month from nombra.fecha_retiro - 1) || extract(year from nombra.fecha_retiro - 1) = (select id_meses || id_anhos from no_periodo where id_periodo = $id_periodo) 
then nombra.fecha_termina else null end as fecha_termina,
case when extract(month from nombra.fecha_retiro - 1) || extract(year from nombra.fecha_retiro - 1) = (select id_meses || id_anhos from no_periodo where id_periodo = $id_periodo) 
then nombra.fecha_retiro else null end as fecha_retiro,
nombra.fecha_termina as fecha_termina_real,
nombra.fecha_retiro as fecha_retiro_real,
case when nombra.fecha_retiro = (select fecha_ini from no_periodo where id_periodo = $id_periodo) then 1 else 0 end as retiro_primerdiames
                    
from no_estado_func_v tab0

left join no_periodo perd
on perd.ID_PERIODO = tab0.PERIODO

join no_nombramiento_v nombra
on tab0.id_tipo_doc = nombra.id_tipo_doc
and tab0.num_doc = nombra.num_doc

WHERE tab0.periodo = $id_periodo
and perd.ID_TIPO_PERIODO = 1
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and ( tab0.actual = 1 

    or (nombra.estado = 1 or
      ( nombra.estado = 0 
        and nombra.fecha_retiro
      between to_date('01/'|| (select lpad(id_meses,2,'0') ||'/'||id_anhos from no_periodo where id_periodo = $id_periodo) ,'dd/mm/yyyy')
      and trunc(last_day( TO_DATE('01/'|| (SELECT LPAD(ID_MESES,2,'0') ||'/'||ID_ANHOS FROM NO_PERIODO WHERE ID_PERIODO = $id_periodo) ,'dd/mm/yyyy') ) +1 )
      )
    )

)

order by
tab0.id_anhos,
tab0.id_tipo_doc,
tab0.id_meses,
tab0.num_doc 
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

            //Validar si hay funcionarios para liquidación
            if (count($records) > 0) {
                $this->logMessage("[Liquidación Cesantias] Validar si hay funcionarios para liquidación.");

                /*
                 * Obtener concep_periodo por agrupacion - Orden a liquidar
                 */
                $sql = <<<EOD
select 
* 
from no_agrup_deta
where id_agrup_concepto = $id_agrup_concepto
order by 
orden,
id_agrup_deta 
EOD;
                //Ejecutar SQL
                $records_agrup = CN_TABLE::executeSQL($sql);


                /*
                 * Por funcionario 
                 */
                $i = 1;
                $nom_conceptos_a_procesar = count($records);

                // Antes de inicar el proceso largo
                $brecha = 1;
                if ($nom_conceptos_a_procesar > 100)
                    $brecha = $nom_conceptos_a_procesar - (0.99 * $nom_conceptos_a_procesar);

                $this->logMessage("[Liquidación Cesantias] nom_conceptos_a_procesar: " . $nom_conceptos_a_procesar);
                foreach ($records as $value) {

                    // Guardar un valor en el proceso largo
                    if ($i % $brecha == 0) {
                        MemcacheHandler::getInstance()->set($progress_key, round(($i / $nom_conceptos_a_procesar) * 100, 0));
                    }

                    $this->logMessage("[Liquidación Cesantias] Existen liquidaciones.");

                    /*
                     * Datos por record
                     */
                    $fecha_ingreso = $value['fecha_ingreso'];
                    $fecha_termina = $value['fecha_termina'];
                    $fecha_termina_real = $value['fecha_termina_real'];
                    $fecha_retiro = $value['fecha_retiro'];
                    $fecha_retiro_real = $value['fecha_retiro_real'];
                    $retiro_primerdiames = $value['retiro_primerdiames'];
                    $num_doc = $value['num_doc'];
                    $id_tipo_doc = $value['id_tipo_doc'];

                    /*
                     * Calcular los dias a liquidar (ausencias no afectan antiguedad)
                     */
                    $dias_liq = $this->diasLiquidar($id_periodo, $num_doc, $id_tipo_doc, $fecha_ingreso, $fecha_termina, $value);
                    $this->logMessage("[Liquidación Cesantias] Dias de Liquidación: " . $dias_liq);

                    /**
                     * Recorrer Agrupaciones
                     */
                    foreach ($records_agrup as $value_agrup) {

                        /*
                         * Variables agrup_concep
                         */
                        $id_concep_nomina = $value_agrup['id_concep_nomina'];
                        $caracter = $value_agrup['tipo_valor'];

                        /**
                         * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
                         * Se pone Tag_retro en 1 para que tenga encuenta el retro - 20150626
                         */
                        $sql = <<<EOD
select
$salario_minimo as salario_minimo,
1 as tag,
1 as tg_retro,
$dias_liq as dias_liq,
'$caracter' as caracter,
nvl('$fecha_ingreso', '') as fecha_ingreso,
nvl('$fecha_termina', '') as fecha_termina,
nvl('$fecha_termina_real', '') as fecha_termina_real,
nvl('$fecha_retiro', '') as fecha_retiro,
nvl('$fecha_retiro_real', '') as fecha_retiro_real,
nvl('$retiro_primerdiames', '')  as retiro_primerdiames,
$dias_liq as num_dias,
null as porcentaje,
$num_doc as num_doc,
$id_tipo_doc as id_tipo_doc,
$id_periodo as id_periodo,
$id_periodo as periodo,
$id_concep_nomina as id_concep_nomina
from dual     
EOD;
                        //Ejecutar SQL
                        $recordsLiq = CN_TABLE::executeSQL($sql);

                        /*
                         * Validar registro
                         */
                        if (count($recordsLiq) > 0) {

                            //Liquidar concepto
                            $record_liq = $recordsLiq[0];
                            $this->liquidar($id_periodo, $num_doc, $id_tipo_doc, $id_concep_nomina, $record_liq, $arrayConstantes);


                            /*
                             * Borrar aportes de funcionarios en comision en otra entidad id -> 8 - 20141209
                             * Validar novedad por fecha y actualizar valor base del mes anterior - 20150311
                             * Incidente #38770, Se retira por Ajuste del total, para no tener en cuenta valores de personas en comision o sin liquidacion - 20240924
                             */
                            //Sql
                            $sql = <<<EOD
UPDATE NO_CESANTIA tab0  SET tab0.valor_liquidado = 0, 
valor_base = (
    select /*aux.num_doc,*/ sum(aux.valor_base) as valor_base from (
        select 
        ces.num_doc, nvl(ces.valor_base,0) as valor_base, 
        row_number() over ( partition by ces.num_doc order by ces.id_periodo desc) rn
        from no_cesantia ces 
        where
        ces.consolidado = 0
        and ces.id_periodo != $id_periodo 
    )aux  
    where aux.rn = 1
    and aux.num_doc = tab0.num_doc
    group by
    aux.num_doc
)
WHERE tab0.id_periodo = $id_periodo
and tab0.consolidado = 0 
and tab0.num_dias = 0 
and tab0.num_doc in (
    select distinct nov.num_doc from no_novedad_personal nov
    where 
    nov.estado = 1
    and nov.id_novedad = 8
    and (
        (select fecha_ini from no_periodo where id_periodo = $id_periodo) between nov.fecha_inicial and nov.fecha_terminacion
        or    
        (select fecha_fin from no_periodo where id_periodo = $id_periodo) between nov.fecha_inicial and nov.fecha_terminacion
    )
)                                    
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
                            //Ejecutar SQL
                            //CN_TABLE::executeSQL($sql);
                        } else {
                            /*
                             * Mensaje de error
                             */
                            $mensajeError = "No hay registro para liquidación de cesantias. Concepto: " . $id_concep_nomina;

//                            $this->status = 1;
//                            $this->list_data = array();
//                            $this->mensajeError = $mensajeError;
                            $this->logMessage("[Liquidación Cesantias] " . $mensajeError);
                        }
                    }
//                    die();
                    $i++;
                }
                MemcacheHandler::getInstance()->set($progress_key, 100);

                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();
                $this->status = 0;
                $this->list_data = array();
                $this->logMessage("[Liquidación Cesantias] Liquidación exitosa.");
            } else {
                MemcacheHandler::getInstance()->set($progress_key, 100);

                /*
                 * ROLLBACK DE TODAS LAS TRANSACCIONES EN CASO DE QUE OCURRA ALGUN ERROR
                 */
//                $this->conn->rollback();

                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();

                /*
                 * Mensaje de error
                 */
                $mensajeError = "No hay funcionarios para liquidación.";

                $this->status = 1;
                $this->list_data = array();
                $this->mensajeError = $mensajeError;
                $this->logMessage("[Liquidación Cesantias] " . $mensajeError);
            }
        } catch (Exception $e) {
            MemcacheHandler::getInstance()->set($progress_key, 100);

            /*
             * ROLLBACK DE TODAS LAS TRANSACCIONES EN CASO DE QUE OCURRA ALGUN ERROR
             */
            $this->conn->rollback();
            $this->status = 1;
            $this->mensajeError = "[Liquidación Cesantias] Ocurrio un error: " . $e->getMessage();
            $this->list_data = array();
            $this->logMessage("[Liquidación Cesantias] ERROR!");
            $this->logMessage($e->getMessage());
        }
    }

    /**
     * Calcular los dias a liquidar (ausencias no afectan antiguedad) 
     * @param type $id_periodo
     * @param type $num_doc
     * @param type $id_tipo_doc
     * @param type $fecha_ingreso
     * @param type $fecha_termina
     * @param type $record
     */
    private function diasLiquidar($id_periodo, $num_doc, $id_tipo_doc, $fecha_ingreso, $fecha_termina, $record) {

        /*
         * Variables de calculo
         */
        $dias_calc = 0;
        $dias_kardex = 0;

        /*
         * Calculo de dias diferencia
         */
        //Sql
        $sql = <<<EOD
select 
to_date(fecha_termina, 'yyyy-mm-dd') - to_date(fecha_ingreso, 'yyyy-mm-dd') + 1 as dias,
to_date(fecha_termina, 'yyyy-mm-dd') as fecha_termina,
to_date(fecha_ingreso, 'yyyy-mm-dd') as fecha_ingreso
from (
select
nvl('$fecha_ingreso',to_date( per.id_anhos || '-' || per.id_meses || '-01', 'yyyy-mm-dd') ) as fecha_ingreso,
nvl('$fecha_termina',trunc(last_day( to_date( per.id_anhos || '-' || per.id_meses, 'yyyy-mm') ) ) ) as fecha_termina
from no_periodo per
where 
per.id_periodo = $id_periodo
)
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        if (count($records) > 0) {
            $this->logMessage("[Liquidación Cesantias] Dias de diferencia: " . $records[0]['dias']);

            $fecha_ingreso = $records[0]['fecha_ingreso'];
            $fecha_termina = $records[0]['fecha_termina'];
            $dias = CN_TABLE::diasEntreFechas($fecha_ingreso, $fecha_termina, false);
//            $dias_calc = $records[0]['dias'];
            $dias_calc = $dias;


            /*
             * Claculo de dias de novedad de kardex que afectan antiguedad
             * 
             * Se restan dias de kardex del mes unicamente - 20130627
             * Verificacion del mes de periodo a liqudiar cesantias - 20130826
             * Solo coloca en 0 para los que estan todo en mes en la novedad de kardex - 20170822
             * Si la fecha final de la novedad es igual o menor al periodo final, toma todos los dias, asi sean del mes de registro la novedad - 20190909
             * Incidente #16371,se toman dias de la novedad que apliquen segun el periodo liquidado, se comenta segun comentario de (20190909) - 20200227
             * Se valida inicio de la nov para que no tome meses de otros años - 20210818::LAVILA
             */
            $fecha_ini = $records[0]['fecha_ingreso'];
            $fecha_fin = $records[0]['fecha_termina'];
            //Sql
            $sql = <<<EOD
select nvl(sum(dias_ka),0) as dias from(
  select 
  dias_habiles_cant( to_date(novka.fecha_ini,'yyyy-mm-dd'), to_date(novka.fecha_fin,'yyyy-mm-dd') ) as dias,
  DIAS_RANGO_MES_SIN_TREINTAYUNO( case when NOVKA.FECHA_INI < (select fecha_ini from no_periodo where id_periodo =  $id_periodo) then (select fecha_ini from no_periodo where id_periodo =  $id_periodo) else NOVKA.FECHA_INI end,
      NOVKA.FECHA_FIN, (select extract(month from fecha_ini) from no_periodo where id_periodo =  $id_periodo) ) as DIAS_KA,
  /*case when NOVKA.FECHA_FIN <= (select fecha_fin from no_periodo where id_periodo = $id_periodo) then novka.num_dias 
      else DIAS_RANGO_MES_SIN_TREINTAYUNO( NOVKA.FECHA_INI, NOVKA.FECHA_FIN, (select extract(month from fecha_ini) from no_periodo where id_periodo =  $id_periodo) ) end DIAS_KA,*/
  novka.* ,
  tipnov.afecta_antigu,
  tipnov.afecta_alimen
  from no_novedad_kardex novka
  join no_tip_nov_ka tipnov 
  on novka.id_tip_nov_ka = tipnov.id_tip_nov_ka
  and tipnov.afecta_antigu = 1 
  and novka.estado = 1
  where
    (
        novka.fecha_ini between to_date('$fecha_ini','yyyy-mm-dd') and to_date('$fecha_fin','yyyy-mm-dd')
        or 
        NOVKA.FECHA_FIN between TO_DATE('$fecha_ini','yyyy-mm-dd') and TO_DATE('$fecha_fin','yyyy-mm-dd')
        
        or
        
        TO_DATE('$fecha_ini','yyyy-mm-dd') between novka.fecha_ini and NOVKA.FECHA_FIN
        or 
        TO_DATE('$fecha_fin','yyyy-mm-dd') between novka.fecha_ini and NOVKA.FECHA_FIN
        
        or
        novka.id_periodo =  $id_periodo
    )
    AND novka.num_doc = '$num_doc'
    AND novka.id_tipo_doc = $id_tipo_doc
) 
EOD;
            //Ejecutar SQL
            $recordsKa = CN_TABLE::executeSQL($sql);

            $dias_kardex = $recordsKa[0]['dias'];


            /**
             * Dias de suspension id_nov_ka_susinc - 20190909
             */
            $fecha_fin = $records[0]['fecha_termina'];
            //Sql
            $sql = <<<EOD
select 

DIAS_RANGO_MES_SIN_TREINTAYUNO( 
case when (select fecha_ini from no_periodo where id_periodo = $id_periodo) > nov.fecha_ini then (select fecha_ini from no_periodo where id_periodo = $id_periodo) else nov.fecha_ini end, 
case when nov.fecha_fin > (select fecha_fin from no_periodo where id_periodo = $id_periodo) then (select fecha_fin from no_periodo where id_periodo = $id_periodo) else nov.fecha_fin end, 
(select id_meses from no_periodo where id_periodo = $id_periodo)
) as dias_nov_sus,

(case when (select count(con.id_concepto_periodo) as cant from no_concepto_periodo con 
    where con.num_doc = nov.num_doc and con.periodo = $id_periodo and con.id_concep_nomina = (select id_concep_basica from no_param_concep where id_param_concep = 1) ) > 0 then 1 else 0 end) as concepto_periodo,
(case when (select count(est.id_estado_func) as cant from no_estado_func est where est.num_doc = nov.num_doc and est.periodo = $id_periodo ) > 0 then 1 else 0 end) as estado_func,
nov.* 

from no_novedad_kardex nov

where 
nov.estado = 1
and nov.num_doc = $num_doc 
and nov.id_tip_nov_ka = (select no_param_concep.id_nov_ka_susinc from no_param_concep where no_param_concep.id_param_concep = 1)
and (
    (select fecha_ini from no_periodo where id_periodo = $id_periodo) between nov.fecha_ini and nov.fecha_fin
    or    
    (select fecha_fin from no_periodo where id_periodo = $id_periodo) between nov.fecha_ini and nov.fecha_fin
) 
EOD;
            //Ejecutar SQL
            $recordsKa_sus = CN_TABLE::executeSQL($sql);

            if (count($recordsKa_sus) > 0) {
                $dias_kardex += $recordsKa_sus[0]['dias_nov_sus'];
            }
        }


        /**
         * Calculo de dias de novedad kardex
         */
        $this->logMessage("[Liquidación Cesantias] " . $dias_calc . " - " . $dias_kardex);

        if (($dias_calc - $dias_kardex) > 30) {
            $dias_cesantias = 30;
        } else {
            $dias_cesantias = $dias_calc - $dias_kardex;
        }

        /**
         * Incidente #7746, si tiene prima liquida cesantias mensuales - 20171214
         */
        if ($dias_cesantias == 0) {

            //Sql
            $sql = <<<EOD
select 
liq.* 
from no_liquida_nomina liq

where
liq.num_doc = '$num_doc'
AND liq.id_tipo_doc = $id_tipo_doc
and liq.id_periodo in ( select no_periodo.id_periodo from no_periodo 
                        where no_periodo.id_tipo_periodo in (3,4) 
                        and no_periodo.id_anhos = (select id_anhos from no_periodo where id_periodo = $id_periodo) 
                        and no_periodo.id_meses = (select id_meses from no_periodo where id_periodo = $id_periodo) 
                        )   
EOD;
            //Ejecutar SQL
            $recordsPrima = CN_TABLE::executeSQL($sql);

            if (count($recordsPrima) > 0) {
                $dias_cesantias = 30;
            }
        }

        return $dias_cesantias;
    }

    /**
     * Procesa la liquidacion para el periodo, funcionario y concepto nomina
     * @param type $id_periodo
     * @param type $num_doc
     * @param type $id_tipo_doc
     * @param type $id_concep_nomina
     * @param type $record_liq
     * @param type $arrayConstantes
     */
    private function liquidar($id_periodo, $num_doc, $id_tipo_doc, $id_concep_nomina, $record_liq, $arrayConstantes) {
        $this->logMessage("[Liquidación Cesantias] Liquidar: periodo " . $id_periodo .
                " - funcionario " . $num_doc . " - concepto nomina " . $id_concep_nomina);

        /**
         * Varibles
         */
        $arrayParametros = array();
        $valor_liquidado = 0;
        $fecha_ingreso = $record_liq['fecha_ingreso'];
        $fecha_termina = $record_liq['fecha_termina'];
        $fecha_termina_real = $record_liq['fecha_termina_real'];
        $fecha_retiro = $record_liq['fecha_retiro'];
        $fecha_retiro_real = $record_liq['fecha_retiro_real'];
        $num_dias = $record_liq['num_dias'];
        $retiro_primerdiames = $record_liq['retiro_primerdiames'];

        /*
         * Valor Base y porcentaje
         */
        $porcentaje = 'null';
        $valor_base = 'null';

        /*
         *  Cargar fórmulas por concepto
         */
        //Sql
        $sql = <<<EOD
Select * from no_formula WHERE id_concep_nomina = $id_concep_nomina 
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        /*
         * Valida si posee formula el concepto
         */
        if (count($records) > 0) {
            $this->logMessage("[Liquidación Cesantias] Entro a calcular Formula.");

            foreach ($records as $value) {

                //se adiciona un nuevo campo de formula para completar la retencion que es muy grande el proceso - 20210415::LAVILA
                $formula = $value['formula'] . $value['formula_adic'];
                $this->logMessage("[Liquidación Cesantias] Formula Inicial: " . $formula);


                /*
                 *  Buscar las constantes, variables, fórmulas(parametros) y agrupaciones que use la fórmula
                 */
                //Reemplazo de constantes            
                $formula = $this->reemplazoConstante($formula, $arrayConstantes);
                $this->logMessage("[Liquidación Cesantias] Formula Constante: " . $formula);

                /*
                 * Reemplaza en la consulta los filtros y valores del SQL, que vienen en el record
                 * Ejemplo: select raz_soc from id_cia where id_cia = $id_cia
                 * Reemplaza $id_cia por el valor en el record
                 */
                if ($record_liq['porcentaje'] == '' || $record_liq['porcentaje'] == null) {
                    $record_liq['porcentaje'] = 0;
                }
                $formula = CN_TABLE::reemplazoConsulta($formula, $record_liq);
                $this->logMessage("[Liquidación Cesantias] Formula consulta los filtros: " . $formula);

                /*
                 * Cambio en la formula de A por (C1+C2)
                 */
                $vars = array();

                CN_TABLE::getVarsInFormula($vars, $formula);

//        var_dump($vars);

                foreach ($vars as $var) {
                    if (substr($var, 0, 1) == 'A') {
                        /*
                         * Cambio de A1 por relacion con los conceptos C1
                         * Ejemplo: 'A1' => '0'
                         */
                        $agrup = $this->reemplazoAgrupacion(substr($var, 1));
                        $this->logMessage("[Liquidación Cesantias] Agrupacion: " . $agrup);

                        $formula = str_replace('{' . $var . '}', $agrup, $formula);
                    }
                }
                $this->logMessage("[Liquidación Cesantias] Formula parametrosFormula y reemplazoAgrupacion: " . $formula);


                /*
                 * Parser de la formula para obtener parametros(variables)
                 * Ejemplo: 'A1' => '0',
                 * 'C1' => '0'
                 */
                $arrayParametros = $this->parametrosFormula($formula);


                /*
                 * Obtener resultados de los parametros(variables)
                 * Ejemplo: $arrayParametros = array(
                 * 'C1' => '0',
                 * 'C2' => '0'
                 * );
                 */
                $arrayParametros = $this->resultadoParametros($arrayParametros, $record_liq);


                /*
                 * Reemplazo de parametros(variables) a la formula
                 * Ejemplo: $arrayParametros = array(
                 * 'C1' => '1100',
                 * 'C2' => '55'
                 * );
                 */
                $formula = $this->reemplazoParametros($formula, $arrayParametros);
                $this->logMessage("[Liquidación Cesantias] Formula Final: " . $formula);


                /*
                 * Ejecutar fórmula
                 * Ejemplo: ( 0 == 0 ? {C1} * $porcentaje : false )
                 * Retorna false  si no cumple con la condicion
                 */
                $formula = str_replace('{', ' ', $formula);
                $formula = str_replace('}', ' ', $formula);
                $result = CN_TABLE::aplicarEval($formula);


                /*
                 * No cumple con la condicion
                 */
//                if ($result === false) {
                if ($result == '-9999' || $result == -9999) {
                    $this->logMessage("[Liquidación Cesantias] Formula No cumple con la condicion: " . $formula);
                    $result = 0;
                }


                /*
                 * Acumulan resultados de liquidacion
                 */
                $valor_liquidado += $result;
                /*
                 * Si es por porcentaje
                 */
                if ($record_liq['porcentaje'] != '' || $record_liq['porcentaje'] != null) {
                    /*
                     * Tipo de formula
                     * V - Valor base 
                     * R - Valor restado 
                     * F - Valor de la fórmula (Uso normal)
                     */
                    if ($value['cod_tipo'] == 'V') {
                        $this->logMessage("[Liquidación Cesantias] Formula CodTipo: " . $value['cod_tipo']);

                        /*
                         * Valor Base y porcentaje
                         */
                        $porcentaje = $record_liq['porcentaje'];
                        $valor_base = ($result * 100) / $record_liq['porcentaje'];
                    }
                }
            }
        } else {

            /**
             * Logica de N
             */
            if ($record_liq['caracter'] == 'N') {
                $this->logMessage("[Liquidación Cesantias] Logica de N - Concepto: " . $id_concep_nomina);

                /*
                 * Resta % (se puede para el valor) 
                 */
                //sumar devengados
                //Sql
                $sql = <<<EOD
select 
nvl(sum(liqnom.valor_liquidado),0) as valor_liquidado  
from no_liquida_nomina liqnom
join no_concep_nomina connom
on liqnom.id_concep_nomina = connom.id_concep_nomina
and connom.operador = 1
where
liqnom.id_periodo = $id_periodo
and liqnom.id_tipo_doc = $id_tipo_doc
and liqnom.num_doc = '$num_doc' 
EOD;
                //Ejecutar SQL
                $records_deveng = CN_TABLE::executeSQL($sql);

                if (count($records_deveng) > 0) {

                    $devengado = $records_deveng[0]['valor_liquidado'];

                    //obtener porcentaje de max_ded_noley
                    $devengado_por = ($devengado * $max_ded_noley) / 100;

                    /*
                     * Si es por porcentaje
                     */
                    if ($record_liq['porcentaje'] != '' || $record_liq['porcentaje'] != null) {

                        $valor_logica_n = (0 * $record_liq['porcentaje']) / 100;
                    } else {
                        $valor_logica_n = $record_liq['valor'];
                    }

                    //Validar resta - operar
                    if (($devengado_por - $valor_logica_n - $valor_sumatoria_logica_n) <= 0) {

                        $valor_liquidado = $valor_logica_n;
                        $valor_sumatoria_logica_n += $valor_liquidado;
                    } else {

                        $valor_liquidado = 0;
                    }
                } else {

                    $this->logMessage("[Liquidación Cesantias] No hay valor devengados.");
                    $valor_liquidado = 0;
                }
            } else {
                /*
                 * La liquidación se hacer por 2 espacios temporales:
                 *
                 * - Mensual
                 * En cuyo caso, todos los meses tienen una duración de 30 días
                 * - Por días calendario
                 * En cuyo caso se hace por la cantidad de días especificada en no_concepto_periodo.num_dias
                 * 
                 * Esta especificación, si se hace mensual o usando los días, lo especifica la variable no_concep_nomina.dias_calendario
                 * 
                 * Si se hace una interrupción en un concepto, digamos algún cargo temporal, debe liquidarse el valor del concepto asÍ: 
                 * Ejemplo: $valor = ($valor_liquidado_concepto_mes/30)*$num_dias
                 */

                /*
                 * Si es por porcentaje y diferente de 0
                 */
                if (($record_liq['porcentaje'] != '' || $record_liq['porcentaje'] != null) && $record_liq['porcentaje'] != 0) {
                    $this->logMessage("[Liquidación Cesantias] Calcular porcentaje - " . $record_liq['porcentaje']);


                    //Sql
                    $sql = <<<EOD
select * from no_liquida_nomina 
where id_concep_nomina = (select id_concep_basica from no_param_concep where id_param_concep = 1)
and id_periodo = $id_periodo
and id_tipo_doc = $id_tipo_doc
and num_doc = '$num_doc' 
EOD;
                    //Ejecutar SQL
                    $records = CN_TABLE::executeSQL($sql);

                    if (count($records) <= 0) {
                        $records[0]['valor_liquidado'] = 0;
                    }

                    //Resultado del calculo de porcentaje
                    $result = ($records[0]['valor_liquidado'] * $record_liq['porcentaje']) / 100;

                    /*
                     * Valor Base y porcentaje
                     */
                    $porcentaje = $record_liq['porcentaje'];
                    $valor_base = $records[0]['valor_liquidado'];
                } else {
                    $this->logMessage("[Liquidación Cesantias] Calcular valor - " . $record_liq['valor']);

                    if (!is_null($record_liq['num_dias'])) {

                        /*
                         * usa_dias_calen
                         */
                        if ($record_liq['usa_dias_calen'] == 0) { //Mensual
                            $num_dias = 30;
                            $num_dias = $record_liq['num_dias']; // ? Revisar
                        } else { //Por días calendario
                            $num_dias = $record_liq['num_dias'];
                        }

                        $result = ($record_liq['valor'] / 30) * $num_dias;
                    } else {
                        $num_dias = 'null';
                        $result = $record_liq['valor'];
                    }
                }

                $valor_liquidado += $result;
            }
        }

        /**
         * Registro de liquida nomina por concepto 
         */
        /*
         * Valida creacion de registro
         */
        if ($valor_liquidado >= 0) {

            $this->logMessage("[Liquidación Cesantias] El valor liquidado es: " . $valor_liquidado);

            /*
             * validar que se retira el primer dia del mes - 20150219
             * si es el primer dia del mes no liquida ningun valor - 20150312
             */
            if ($retiro_primerdiames) {
                $fecha_termina = $fecha_termina_real;
                $fecha_retiro = $fecha_retiro_real;
                $valor_liquidado = 0;
            }

            /**
             * mes y año anterior al periodo liquidado - 20150219
             */
            $sql = <<<EOD
select * from no_periodo where id_periodo = $id_periodo 
EOD;

            //Ejecuta sql
            $per = CN_TABLE::executeSQL($sql);
            $anho = $per[0]['id_anhos'];
            $mes = $per[0]['id_meses'];

            $saldosAnt = CN_TABLE::fechaAnterior($anho, $mes);

            $anho_ant = $saldosAnt['id_anhos'];
            $mes_ant = $saldosAnt['id_meses'];

            //obtener registros de consulta
            $sql = <<<EOD
select  
                    
nvl( 
(case when to_date( '$fecha_termina', 'yyyy-mm-dd') is not null then

(select nvl(sum(liq2.valor_liquidado),0) 
from no_liquida_nomina liq2
join no_periodo_v per3 on per3.id_periodo = liq2.id_periodo
where 
per3.id_anhos =  $anho_ant
and per3.id_meses =  $mes_ant
and liq2.num_doc = '$num_doc' and liq2.id_tipo_doc = $id_tipo_doc
and liq2.id_concep_nomina = 20)

else 0 end)
, 0) as valor_consolidado_ant,
                    
nvl( 
(case when to_date( '$fecha_termina', 'yyyy-mm-dd') is not null then

(select nvl(sum(liq2.valor_liquidado),0) 
from no_liquida_nomina liq2
join no_periodo_v per3 on per3.id_periodo = liq2.id_periodo
where 
per3.id_anhos =  per.id_anhos
and per3.id_meses =  per.id_meses
and liq2.num_doc = '$num_doc' and liq2.id_tipo_doc = $id_tipo_doc
and liq2.id_concep_nomina = 20)

else 0 end)
, 0) as valor_consolidado,

nvl(
(case when to_date( '$fecha_termina', 'yyyy-mm-dd') is not null then
(select nvl(sum(valor_liquidado),0) 
from no_cesantia ces2
join no_periodo_v per2 on per2.id_periodo = ces2.id_periodo
where 
per2.id_anhos || lpad(per2.id_meses , 2, '0') between per.id_anhos || '01' and per.id_anhos || lpad(per.id_meses , 2, '0')
and ces2.num_doc = '$num_doc' and ces2.id_tipo_doc = $id_tipo_doc
and ces2.CONSOLIDADO = 0 ) + $valor_liquidado 
else 0 end)
, 0)  as valor_aplica,
     
-- validar si se retiro el siguiente mes(1 del mes)   
case when  to_date( '$fecha_retiro', 'yyyy-mm-dd') = (per.fecha_fin + 1) then 1 else 0 end as retiro_mes                   
                    

from no_periodo_v per

where 
per.id_periodo = $id_periodo    
EOD;

            /*
             * ejecuta y obtiene el resultado del sql
             */

            $resultado_ajuste = CN_TABLE::executeSQL($sql);

            $valor_consolidado = $resultado_ajuste[0]['valor_consolidado'];
            $valor_aplicado = $resultado_ajuste[0]['valor_aplica'];
            $retiro_mes = $resultado_ajuste[0]['retiro_mes'];

            /*
             * validar que se retira el primer dia del mes - 20150219
             * Incidente #34593, si el valor es 0 toma el del mes actual, ya que los retiran en el mes que solo tiene 1 dia - 20230221
             */
            if ($retiro_primerdiames) {
                if ($resultado_ajuste[0]['valor_consolidado_ant'] != 0 && $anho_ant == $anho) {
                    $valor_consolidado = $resultado_ajuste[0]['valor_consolidado_ant'];
                }
            }


            /*
             * INCI:Los valores negativos del ajuste se restan al valor_liquidado - 20130729
             */
            $this->logMessage("[Liquidación Cesantias] El valor_consolidado :: $valor_consolidado - valor_aplicado :: $valor_aplicado");
            if (($valor_consolidado - $valor_aplicado) < 0) {
                $this->logMessage("[Liquidación Cesantias] Resta valor_consolidado :: " . ($valor_consolidado - $valor_aplicado));
                if (($valor_liquidado + ($valor_consolidado - $valor_aplicado)) > 0) {
                    $this->logMessage("[Liquidación Cesantias] Suma valor_consolidado :: " . ($valor_liquidado + ($valor_consolidado - $valor_aplicado)));
                    $valor_ajuste = 0;
                    $valor_liquidado = $valor_liquidado + ($valor_consolidado - $valor_aplicado);
                    $valor_aplicado = $valor_consolidado; //Se igualan valores - 20140811
                } else {
                    $this->logMessage("[Liquidación Cesantias] Resta else valor_consolidado :: " . ($valor_consolidado - $valor_aplicado));
                    $valor_ajuste = $valor_consolidado - $valor_aplicado;
                }
            } else {
                $valor_ajuste = $valor_consolidado - $valor_aplicado;
            }


            //Validar que los dias son positivos o cero
            if ($num_dias < 0) {
                $num_dias = 0;
            }


            /*
             * $retiro_mes - validar si se retiro el siguiente mes(1 del mes) - 20150202
             */
            if ($retiro_mes == 1) {
                $fecha_retiro = '';
                $valor_consolidado = 0;
                $valor_aplicado = 0;
                $valor_ajuste = 0;
            }

            $valor_liquidado_base = round($valor_liquidado) * 12;

            /**
             * Para las personas con novedad de kardex id-8, se coloca en base 1000 - 20151002
             */
            /**
             * Personas con novedad Suspensión por Incapacidad no_param_concep id 13-Suspensión por Incapacidad,
             * Se crea en estado funcionario y el registro en concepto_periodo - 20150312
             */
            $sql = <<<EOD
select 
(case when (select count(con.id_concepto_periodo) as cant from no_concepto_periodo con 
    where con.num_doc = nov.num_doc and con.periodo = $id_periodo and con.id_concep_nomina = (select id_concep_basica from no_param_concep where id_param_concep = 1) ) > 0 then 1 else 0 end) as concepto_periodo,
(case when (select count(est.id_estado_func) as cant from no_estado_func est where est.num_doc = nov.num_doc and est.periodo = $id_periodo ) > 0 then 1 else 0 end) as estado_func,
nov.* 

from no_novedad_kardex nov

where 
nov.estado = 1
and nov.num_doc = $num_doc 
and nov.id_tip_nov_ka = (select no_param_concep.id_nov_ka_susinc from no_param_concep where no_param_concep.id_param_concep = 1)
and (
    (select fecha_ini from no_periodo where id_periodo = $id_periodo) between nov.fecha_ini and nov.fecha_fin
    or    
    (select fecha_fin from no_periodo where id_periodo = $id_periodo) between nov.fecha_ini and nov.fecha_fin
)
EOD;
            $results_nov = CN_TABLE::executeSQL($sql);

            if (count($results_nov) > 0) {
                $valor_liquidado_base = 1000;
            }

            /*
             * Se realiza que force valor base a 1000 - 20210315::LAVILA
             */
            if ($valor_liquidado == 0 && $valor_liquidado_base == 0) {
                $valor_liquidado_base = 1000;
            }


            /*
             * Crear nueva liquidación
             * 
             * Asignar valores encontrados en persona
             */
            //insert into no_cesantia (id_cesantia,id_periodo,id_tipo_doc,num_doc,id_concep_nomina,
            //valor_liquidado,num_dias,fecha_ingreso,fecha_termina,valor_base,
            //valor_consolidado, valor_aplicado, valor_ajuste) 
            //values ('1','43','1','1015408219','425','100','1',null,null,null,
            //0,0,0);
            //Sql
            $sql = <<<EOD
insert into no_cesantia (id_periodo,id_tipo_doc,num_doc,id_concep_nomina,
valor_liquidado,num_dias,fecha_ingreso,fecha_termina,valor_base,
valor_consolidado, valor_aplicado, valor_ajuste, consolidado) 
values ($id_periodo,$id_tipo_doc,'$num_doc', $id_concep_nomina,
            round($valor_liquidado),$num_dias, 
                to_date('$fecha_ingreso','yyyy-mm-dd'), to_date('$fecha_retiro','yyyy-mm-dd'), 
                    round($valor_liquidado_base),
                    round($valor_consolidado), round($valor_aplicado), round($valor_ajuste), 0 )  
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);
        } else {

            $this->logMessage("[Liquidación Cesantias] El valor_liquidado es menor a cero.");
        }
    }

    /**
     * Reemplaza en la formula las constantes por valores de la tabla NO_CONSTANTE
     * Ejemplo: $con_1
     * @param type $formula
     * @param type $arrayConstantes
     */
    private function reemplazoConstante($formula, $arrayConstantes) {

        /*
         * Recorrer array de Constantes
         */
        foreach ($arrayConstantes as $key => $value) {

            $formula = str_replace($key, $value['valor'], $formula);
        }

        return $formula;
    }

    /**
     * Reemplaza los parametros(variables) a la formula
     * Ejemplo: $key: C1 / $value: valor - 2+5
     * @param type $formula
     * @param type $arrayParametros
     */
    private function reemplazoParametros($formula, $arrayParametros) {

        /*
         * Recorrer array de Parametros
         */
        foreach ($arrayParametros as $key => $value) {

            $formula = str_replace('{' . $key . '}', $value, $formula);
        }

        return $formula;
    }

    /**
     * Obtener resultados de los parametros(variables)
     * Ejemplo: 'C1' => '0'
     * @param type $arrayParametros
     * @param type $record_liq
     */
    private function resultadoParametros($arrayParametros, $record_liq) {

        /*
         * Recorrer array de Parametros
         */
        foreach ($arrayParametros as $key => $value) {

            //Sacar caracter y numero(id_concep_nomina) para consulta
            $caracter = substr($key, 0, 1);
            $id_concep_nomina = substr($key, 1);
            $this->logMessage("[Liquidación Cesantias] Caracter: " . $caracter . ", numero: " . $id_concep_nomina);

            /*
             * Obtener consulta por caracter
             */
            //Sql
            $sql = <<<EOD
select * from NO_CONSULTA where caracter = '$caracter' 
EOD;
            //Ejecutar SQL
            $record = CN_TABLE::executeSQL($sql);

            //Validar registros SQL
            if (count($record) > 0) {

                $consulta = $record[0]['consulta'];

                //Reemplazo de id_concep_nomina
                $consulta = str_replace('$id_concep_nomina', $id_concep_nomina, $consulta);

                /*
                 * Reemplaza en la consulta los filtros y valores del SQL, que vienen en el record
                 * Ejemplo: select raz_soc from id_cia where id_cia = $id_cia
                 * Reemplaza $id_cia por el valor en el record
                 */
                $consulta = CN_TABLE::reemplazoConsulta($consulta, $record_liq);

                /*
                 * Ejecutar SQL de consulta
                 */
                //Sql
                $sql = <<<EOD
$consulta  
EOD;
                //Ejecutar SQL
                $record = CN_TABLE::executeSQL($sql);

                //Validar registros SQL
                if (count($record) > 0) {
                    $valor = $record[0]['valor'];
                } else {
                    $valor = 0;
                }
            } else {
                $valor = 0;
            }

            $arrayParametros[$key] = $valor;
        }

        return $arrayParametros;
    }

    /**
     * Parser de la formula para obtener parametros(variables)
     * Ejemplo: 'C1' => '0'
     * @param type $formula
     * @param type $arrayParametros
     */
    private function parametrosFormula($formula) {

        $vars = array();

        CN_TABLE::getVarsInFormula($vars, $formula);

        foreach ($vars as $var) {
            $arrayParametros[$var] = 0;
        }

//        var_dump($arrayParametros);
//        exit();
//        $arrayParametros = array(
//            'C1' => '0',
//            'C2' => '0',
//            'T1' => '0',
//            'A1' => '0'
//        );

        return $arrayParametros;
    }

    /**
     * Reemplaza las agrupaciones por los parametros(variables)
     * Ejemplo: A1 -> (+C1-C2-T1)
     * @param type $id_agrup_var
     */
    private function reemplazoAgrupacion($id_agrup_var) {

        $agrup = '( ';

        /*
         * Ejecutar SQL de agrupciones
         */
        //Sql
        $sql = <<<EOD
select 
agru.*,
agru.tipo_valor as caracter
from
no_agrup_deta agru
where agru.id_agrup_concepto = $id_agrup_var  
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        /*
         * Recorrer registros 
         */
        foreach ($records as $value) {

            $operador = ($value['operador'] == 1 ? '+' : '-');

            //Concatenar todas las agrupaciones
            $agrup .= $operador . '{' . $value['caracter'] . $value['id_concep_nomina'] . '}';
        }

        $agrup .= ' )';

        return $agrup;
    }

}
