<?php

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

    /**
     * Liquidacion de la nomina
     * tag. 1 otras nominas 0 nomina del retroactivo
     * tag_retro. 1 cuando debe tomar todo lo del mes incluyendo el retro
     *
     * @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");

        $records = array();
        $arrayConstantes = array();
        /*
         * Variable para optimizar consultas de formulas en las liquidaciones - 20140117
         */
        $vals_calc = array();

        /**
         * 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);

        try {

            /*
             * (SGC-1, ANM-2, SGR-3, CYC-4, COL-5, INCI-6, LOCAL-7)
             */
            $array = sfYaml::load(dirname(__FILE__) . '/../../../config/app-gwt.yml');

            $int = 0;
            foreach ($array as $routeName => $routeData) {
                //echo $routeName . "\n";
                if ('entidad_cliente' == $routeName) {
                    foreach ($routeData as $key => $value) {
                        //echo $value . "\n";
                        if ($key == 'value') {
                            $entidadCliente = $value;
                        }
                    }
                }
                $int++;
            }

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


            //Sql
            $sql = <<<EOD
select 
definitivo as definitivo,
fecha_ini as fecha_desde_tipter,
fecha_fin as fecha_hasta_tipter,
id_anhos as id_anhos_tipter,
id_meses as id_meses_tipter, 
nvl(id_tipo_periodo,0) as id_tipo_periodo 
from no_periodo 
    where id_periodo = $id_periodo 
EOD;
            //Ejecutar SQL
            $record_tipper = CN_TABLE::executeSQL($sql);
            $definitivo = $record_tipper[0]['definitivo'];
            $id_tipo_periodo = $record_tipper[0]['id_tipo_periodo'];
            $id_anhos_tipter = $record_tipper[0]['id_anhos_tipter'];
            $id_meses_tipter = $record_tipper[0]['id_meses_tipter'];
            $fecha_desde_tipter = $record_tipper[0]['fecha_desde_tipter'];
            $fecha_hasta_tipter = $record_tipper[0]['fecha_hasta_tipter'];

            /**
             * Incidente #10608 - 20181213
             */
            if ($definitivo == 1) {
                throw new Exception('El periodo a liquidar ya esta bloqueado.');
            }



            /**
             * Consultar salario minimo
             * Se cambia a vigencia el periodo del filtro - 20140403
             * (select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = extract(year from sysdate))  
             */
            $salario_minimo = 550000;
            //Sql
            $sql = <<<EOD
(select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = (select id_anhos from no_periodo where id_periodo = $id_periodo ))  
EOD;
            //Ejecutar SQL
            $record_smlv = CN_TABLE::executeSQL($sql);

            if (count($record_smlv) > 0) {
                $salario_minimo = $record_smlv[0]['valor_mensual'];
            }

            /*
             * Obtener consultas glodal
             */
            //Sql
            $sql = <<<EOD
select * from NO_CONSULTA 
EOD;
            //Ejecutar SQL
            $record_consul = CN_TABLE::executeSQL($sql);
            $record_consulta = array();

            if (count($record_consul) > 0) {
                foreach ($record_consul as $key => $value) {
                    $record_consulta[$value['caracter']] = $value;

//                    $this->logMessage("Caracter - " . $value['caracter']);
                }
            }
//            $this->logMessage("Consulta - " . $record_consulta['M']['consulta']);
//            die();


            /**
             * 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['valor'];
//                $this->logMessage($value['reemplazo'] . "------------------------" . $arrayConstantes[$value['reemplazo']]);
            }

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

            /*
             * Iniciar en 0 dias de liquidacion y totales de vacaciones - 20131216
             */
            $dias_liq = 0;
            $wdiasv_tot = 0;


            //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_LIQUIDA_NOMINA tab0 WHERE tab0.id_periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);


            /**
             * Validacion de afiliación a fondos - 20181003
             */
            $sql = <<<EOD
SELECT
--tab0.num_doc
LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_pen
FROM (
    SELECT distinct 
    id_tipo_doc,
    num_doc
    FROM no_concepto_periodo
    where
    periodo = $id_periodo
) tab0

left join no_afilia_fondo tab1 
on tab1.id_tipo_doc = tab0.id_tipo_doc
and tab1.num_doc = tab0.num_doc
and tab1.id_clase_fondo in (1)
and tab1.estado = 1

where
1 = 1
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab1.estado is null
                    
and tab0.num_doc not in (
    SELECT
    num_doc
    FROM no_pension_func where no_pension_func.estado = 1
)                   
EOD;
            //Ejecutar SQL
            $records_pen = CN_TABLE::executeSQL($sql);
            $num_doc_pen = "";
            if (count($records_pen) > 0 && $records_pen[0]['num_doc_pen'] != null) {
                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();

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

                $num_doc_pen = $records_pen[0]['num_doc_pen'];
                throw new Exception('El o los usuarios(' . $num_doc_pen . ') no tienen afiliación a fondo de Pensión.');
            }

            $sql = <<<EOD
SELECT
--tab0.num_doc
LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_sal
FROM (
    SELECT distinct 
    id_tipo_doc,
    num_doc
    FROM no_concepto_periodo
    where
    periodo = $id_periodo
) tab0

left join no_afilia_fondo tab1 
on tab1.id_tipo_doc = tab0.id_tipo_doc
and tab1.num_doc = tab0.num_doc
and tab1.id_clase_fondo in (2)
and tab1.estado = 1

where
1 = 1
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab1.estado is null
EOD;
            //Ejecutar SQL
            $records_sal = CN_TABLE::executeSQL($sql);
            $num_doc_sal = "";
            if (count($records_sal) > 0 && $records_sal[0]['num_doc_sal'] != null) {
                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();

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

                $num_doc_sal = $records_sal[0]['num_doc_sal'];
                throw new Exception('El o los usuarios(' . $num_doc_sal . ') no tienen afiliación a fondo de Salud.');
            }


            /**
             * Validacion de liquidacion de concepto periodo a fondos - 20181116
             */
            $sql = <<<EOD
select
LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_pen
from(

    SELECT distinct
    tab0.num_doc,
    --conper.id_concepto_periodo,
    max(concep.id_concep_nomina) as id_concep_nomina
    --LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_pen
    FROM (
        SELECT distinct 
        tab0.id_tipo_doc,
        tab0.num_doc
        FROM no_concepto_periodo tab0
        join no_periodo perd
        on tab0.periodo = perd.id_periodo
        where
        tab0.periodo = $id_periodo
        and perd.id_tipo_periodo = 1
    ) tab0
    
    left join no_concepto_periodo conper
    on tab0.id_tipo_doc = conper.id_tipo_doc
    and tab0.num_doc = conper.num_doc
    and conper.periodo = $id_periodo
    
    left join no_concep_nomina concep
    on conper.id_concep_nomina = concep.id_concep_nomina
    and concep.id_clase_fondo = 1
    
    where
    1 = 1
    $whereFuncionarioNumDoc $whereFuncionarioTipoDoc
    
    group by
    tab0.num_doc

)tab0

where
tab0.id_concep_nomina is null
            
and tab0.num_doc not in (
    SELECT
    num_doc
    FROM no_pension_func where no_pension_func.estado = 1
)     
            
and tab0.num_doc not in (
    25282982
)                 
EOD;
            //Ejecutar SQL
            $records_pen = CN_TABLE::executeSQL($sql);
            $num_doc_pen = "";
            if (count($records_pen) > 0 && $records_pen[0]['num_doc_pen'] != null) {
                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();

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

                $num_doc_pen = $records_pen[0]['num_doc_pen'];
                throw new Exception('El o los usuarios(' . $num_doc_pen . ') no tienen registro de liquidación a fondo de Pensión.');
            }

            $sql = <<<EOD
select
LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_sal
from(

    SELECT distinct
    tab0.num_doc,
    --conper.id_concepto_periodo,
    max(concep.id_concep_nomina) as id_concep_nomina
    --LISTAGG(tab0.num_doc, ',') WITHIN GROUP (ORDER BY tab0.num_doc)  as num_doc_sal
    FROM (
        SELECT distinct 
        tab0.id_tipo_doc,
        tab0.num_doc
        FROM no_concepto_periodo tab0
        join no_periodo perd
        on tab0.periodo = perd.id_periodo
        where
        tab0.periodo = $id_periodo
        and perd.id_tipo_periodo = 1
    ) tab0
    
    left join no_concepto_periodo conper
    on tab0.id_tipo_doc = conper.id_tipo_doc
    and tab0.num_doc = conper.num_doc
    and conper.periodo = $id_periodo
    
    left join no_concep_nomina concep
    on conper.id_concep_nomina = concep.id_concep_nomina
    and concep.id_clase_fondo = 2
    
    where
    1 = 1
    $whereFuncionarioNumDoc $whereFuncionarioTipoDoc
    
    group by
    tab0.num_doc

)tab0

where
tab0.id_concep_nomina is null      
            
and tab0.num_doc not in (
    25282982
)              
EOD;
            //Ejecutar SQL
            $records_sal = CN_TABLE::executeSQL($sql);
            $num_doc_sal = "";
            if (count($records_sal) > 0 && $records_sal[0]['num_doc_sal'] != null) {
                /*
                 * COMMIT DE TODAS LAS TRANSACCIONES
                 */
                $this->conn->commit();

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

                $num_doc_sal = $records_sal[0]['num_doc_sal'];
                throw new Exception('El o los usuarios(' . $num_doc_sal . ') no tienen registro de liquidación a fondo de Salud.');
            }

            /*
             * Tomar valores de NO_AJUSTE_NOMINA
             */
            //Sql
            $sql = <<<EOD
Insert into NO_LIQUIDA_NOMINA (ID_TIPO_DOC,NUM_DOC,ID_CONCEP_NOMINA,ID_PERIODO,VALOR_LIQUIDADO,FECHA_DESDE,FECHA_HASTA,NUM_DIAS,VALOR_BASE,PORCENTAJE,NUM_DIAS_BASE) 

select 
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_concep_nomina,
tab0.id_periodo,
tab0.valor_ajuste,
 to_date( '01/' || per.id_meses || '/' || per.id_anhos, 'dd/mm/yyyy')  as fecha_desde,
TRUNC(LAST_DAY( to_date(per.id_meses || '/' || per.id_anhos, 'mm/yyyy')  )) as fecha_hasta,
tab0.num_dias,
tab0.valor_base,
tab0.porcentaje,
tab0.num_dias_base
                    
from no_ajuste_nomina tab0
join no_periodo per
on per.id_periodo = tab0.id_periodo 
WHERE tab0.id_periodo = $id_periodo 
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);


            /**
             * Se filtran para vacaciones dias de periodos adicionales - 20140613
             * Dias de vacaciones solo se toman del periodo de la nomina liquidada - 20171010
             */
            //Sql
            $sql = <<<EOD
select 
to_char(listagg(id_periodo,',') within group (order by id_periodo)) as  periodos
from no_periodo
where id_anhos = (select id_anhos from no_periodo where id_periodo = $id_periodo )
and id_meses = (select id_meses from no_periodo where id_periodo = $id_periodo )
--and id_tipo_periodo in (1 , 2)  
and id_periodo = $id_periodo                    
EOD;
            //Ejecutar SQL
            $record_per = CN_TABLE::executeSQL($sql);
            $periodos = $record_per[0]['periodos'];


            /*
             * Cargar Periodo-Funcionario-Concepto
             * 
             * Cargar Funcionarios
             * 
             * Para cada persona
             * 
             * Cargar conceptos que apliquen en periodo para la persona, en orden de ejecución
             */
            /*
             * Se modificó la formula de liquidación de Vacaciones,  colocando la condición de Bonificación por servicios.  
             * Por lo tanto se debe verificar que el orden de concpetos para liquidación de la nómina los conceptos 1007, 1008, 1009 y 1010   
             * se liquiden despues del concpeto 1011 - 20130812
             * Se cambia calculo de dias por FECHA_RANGO_SIN_TREINTAYUNO para no tomar los dias 31 en wdiasv - 20130913
             * El orden para tomar los 4000 primero - 20140616
             * Dias num ant para las novedades de incapacidad - 20150224
             * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
             * Se agrega para los dias wdiasv, que tome reintegros, y opere dias - 20161207
             */
            //Sql
            $sql = <<<EOD
select 
conka.id_concep_ka,
novka.id_novedad_kardex,
nvl(novka.num_dias_ant,0) as num_dias_ant,
$salario_minimo as salario_minimo,
1 as tag,
0 as tg_retro,
tab0.*,
tab0.num_dias as dias_liq,
nvl(vac.dias_vac,0) as wdiasv,
tipcon.orden,
connom.codigo,
connom.usa_dias_calen
from no_concepto_periodo tab0

join no_concep_nomina connom
on connom.id_concep_nomina = tab0.id_concep_nomina

join no_tipo_concepto tipcon
on tipcon.id_tipo_concepto = connom.id_tipo_concepto

left join no_concep_ka conka
on conka.id_concep_nomina = tab0.id_concep_nomina

left join no_novedad_kardex novka
on novka.id_tipo_doc = tab0.id_tipo_doc
and novka.num_doc = tab0.num_doc
and novka.id_periodo = tab0.periodo
and novka.id_tip_nov_ka = conka.id_tip_nov_ka
and novka.estado = 1
and novka.fecha_ini = tab0.fecha_desde
and novka.fecha_fin = tab0.fecha_hasta
                    
left join (

    select 
    novvac.id_tipo_doc,                  
    novvac.num_doc,
    nvl(sum(dias_rango_mes(novvac.fecha_ini,novvac.fecha_fin,(select id_meses 
     from no_periodo where id_periodo =  $id_periodo))),0) as dias,
    nvl(sum( novvac.fecha_fin - novvac.fecha_ini + 1),0) as num_dias_vac,
    --nvl(sum(FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin)),0) as dias_vac
    nvl(sum(     
    case when tipnov.operador = 1 
    then FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin)
    else FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin) * (-1) end    
    ),0) as dias_vac
    from no_novedad_vac novvac
    left join no_tipo_nov_vac tipnov on tipnov.id_tipo_nov_vac = novvac.id_tipo_nov_vac
    where tipnov.tiempo_liqui = 1 and tipnov.operador in (0,1) and novvac.id_periodo in ( $periodos )
    group by novvac.id_tipo_doc, novvac.num_doc
     
)vac
on vac.id_tipo_doc = tab0.id_tipo_doc and vac.num_doc = tab0.num_doc

where tab0.periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab0.id_concep_nomina != (select id_concep_rete from no_param_concep where id_param_concep = 1)
and tipcon.id_tipo_concepto != 4
                    
order by 
tab0.id_anhos,
tab0.id_meses,
tab0.id_tipo_doc,
tab0.num_doc,
--tipcon.orden,
case 
  when connom.codigo >= 4000  
      then '0000'
  when connom.id_concep_nomina = (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)  
      then '0001'
      else connom.codigo 
  end ,
tipcon.orden
--connom.codigo 
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);


            /*
             * Recorre los registros de funcionario - concepto nomina
             * para ser liquidados
             */
            $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] nom_conceptos_a_procesar: " . $nom_conceptos_a_procesar);
            $logPath = sfConfig::get('sf_log_dir') . '/liquidacion.log';
            $custom_logger = new sfFileLogger(new sfEventDispatcher(), array('file' => $logPath));
            foreach ($records as $value) {

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

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

                $id_periodo = $value['periodo'];
                $num_doc = $value['num_doc'];
                $id_tipo_doc = $value['id_tipo_doc'];
                $id_concep_nomina = $value['id_concep_nomina'];

                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");

                /*
                 * Liquidar periodo-funcionario-concepto nomina
                 */
                $this->liquidar($id_periodo, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta);

                // Termina procesamiento de concepto
//                file_put_contents('/home/lavila/Escritorio/liquidacion.log', "Procesado $i de $nom_conceptos_a_procesar conceptos.\n", FILE_APPEND);
                $i++;
//                if ($num_doc == '10292794') {
//                    MemcacheHandler::getInstance()->set($progress_key, 80);
//                    break;
//                }
            }
            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - Termino Mencache.\n");
            MemcacheHandler::getInstance()->set($progress_key, 80);



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


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


            /**
             * Reliquidar FSP
             * Se toman conceptos segun la Tabla NO_FONDO_CONCEPTO para el id_descuento_ss = 2 
             */
            /**
             * Consultar salario minimo
             * Se cambia a vigencia el periodo del filtro - 20140403
             * (select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = extract(year from sysdate))  
             */
            $salario_minimo = 550000;
            //Sql
            $sql = <<<EOD
(select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = (select id_anhos from no_periodo where id_periodo = $id_periodo ))  
EOD;
            //Ejecutar SQL
            $record_smlv = CN_TABLE::executeSQL($sql);

            if (count($record_smlv) > 0) {
                $salario_minimo = $record_smlv[0]['valor_mensual'];
            }

            $valor_base = 0;

            /*
             * Se toman conceptos segun la 
             * Tabla NO_FONDO_CONCEPTO para el id_descuento_ss = 2 
             * Se agrega tag y periodo para la consulta de R - 20131216
             * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
             */
            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - Proceso de FSP.\n");
            //Sql
            $sql = <<<EOD
select 
$salario_minimo as salario_minimo,
1 as tag,
0 as tg_retro,
$id_periodo as periodo,                    
tab0.* 
from no_liquida_nomina tab0
left join no_fondo_concepto foncon
on tab0.id_concep_nomina = foncon.id_concep_nomina
where foncon.id_descuento_ss = 2
and tab0.id_periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
order by 
tab0.id_tipo_doc,
tab0.num_doc
EOD;

            //Ejecutar SQL
            $record_fsp = CN_TABLE::executeSQL($sql);

            $i = 0;
            $nom_conceptos_a_procesar = count($record_fsp);
            /**
             * Incidente #5032, Se coloca para nominas adicionales conceptos de deducciones, solo mensuales, mas abajo esta para las adicionales - 20190528
             */
            if ($id_tipo_periodo != 2) {
                foreach ($record_fsp as $value) {

                    $id_liquida_nomina = $value['id_liquida_nomina'];
                    $valor_base = $value['valor_liquidado'];
                    $valor_base_vac = 0;
                    $num_doc = $value['num_doc'];
                    $id_tipo_doc = $value['id_tipo_doc'];
                    $num_dias_fsp = $value['num_dias'];
                    $id_concep_nomina = $value['id_concep_nomina'];

                    $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - FSP - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");

                    //Dias para vacaciones
                    //Se habilita novedvac para el periodo a liquidar - filtro id_periodo - 20130722 Se deshablita - 20130723
                    //Toma los dias de vacaciones para el mes a liquidar - 20130723
                    //Sql
                    $sql = <<<EOD
select  nvl(num_dias_vac,0) as dias_vac from (    
    select 
    novvac.id_tipo_doc,                  
    novvac.num_doc,
    nvl(sum(dias_rango_mes(novvac.fecha_ini,novvac.fecha_fin,(select id_meses 
        from no_periodo where id_periodo =  $id_periodo))),0) as dias,
    nvl(sum( novvac.fecha_fin - novvac.fecha_ini + 1),0) as dias_vac,

    nvl(sum( 
        case when TIPNOV.operador = 1
        then DIAS_RANGO_MES_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo))
        else DIAS_RANGO_MES_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo)) * (-1)
        end     
    ),0) as num_dias_vac

    from no_novedad_vac novvac
      left join NO_TIPO_NOV_VAC TIPNOV on TIPNOV.ID_TIPO_NOV_VAC = NOVVAC.ID_TIPO_NOV_VAC
      where TIPNOV.TIEMPO_LIQUI = 1 
      --and NOVVAC.ID_PERIODO = $id_periodo
      and (
              novvac.fecha_ini 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') )) 
              or
              novvac.fecha_fin 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') )) 

              or        


              to_date('01/'|| (select lpad(id_meses,2,'0') ||'/'||id_anhos from no_periodo where id_periodo = $id_periodo) ,'dd/mm/yyyy') between novvac.fecha_ini and novvac.fecha_fin
              or
              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') )) between novvac.fecha_ini and novvac.fecha_fin
     )
      and novvac.NUM_DOC = $num_doc
      group by novvac.id_tipo_doc, novvac.num_doc
)
EOD;

                    //Ejecutar SQL
                    $record_vac = CN_TABLE::executeSQL($sql);
                    /*
                     * Calcular IBC para vacaciones
                     */
                    // Se agrega al calculo la formula (({A39}/30)*$wdiasv)) - 20130517
                    // Toma los dias de vacaciones para el mes a liquidar
                    $wdiasv = 0;
                    if (count($record_vac) > 0) {
                        $wdiasv = $record_vac[0]['dias_vac'];
                    }

                    $formula = "(({A39}/30)*$wdiasv)";
                    $this->logMessage("[Liquidación Vac] Formula Inicial: " . $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 Vac] Agrupacion: " . $agrup);

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

                    $arrayParametros = $this->parametrosFormula($formula);
                    $arrayParametros = $this->resultadoParametros($arrayParametros, $value, $record_consulta, $vals_calc);

                    $formula = $this->reemplazoParametros($formula, $arrayParametros);
                    /*
                     * 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 Vac] Formula No cumple con la condicion: " . $formula);
                        $result = 0;
                    }
                    //Valor base de IBC vacaciones
                    $valor_base_vac = round($result, -3);
                    $this->logMessage("[Liquidación Vac] Valor base de IBC vacaciones: " . $valor_base_vac);
                    //Valor base no puede superar 25 salarios minimos - 20151019
                    /* if ($valor_base_vac > ($salario_minimo * 25)) {
                      $valor_base_vac = round(($salario_minimo * 25) - 1, -3);
                      $this->logMessage("[Liquidación Vac] Valor base no puede superar 25 salarios minimos: " . $valor_base_vac);
                      } */

                    /*
                     * Valor base formula FSP
                     */
                    $valor_base = round($valor_base, -3);
//                $valor_base = round($valor_base);
                    //valor base no puede superar 25 salarios minimos
                    if ($valor_base > ($salario_minimo * 25)) {
                        $valor_base = round(($salario_minimo * 25) - 1, -3);
//                    $valor_base = round(($salario_minimo * 25) - 1);
                    }


                    /*
                     * Variables del concepto 1 asignacion basica para los dias de liquidacion y totales de vacaciones - 20131216
                     * Anexo de conceptos de enfermedad por el tipo de novedad que causa liquidacion - 20131217
                     * Se agrega filtro de vacaciones para que tome novedad por la fecha y no solo el periodo - 20140526 
                     * Se quita condicion anterior - 20140605
                     * Se agregan periodos adicionales para el periodo filtrado, para que tenga en cuenta los dias de vac - 20150123 Revisar Gloria Amparo
                     * Se agrega para los dias wdiasv, que tome reintegros, y opere dias - 20161207
                     */
                    //Sql
                    $sql = <<<EOD
select 
tab0.id_tipo_doc,
tab0.num_doc,
--tab0.id_concep_nomina,
--sum(tab0.num_dias) as dias_liq,
sum(case when connom.operador = 1 then tab0.num_dias else tab0.num_dias*(-1) end ) as dias_liq,
max(nvl(vac.dias_vac,0)) as wdiasv

from no_concepto_periodo tab0

join no_concep_nomina connom
on connom.id_concep_nomina = tab0.id_concep_nomina

join no_tipo_concepto tipcon
on tipcon.id_tipo_concepto = connom.id_tipo_concepto
                    
left join (
    
    select 
    novvac.id_tipo_doc,                  
    novvac.num_doc,
    nvl(sum(dias_rango_mes(novvac.fecha_ini,novvac.fecha_fin,(select id_meses 
        from no_periodo where id_periodo =  $id_periodo))),0) as dias,
    nvl(sum( novvac.fecha_fin - novvac.fecha_ini + 1),0) as num_dias_vac,
    --nvl(sum(FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin)),0) as dias_vac
    nvl(sum(     
    case when tipnov.operador = 1 
    then FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin)
    else FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin) * (-1) end    
    ),0) as dias_vac 
                        
    from no_novedad_vac novvac
    left join no_tipo_nov_vac tipnov on tipnov.id_tipo_nov_vac = novvac.id_tipo_nov_vac
    where tipnov.tiempo_liqui = 1 and tipnov.operador in (0,1) and novvac.id_periodo in ( $periodos )
    /*                    
    and (    
             novvac.id_periodo = $id_periodo
              or
             novvac.fecha_ini 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') )) 
             or
             novvac.fecha_fin 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') )) 

             or        

             to_date('01/'|| (select lpad(id_meses,2,'0') ||'/'||id_anhos from no_periodo where id_periodo = $id_periodo) ,'dd/mm/yyyy') between novvac.fecha_ini and novvac.fecha_fin
             or
             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') )) between novvac.fecha_ini and novvac.fecha_fin
    )
    */
    group by novvac.id_tipo_doc, novvac.num_doc

)vac
on vac.id_tipo_doc = tab0.id_tipo_doc and vac.num_doc = tab0.num_doc

where tab0.periodo = $id_periodo
and tab0.num_doc = $num_doc
and tab0.id_tipo_doc = $id_tipo_doc

and ( 
  tab0.id_concep_nomina in (select id_concep_rein from no_concep_nomina where id_concep_nomina = (select no_param_concep.ID_CONCEP_BASICA from no_param_concep where id_param_concep = 1)) 
  or tab0.id_concep_nomina in (select id_concep_ajuste from no_concep_nomina where id_concep_nomina = (select no_param_concep.ID_CONCEP_BASICA from no_param_concep where id_param_concep = 1)) 
  or  tab0.id_concep_nomina = (select no_param_concep.ID_CONCEP_BASICA from no_param_concep where id_param_concep = 1) 
  or tab0.id_concep_nomina in (SELECT DISTINCT
    kar.ID_CONCEP_NOMINA 
    FROM NO_CONCEP_KA kar
    join NO_TIP_NOV_KA tipkar
    on tipkar.ID_TIP_NOV_KA = kar.ID_TIP_NOV_KA
    where tipkar.CAUSA_LIQUIDACION = 1) 
)
                        
and tipcon.id_tipo_concepto != 4
             
group by
tab0.id_tipo_doc,
tab0.num_doc
    --,tab0.id_concep_nomina  
EOD;
                    //Ejecutar SQL
                    $record_smlv = CN_TABLE::executeSQL($sql);

                    if (count($record_smlv) > 0) {
                        $dias_liq = $record_smlv[0]['dias_liq'];
                        $wdiasv_tot = $record_smlv[0]['wdiasv'];
                    }

                    //Anexo dias totales y de vacaciones totales - 20131217
                    $array_valor_base = $this->valor_base_fsp($valor_base, $salario_minimo, $valor_base_vac, $wdiasv_tot, $dias_liq, $num_doc, $id_periodo);
                    $valor_fsp = $array_valor_base['valor_fsp'];
                    $porcentaje_fsp = $array_valor_base['porcentaje_fsp'];

                    /**
                     * SQL de consulta para validar si el concepto de FSP es por ajuste - 20131129
                     */
                    //Sql
                    $sql = <<<EOD
select 
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_concep_nomina,
tab0.id_periodo,
tab0.valor_ajuste,
 to_date( '01/' || per.id_meses || '/' || per.id_anhos, 'dd/mm/yyyy')  as fecha_desde,
TRUNC(LAST_DAY( to_date(per.id_meses || '/' || per.id_anhos, 'mm/yyyy')  )) as fecha_hasta,
tab0.num_dias
from no_ajuste_nomina tab0
join no_periodo per
on per.id_periodo = tab0.id_periodo 
WHERE tab0.id_periodo = $id_periodo 
and tab0.NUM_DOC = $num_doc
and tab0.id_concep_nomina = $id_concep_nomina
EOD;

                    //Ejecutar SQL
                    $record_fsp_ver = CN_TABLE::executeSQL($sql);

                    /*
                     * Validar si el FSP es por ajuste - 20131129
                     */
                    if (count($record_fsp_ver) == 0) {
                        $this->logMessage("[Liquidación] Valor base del FSP::" . $valor_fsp);
                        if ($valor_fsp > 0) {

                            /*
                             * Actualizar valores de FSP
                             */
                            //sentencia sql
                            $sql = <<<EOD
update NO_LIQUIDA_NOMINA set valor_liquidado =  $valor_fsp
        , porcentaje = $porcentaje_fsp
            , valor_base = round( valor_liquidado, -3 ) 
    where id_liquida_nomina = $id_liquida_nomina 
        and id_periodo = $id_periodo
EOD;
                            //ejecuta y obtiene el resultado del sql
                            CN_TABLE::executeSQL($sql);
                        } else {

                            /*
                             * Borrar del FSP
                             */
                            //sentencia sql
                            $sql = <<<EOD
delete from NO_LIQUIDA_NOMINA 
    where id_liquida_nomina = $id_liquida_nomina 
and id_periodo = $id_periodo
EOD;
                            //ejecuta y obtiene el resultado del sql
                            CN_TABLE::executeSQL($sql);
                        }
                    } else {

                        $valor_ajuste = $record_fsp_ver[0]["valor_ajuste"];

                        /*
                         * Borrar del FSP que no estan en la tabla de ajustes - 20140515
                         */
                        //sentencia sql
                        $sql = <<<EOD
delete from NO_LIQUIDA_NOMINA where id_liquida_nomina = $id_liquida_nomina 
and id_periodo = $id_periodo
and valor_liquidado != $valor_ajuste
EOD;
                        //ejecuta y obtiene el resultado del sql
                        CN_TABLE::executeSQL($sql);
                    }


                    $i++;

                    /*
                     * Iniciar en 0 dias de liquidacion y totales de vacaciones - 20131216
                     */
                    $dias_liq = 0;
                    $wdiasv_tot = 0;
                }
            }
            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - FSP - Termino Mencache.\n");
            MemcacheHandler::getInstance()->set($progress_key, 90);



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


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



            /*
             * Inicio del proceso de calculo de Retencion en la fuente concepto 2001
             * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
             * Solo retefunte
             * Incidente #6468 <-> Se agrega valor_bonif - 20170613
             * Se agregan los que tienen procedimiento 1, solo para la mensual -  20171219
             * Se agrega distinct en consulta procedimiento 1, ya que estaba duplicando registros - 20180117
             * Se coloca para los concepots de no_concepto_periodo no tome func de procedimiento 1 - 20180816
             */
            /** 20181212
             * Según comunicación telefónica con la Dra. Luz Elena Rodriguez , la retenci+on en la fuente para el mes de diciembre debe:
              1.- PROCEDIMIENTO 2: Se recalcula todo el mes con la prima y se descuenta lo aplicado en la prima -> la agrupacion 7 debe tener
              2.- PROCEDIMIENTO 1: NO se recalcula con la PRIMA de NAVIDAD, es decir se liquida solo con la nómina mensual.
             */
            //Sql
            $sql = <<<EOD
select 
$salario_minimo as salario_minimo,
1 as tag,
1 as tg_retro,
nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt,  
nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif,                      
tab0.*,
tab0.num_dias as dias_liq,
tipcon.orden,
connom.codigo,
connom.usa_dias_calen

from (
    select
    tab0.id_concepto_periodo,
    tab0.id_anhos,
    tab0.id_meses,
    tab0.periodo,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.id_concep_nomina,
    tab0.fecha_desde,
    tab0.fecha_hasta,
    tab0.valor,
    tab0.porcentaje,
    tab0.num_dias,
    tab0.id_periodo_ajuste
    from no_concepto_periodo tab0
    where tab0.periodo = $id_periodo
    and tab0.num_doc not in (  
         select distinct 
          aut.num_doc
          from (
               SELECT
               aut.*,
               ROW_NUMBER() OVER (
                partition by aut.num_doc
                ORDER BY aut.ESTADO desc, aut.ID_NOVEDAD_PROCED_RETE desc
               ) AS rn
              from no_novedad_proced_rete aut
          )aut
          left join no_nombramiento_v nom
          on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc
          where
          aut.id_tipo_proced_rete = 1 
          and aut.rn = 1
          and (
            aut.estado = 1 
            or (
                aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
            )
          )
    )
    
    union
    
    select     
    rownum as id_concepto_periodo,
    id_anhos,
    id_meses,
    periodo,
    id_tipo_doc,
    num_doc,
    id_concep_nomina,
    fecha_desde,
    fecha_hasta,
    valor,
    porcentaje,
    num_dias,
    id_periodo_ajuste
    
    from(
        select distinct 
        --rownum id_concepto_periodo,
        per.id_anhos as id_anhos,
        per.id_meses as id_meses,
        per.id_periodo as periodo,
        aut.id_tipo_doc,
        aut.num_doc,
        param.id_concep_rete as id_concep_nomina,
        per.fecha_ini as fecha_desde,
        per.fecha_fin as fecha_hasta,
        null as valor,
        1 as porcentaje,
        30 as num_dias,
        per.id_periodo as id_periodo_ajuste,
        per.id_tipo_periodo,
        aut.id_tipo_proced_rete

        from (
               SELECT
               aut.*,
               ROW_NUMBER() OVER (
                partition by aut.num_doc
                ORDER BY aut.ESTADO desc, aut.ID_NOVEDAD_PROCED_RETE desc
               ) AS rn
              from no_novedad_proced_rete aut
        )aut

        left join no_nombramiento_v nom
        on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc

        left join no_periodo per
        on per.id_periodo = $id_periodo

        left join no_param_concep param
        on param.id_param_concep = 1

        where
        aut.id_tipo_proced_rete = 1 
        and aut.rn = 1    
        and (
            aut.estado = 1
            or (
                aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  
                    and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
            ) 
        )
    )
    where
    id_tipo_periodo = 1 
    and id_tipo_proced_rete = 1
)tab0                    

join no_concep_nomina connom
on connom.id_concep_nomina = tab0.id_concep_nomina

join no_tipo_concepto tipcon
on tipcon.id_tipo_concepto = connom.id_tipo_concepto

where tab0.periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab0.id_concep_nomina = (select id_concep_rete from no_param_concep where id_param_concep = 1)
and tab0.porcentaje > 0

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


            /*
             * Recorre los registros de funcionario - concepto nomina
             * para ser liquidados
             */
            $i = 0;
            $nom_conceptos_a_procesar = count($records);
            foreach ($records as $value) {
                $this->logMessage("[Liquidación] Existen liquidaciones - RETE.");

                $id_periodo_rete = $value['periodo'];
                $num_doc = $value['num_doc'];
                $id_tipo_doc = $value['id_tipo_doc'];
                $id_concep_nomina = $value['id_concep_nomina'];


                $i++;
                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");

                /*
                 * Liquidar periodo-funcionario-concepto nomina
                 */
                $this->liquidar($id_periodo_rete, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta);

//                if ($num_doc == '39537708') {
//                    MemcacheHandler::getInstance()->set($progress_key, 80);
//                    break;
//                }
            }

            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE - Termino Mencache.\n");
            MemcacheHandler::getInstance()->set($progress_key, 95);


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



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



            /*
             * RETENCION CONTINGENTE - 20191128
             * Se deja quemado por ahora el id agrupacion (114-APORTES VOLUNTARIOS-AFC LIQ RETEN) para no tener en cuenta
             * 
             * Inicio del proceso de calculo de Retencion en la fuente concepto 2001
             * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
             * Solo retefunte
             * Incidente #6468 <-> Se agrega valor_bonif - 20170613
             * Se agregan los que tienen procedimiento 1, solo para la mensual -  20171219
             * Se agrega distinct en consulta procedimiento 1, ya que estaba duplicando registros - 20180117
             * Se coloca para los concepots de no_concepto_periodo no tome func de procedimiento 1 - 20180816
             */
            /** 20181212
             * Según comunicación telefónica con la Dra. Luz Elena Rodriguez , la retenci+on en la fuente para el mes de diciembre debe:
              1.- PROCEDIMIENTO 2: Se recalcula todo el mes con la prima y se descuenta lo aplicado en la prima -> la agrupacion 7 debe tener
              2.- PROCEDIMIENTO 1: NO se recalcula con la PRIMA de NAVIDAD, es decir se liquida solo con la nómina mensual.
             */
            //Sql
            $sql = <<<EOD
select 
$salario_minimo as salario_minimo,
1 as tag,
1 as tg_retro,
nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt,  
nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif,                      
tab0.*,
tab0.num_dias as dias_liq,
tipcon.orden,
connom.codigo,
connom.usa_dias_calen

from (
    select
    tab0.id_concepto_periodo,
    tab0.id_anhos,
    tab0.id_meses,
    tab0.periodo,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.id_concep_nomina,
    tab0.fecha_desde,
    tab0.fecha_hasta,
    tab0.valor,
    tab0.porcentaje,
    tab0.num_dias,
    tab0.id_periodo_ajuste
    from no_concepto_periodo tab0
    where tab0.periodo = $id_periodo
    and tab0.num_doc not in (  
         select distinct 
          aut.num_doc
          from (
               SELECT
               aut.*,
               ROW_NUMBER() OVER (
                partition by aut.num_doc
                ORDER BY aut.ESTADO desc, aut.ID_NOVEDAD_PROCED_RETE desc
               ) AS rn
              from no_novedad_proced_rete aut
          )aut
          left join no_nombramiento_v nom
          on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc
          where
          aut.id_tipo_proced_rete = 1 
          and aut.rn = 1
          and (
            aut.estado = 1 
            or (
                aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
            )
          )
    )
    
    union
    
    select     
    rownum as id_concepto_periodo,
    id_anhos,
    id_meses,
    periodo,
    id_tipo_doc,
    num_doc,
    id_concep_nomina,
    fecha_desde,
    fecha_hasta,
    valor,
    porcentaje,
    num_dias,
    id_periodo_ajuste
    
    from(
        select distinct 
        --rownum id_concepto_periodo,
        per.id_anhos as id_anhos,
        per.id_meses as id_meses,
        per.id_periodo as periodo,
        aut.id_tipo_doc,
        aut.num_doc,
        param.id_concep_rete as id_concep_nomina,
        per.fecha_ini as fecha_desde,
        per.fecha_fin as fecha_hasta,
        null as valor,
        1 as porcentaje,
        30 as num_dias,
        per.id_periodo as id_periodo_ajuste,
        per.id_tipo_periodo,
        aut.id_tipo_proced_rete

        from (
               SELECT
               aut.*,
               ROW_NUMBER() OVER (
                partition by aut.num_doc
                ORDER BY aut.ESTADO desc, aut.ID_NOVEDAD_PROCED_RETE desc
               ) AS rn
              from no_novedad_proced_rete aut
        )aut

        left join no_nombramiento_v nom
        on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc

        left join no_periodo per
        on per.id_periodo = $id_periodo

        left join no_param_concep param
        on param.id_param_concep = 1

        where
        aut.id_tipo_proced_rete = 1 
        and aut.rn = 1    
        and (
            aut.estado = 1
            or (
                aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  
                    and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
            ) 
        )
    )
    where
    id_tipo_periodo = 1 
    and id_tipo_proced_rete = 1
)tab0                    

join no_concep_nomina connom
on connom.id_concep_nomina = tab0.id_concep_nomina

join no_tipo_concepto tipcon
on tipcon.id_tipo_concepto = connom.id_tipo_concepto

where tab0.periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab0.id_concep_nomina = (select id_concep_rete from no_param_concep where id_param_concep = 1)
and tab0.porcentaje > 0
and tab0.num_doc in (SELECT DISTINCT num_doc FROM no_concepto_periodo where id_concep_nomina in (SELECT id_concep_nomina FROM no_agrup_deta where id_agrup_concepto = 114) and periodo = $id_periodo)                    

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


            /*
             * Recorre los registros de funcionario - concepto nomina
             * para ser liquidados
             */
            $i = 0;
            $nom_conceptos_a_procesar = count($records);
            foreach ($records as $value) {
                $this->logMessage("[Liquidación] Existen liquidaciones - RETE CONTINGENTE.");

                $id_periodo_rete = $value['periodo'];
                $num_doc = $value['num_doc'];
                $id_tipo_doc = $value['id_tipo_doc'];
                $id_concep_nomina = $value['id_concep_nomina'];


                /*
                 * Liquidar periodo-funcionario-concepto nomina
                 */
                //CYC: Valor y base extra rete contingente - 20191128
                $this->liquidar($id_periodo_rete, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta, 1);

                $i++;
                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE CONTINGENTE - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");

//                if ($num_doc == '39537708') {
//                    MemcacheHandler::getInstance()->set($progress_key, 80);
//                    break;
//                }
            }

            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE CONTINGENTE - Termino Mencache.\n");
            MemcacheHandler::getInstance()->set($progress_key, 98);


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



            /**
             * NOM-113 <-> COL::Retención en la fuente procedimientos - 20150429
             */
            $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
            $this->conn->beginTransaction();

            /*
             * Recorrer todos los funcionarios que aplican RETENCION MINIMA (Si), aun si estan retirados en el mes
             * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
             * Se valida que sea solo periodo mensual, y que posea registro en concepto periodo - 20150713
             * Incidente #2561 Las personas marcadas como DECLARANTES, tengan o no porcentaje de retención, 
             * tambien los pase siempre por la comparación con retención mínima. - 20160211
             * Incidente #6468 <-> Se agrega valor_bonif - 20170613
             */
            //Para CYC, todos aplican rete minima - 20161212
            $texto_declara = "tab0.declara_renta,";
            $filtro_declara = "and declara_renta = 1";
            if ($entidadCliente == 4) {
                $texto_declara = "1 as declara_renta,";
                $filtro_declara = " ";
            }
            //Sql
            $sql = <<<EOD
select 
(select no_param_concep.id_concep_rete from no_param_concep where no_param_concep.id_param_concep=1) as id_concep_rete,
$salario_minimo as salario_minimo,
1 as tag,
1 as tg_retro,
$id_periodo as id_periodo,
$id_periodo as periodo,     
(select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo) as vig_ini,
(select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo) as vig_fin,
(select no_periodo.id_meses from no_periodo where id_periodo = $id_periodo) as per_ini,
(select no_periodo.id_meses from no_periodo where id_periodo = $id_periodo) as per_fin,
nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt,
nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif, 
nvl( (select valor_liquidado from no_liquida_nomina where id_periodo = $id_periodo and NUM_DOC = tab0.NUM_DOC and id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1 )) , -1) as rete,
tab0.id_novedad_proced_rete,
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_tipo_proced_rete,
--tab0.id_periodo,
tab0.observacion,
tab0.fecha_inicial,
tab0.fecha_terminacion,
$texto_declara
tab0.estado ,
null as porcentaje  
from (

  select 
  aut.*,
   ROW_NUMBER() OVER (
    partition by aut.num_doc
    ORDER BY aut.id_novedad_proced_rete desc
   ) AS rn
  from no_novedad_proced_rete aut
  left join no_nombramiento_v nom
  on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc
  where
  aut.estado = 1 
  or (
    aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
  )

)tab0
where
tab0.rn = 1
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and (SELECT no_periodo.id_tipo_periodo FROM no_periodo where id_periodo = $id_periodo)  = 1  
and tab0.num_doc in (
    select distinct 
    num_doc 
    from no_concepto_periodo
    where
    periodo = $id_periodo
    and id_concep_nomina = (select no_param_concep.id_concep_rete from no_param_concep where no_param_concep.id_param_concep = 1)
    and nvl(porcentaje,0 ) > 0
                        
    union

    select 
    num_doc 
    from no_novedad_proced_rete
    where estado = 1
    $filtro_declara
)
                    
order by 
tab0.fecha_inicial, tab0.id_novedad_proced_rete                          
EOD;
            //Ejecutar SQL
//            $record_nov = CN_TABLE::executeSQL($sql);
            $i = 0;
            //$nom_conceptos_a_procesar = count($record_nov);

            /**
             * Se inactiva calculo retencion minima, por norma nueva de 2017 - 201703016
             */
//            foreach ($record_nov as $value) {
//                $valor_reten_minima = 0;
//                $this->logMessage("[Liquidación] Existen liquidaciones - RETE MINIMA.");
//
//                $id_periodo_min = $value['periodo'];
//                $num_doc = $value['num_doc'];
//                $id_tipo_doc = $value['id_tipo_doc'];
//                $id_tipo_proced_rete = $value['id_tipo_proced_rete'];
//                $id_concep_nomina_for = $id_concep_rete = $value['id_concep_rete'];
//                $declara_renta = $value['declara_renta'];
//                $estado = $value['estado'];
//                $rete = $value['rete'];
//                $valor_uvt = $value['valor_uvt'];
//                $porcentaje = 0;
//                $num_dias = 30;
//                $valor_base = 0;
//
//                $tag = $value['tag'];
//                $tg_retro = $value['tg_retro'];
//
//
//                /**
//                 * Obtener el valor antes de liquidacion del concepto de retencion, para la validacion de reteminima, 
//                 * se usa consulta T, del 2001, menos el periodo que se liquida - 20150717
//                 */
//                //Sql
//                $sql = <<<EOD
//select sum(valor) as valor , sum(valor_min) as valor_min 
//from(
//    select 
//    nvl(sum(liqnom.valor_liquidado),0) as valor,  
//    nvl(sum(liqnom.valor_liquidado),0) as valor_min  
//    from no_liquida_nomina liqnom   
//        join no_periodo per on per.id_periodo = liqnom.id_periodo 
//    where    1 = 1 
//        and per.id_meses = ( select id_meses from no_periodo where id_periodo = $id_periodo)  
//        and per.id_anhos = ( select id_anhos from no_periodo where id_periodo = $id_periodo)
//        and per.id_periodo != $id_periodo               
//    and liqnom.num_doc = $num_doc  and liqnom.id_tipo_doc = $id_tipo_doc  
//    and liqnom.id_concep_nomina in ( (select id_concep_rete from no_param_concep where id_param_concep = 1) )
//    and( 
//        ($tag = 1 and (id_periodo_ajuste is null or $tg_retro = 1) ) 
//            or 
//        ($tag = 0 and (  id_periodo_ajuste = nvl('$id_periodo',null) or (id_periodo_ajuste is not null and $tg_retro = 1)  )  ) 
//    ) 
//    
//    union
//    
//    select 
//    nvl(sum(liqnom.valor_liquidado),0) * (-1) as valor,  
//    0 as valor_min    
//    from no_liquida_nomina liqnom   
//        join no_periodo per on per.id_periodo = liqnom.id_periodo 
//    where    1 = 1 
//        and per.id_meses = ( select id_meses from no_periodo where id_periodo = $id_periodo)  
//        and per.id_anhos = ( select id_anhos from no_periodo where id_periodo = $id_periodo)
//        and per.id_periodo = $id_periodo               
//    and liqnom.num_doc = $num_doc  and liqnom.id_tipo_doc = $id_tipo_doc  
//    and liqnom.id_concep_nomina in ( ( select nvl(id_concep_rein,ID_CONCEP_NOMINA) as id_concep from no_concep_nomina where id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1) ) )
//    and( 
//        ($tag = 1 and (id_periodo_ajuste is null or $tg_retro = 1) ) 
//            or 
//        ($tag = 0 and (  id_periodo_ajuste = nvl('$id_periodo',null) or (id_periodo_ajuste is not null and $tg_retro = 1)  )  ) 
//    )  
//
//)  
//EOD;
//                //Ejecutar SQL
//                $records_ini = CN_TABLE::executeSQL($sql);
//                $valor_reten_minima_ini = $records_ini[0]['valor'];
//                $valor_reten_minima_ini_min = $records_ini[0]['valor_min'];//Solo concepto 2001, no de reintegro - 20161213
//
//
//
//                //si declara renta
//                if ($declara_renta == 1) {
//                    $custom_logger->info("Funcionario: " . $num_doc . " - RETE MINIMA - SI Declara Renta\n");
//
//                    //Incidente #4034, validacion de devengados en el periodo - 20160721
//                    //Sql
//                    $sql = <<<EOD
//select par.id_agrup_deven as valor from no_param_concep par where par.id_param_concep = 1
//EOD;
//                    //Ejecutar SQL
//                    $records_param = CN_TABLE::executeSQL($sql);
//                    $valor_reten_minima_param = $records_param[0]['valor'];
//
//                    //Formula quemada - 20150501 
//                    $formula = "( {A" . $valor_reten_minima_param . "} > 0 ? ({A7}+{A101}+{A102})/(" . $valor_uvt . ") : -9999 )";
//
//                    //ejecuta formula de la retencion para conocer el porcentaje
//                    //Se agrega tipo proced rete, para que lo tenga encuenta para la retencion - 20161214
//                    $pago_uvt = $this->ejecutarFormula($formula, $arrayConstantes, $value, $record_consulta, $vals_calc, $id_concep_nomina_for, $id_tipo_proced_rete, $id_concep_rete);
//                    $valor_base = $pago_uvt = round($pago_uvt, 2);
//                    $custom_logger->info("Pago_uvt: " . $pago_uvt . "\n");
//
//                    //Con el $pago_uvt ubicar en tabla retencion minima y calcular valor segun rete_uvt
//                    //Ticket 3672, validacion de tope tasa marginal - 20160616
//                    //Sql
//                    $sql = <<<EOD
//select  
//(select 
//max(rete_uvt) as tasa_marginal
//from no_retencion_minima
//where
//id_anhos = reten.id_anhos) as tasa_marginal,
//reten.* 
//from no_retencion_minima reten
//where 
//reten.id_anhos = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)
//and $pago_uvt between reten.uvt_desde and reten.uvt_hasta
//order by
//reten.rete_uvt                        
//EOD;
//                    //Ejecutar SQL
//                    $record_reten = CN_TABLE::executeSQL($sql);
//                    if (count($record_reten) > 0) {
//                        $rete_uvt = $record_reten[0]['rete_uvt'];
//                        $tasa_marginal = $record_reten[0]['tasa_marginal'];
//
//                        if ($rete_uvt > 0) {
//
//                            /**
//                             * Ticket 3672, validacion de tope tasa marginal,
//                             * aplicar formula (pago Menzualizado*0,27)-135,17* valor UVT - 20160616
//                             */
//                            if ($rete_uvt >= $tasa_marginal) {
//                                $custom_logger->info("Entro a validacion de tope tasa marginal\n");
//                                $valor_reten_minima = round(((($pago_uvt * 0.27) - 135.17) * $valor_uvt), 0);
//                            } else {
//                                $valor_reten_minima = round(($valor_uvt * $rete_uvt), 0);
//                            }
//
//                            $custom_logger->info("Rete_uvt: " . $rete_uvt . " - Valor_reten_minima: " . $valor_reten_minima . " - Rete: " . $rete . "\n");
//                            $custom_logger->info("Valor_reten_minima_ini: " . $valor_reten_minima_ini . "\n");
//
//                            /*
//                             * actualizar o crear nuevo registro en liquidacion
//                             * redondeo al mil - 20150717
//                             */
//                            if ($rete == -1) {
//
//                                //Borra concepto de reintegro de retencion - 20161212
//                                //sentencia sql
//                                $sql = <<<EOD
//delete from no_liquida_nomina
//where
//num_doc = $num_doc and id_tipo_doc = $id_tipo_doc
//and id_periodo = $id_periodo
//and id_concep_nomina in ( ( select nvl(id_concep_rein,ID_CONCEP_NOMINA) as id_concep from no_concep_nomina where id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1) ) ) 
//EOD;
//                                //ejecuta y obtiene el resultado del sql
//                                CN_TABLE::executeSQL($sql);
//
//                                //Si da negativo pone concepto de ajuste - 20160719
//                                if ($valor_reten_minima >= $valor_reten_minima_ini) {
//
//                                    //sentencia sql
//                                    $sql = <<<EOD
//insert into no_liquida_nomina (id_tipo_doc, num_doc, id_concep_nomina,
//        id_periodo,valor_liquidado,
//            fecha_desde,fecha_hasta,num_dias, valor_base, porcentaje ) 
//        values ( $id_tipo_doc, '$num_doc', (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1), 
//        $id_periodo, round( $valor_reten_minima - $valor_reten_minima_ini_min, -3), 
//        (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo ), (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ),
//            nvl('$num_dias',null), $valor_base , $porcentaje ) 
//EOD;
//                                    //ejecuta y obtiene el resultado del sql
//                                    CN_TABLE::executeSQL($sql);
//                                } else {
//
//                                    //sentencia sql
//                                    $sql = <<<EOD
//insert into no_liquida_nomina (id_tipo_doc, num_doc, id_concep_nomina,
//        id_periodo,valor_liquidado,
//            fecha_desde,fecha_hasta,num_dias, valor_base, porcentaje ) 
//        values ( $id_tipo_doc, '$num_doc', ( select nvl(id_concep_rein,ID_CONCEP_NOMINA) as id_concep from no_concep_nomina where id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1) ), 
//        $id_periodo, round( ($valor_reten_minima - $valor_reten_minima_ini_min) * (-1) , -3), 
//        (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo ), (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ),
//            nvl('$num_dias',null), $valor_base , $porcentaje ) 
//EOD;
//                                    //ejecuta y obtiene el resultado del sql
//                                    CN_TABLE::executeSQL($sql);
//                                }
//                            } else {
//                                if ($valor_reten_minima > ($rete + $valor_reten_minima_ini)) {//solo si es mayor al valor del concepto 2001
//                                    //sentencia sql
//                                    $sql = <<<EOD
//update no_liquida_nomina liq set liq.valor_liquidado = round( $valor_reten_minima - $valor_reten_minima_ini_min, -3) , valor_base = $valor_base
//where 
//liq.NUM_DOC = $num_doc
//and liq.id_periodo = $id_periodo
//and liq.id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1) 
//EOD;
//                                    //ejecuta y obtiene el resultado del sql
//                                    CN_TABLE::executeSQL($sql);
//                                }
//                            }
//                        }
//                    }
//                } else {
//                    $custom_logger->info("Funcionario: " . $num_doc . " - RETE MINIMA - NO Declara Renta\n");
//                }
//
//
//                $i++;
//                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE MINIMA - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");
//            }
            MemcacheHandler::getInstance()->set($progress_key, 99);
            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE MINIMA - Termino Mencache.\n");

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


            /**
             * Solo CEV Privada, solo mensual y en enero - 20200114
             * Aplica para DEDNOLEY
             */
            if ($entidadCliente == 8 && $id_tipo_periodo == 1 && $id_meses_tipter == 1) {

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

                $this->logMessage("[Liquidación] Liquidaciones INICIO - INTERES CESANTIAS.");

                /*
                 * Calculo cesantias intereses - 20200113
                 * id-18 quemado por id del CEV privada
                 * se agregas dias de consolidado
                 */
                $sql = <<<EOD
select distinct 
18 as id_concep_nomina,
(SELECT
    max(id_periodo)
    FROM no_periodo
    where
    id_anhos = $id_anhos_tipter - 1
    and id_meses = 12
    and id_tipo_periodo = 1) as periodo_ces,
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_periodo,
ces.num_dias as dias_liq, 
tab0.id_periodo_ajuste,
per.fecha_ini as fecha_desde,
per.fecha_fin as fecha_hasta,
ces.num_dias as num_dias,
12 as porcentaje

FROM no_liquida_nomina tab0

left join no_concep_nomina concep 
ON concep.id_concep_nomina = tab0.id_concep_nomina

join no_periodo per
on per.id_periodo = tab0.id_periodo
                        
left join(
    
    SELECT
    ces.id_tipo_doc,
    ces.num_doc,
    sum(ces.num_dias) as num_dias
    FROM no_cesantia ces

    where
    ces.id_periodo = (
        SELECT
        max(id_periodo)
        FROM no_periodo
        where
        id_anhos = $id_anhos_tipter - 1
        and id_meses = 12
        and id_tipo_periodo = 1
    )
    and ces.consolidado = 1
    
    group by
    ces.id_tipo_doc,
    ces.num_doc
                        
)ces                       
on ces.id_tipo_doc =  tab0.id_tipo_doc                       
and ces.num_doc =  tab0.num_doc

where 
tab0.id_periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc  
and concep.id_tipo_concepto = 1
--and tab0.id_concep_nomina in (SELECT no_param_concep.id_concep_basica FROM no_param_concep) 
EOD;
                //Ejecutar SQL
                $records = CN_TABLE::executeSQL($sql);

                //recorre num_doc y nov vac
                foreach ($records as $value) {

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

                    $id_periodo_ces = $value['periodo_ces'];
                    $id_periodo = $value['id_periodo'];
                    $num_doc = $value['num_doc'];
                    $id_tipo_doc = $value['id_tipo_doc'];
                    $id_concep_nomina = $value['id_concep_nomina'];


                    /*
                     * Liquidar periodo-funcionario-concepto nomina
                     */
                    $this->liquidar($id_periodo, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta, 1);
                }
                $this->logMessage("[Liquidación] Liquidaciones FIN - INTERES CESANTIAS.");

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



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

            /*
             * Validacion de tope de deducidos de no ley - 20140421
             * Valor tope = Sum Deveng por el % de max dednoley - sum dedley 
             * Se cambia Valor tope = Sum Deveng - sum dedley todo por el % de max dednoley   - 20140515
             */
            //Sql
            $sql = <<<EOD
select 

tab.id_tipo_doc, 
tab.num_doc,
tab.id_periodo,
sum(tab.valor_dev) as valor_dev,
sum(tab.VALOR_dedley) as VALOR_dedley,
sum(tab.VALOR_dednoley) as VALOR_dednoley,
sum(tab.VALOR_ded) as VALOR_ded,
max(tab.max_ded_noley) as max_ded_noley,

round( ( ( sum(tab.valor_dev) - sum(tab.VALOR_dedley) ) * max(tab.max_ded_noley) / 100 )  ) as total_tope

from (

    select 
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.id_periodo,
    tab0.num_dias as dias, 
    tab0.id_periodo_ajuste,
    concep.codigo as codigo, 
    concep.descripcion as descripcion, 
    case when concep.id_tipo_concepto = 1 then tab0.valor_liquidado else 0 end as valor_dev, 
    case when concep.id_tipo_concepto = 2 then tab0.valor_liquidado else 0 end as VALOR_dedley, 
    case when concep.id_tipo_concepto = 3 then tab0.valor_liquidado else 0 end as VALOR_dednoley, 
    case when concep.id_tipo_concepto != 1 then tab0.valor_liquidado else 0 end as VALOR_ded,
    per.max_ded_noley
    
    FROM no_liquida_nomina tab0
    
    left join no_concep_nomina concep 
    ON concep.id_concep_nomina = tab0.id_concep_nomina
    
    join no_periodo per
    on per.id_periodo = tab0.id_periodo
    
    where 
    tab0.id_periodo = $id_periodo
    $whereFuncionarioNumDoc $whereFuncionarioTipoDoc      
    
)tab

having
sum(tab.VALOR_dednoley) > round( ( ( sum(tab.valor_dev) - sum(tab.VALOR_dedley) ) * max(tab.max_ded_noley) / 100 )  )

group by
tab.id_tipo_doc, 
tab.num_doc,
tab.id_periodo

order by tab.num_doc
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

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

            foreach ($records as $value) {

                $id_periodo = $value['id_periodo'];
                $num_doc = $value['num_doc'];
                $id_tipo_doc = $value['id_tipo_doc'];
                $total_tope = $value['total_tope'];

                $this->logMessage("[Liquidación] DEDNOLEY - Total_tope: " . $total_tope);
                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - DEDNOLEY - Funcionario: " . $num_doc . " - Total_tope: " . $total_tope . ".\n");

                /*
                 * Obtener registros de deducidos de no ley
                 * Eliminar registros que superen el tope
                 *///Sql
                $sql = <<<EOD
    select 
    tab0.id_liquida_nomina,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.id_periodo,
    tab0.num_dias as dias, 
    tab0.id_periodo_ajuste,
    concep.codigo as codigo, 
    concep.descripcion as descripcion, 
    tab0.valor_liquidado,
    per.max_ded_noley
    
    FROM no_liquida_nomina tab0
    
    left join no_concep_nomina concep 
    ON concep.id_concep_nomina = tab0.id_concep_nomina
    
    join no_periodo per
    on per.id_periodo = tab0.id_periodo
    
    where 
    tab0.id_periodo = $id_periodo 
    and concep.id_tipo_concepto = 3
    and tab0.num_doc = $num_doc     
    and tab0.id_tipo_doc = $id_tipo_doc 
    
    order by tab0.num_doc, concep.codigo
EOD;
                //Ejecutar SQL
                $records_ded = CN_TABLE::executeSQL($sql);

                foreach ($records_ded as $value_ded) {

                    $id_liquida_nomina = $value_ded['id_liquida_nomina'];
                    $valor_liquidado = $value_ded['valor_liquidado'];

                    if ($valor_liquidado > $total_tope) {

                        //sentencia sql
                        $sql = <<<EOD
 delete from no_liquida_nomina tab0
    where tab0.id_periodo = $id_periodo 
    and tab0.id_liquida_nomina = $id_liquida_nomina
    and tab0.num_doc = $num_doc     
    and tab0.id_tipo_doc = $id_tipo_doc 
EOD;
                        //Ejecutar SQL
                        CN_TABLE::executeSQL($sql);
                    } else {

                        $total_tope = $total_tope - $valor_liquidado;
                    }
                }
            }

            $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - DEDNOLEY - Termino.\n");
            MemcacheHandler::getInstance()->set($progress_key, 99);

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


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

            /*
             * Vacaciones de reintegro, se cambia el concepto original por el concepto de reintegro - 20150625
             */
            //Traer novedades de vac del mes de operador negativo y tiempo liquida            
            $sql = <<<EOD
select 
tab0.* 
from no_novedad_vac tab0
left join no_tipo_nov_vac tipnov
on tipnov.id_tipo_nov_vac = tab0.id_tipo_nov_vac
where
tab0.id_periodo = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc   
and tipnov.tiempo_liqui = 1
and tipnov.operador = 0
order by
tab0.num_doc  
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

            //recorre num_doc y nov vac
            foreach ($records as $value) {

                $id_tipo_doc = $value['id_tipo_doc'];
                $num_doc = $value['num_doc'];
                $id_tipo_nov_vac = $value['id_tipo_nov_vac'];
                $fecha_ini = $value['fecha_ini'];
                $fecha_fin = $value['fecha_fin'];

                //Conceptos por el tipo de novedad de vacaciones
                $sql = <<<EOD
select 
tab.*,
(select nvl( no_concep_nomina.id_concep_rein ,tab.id_concep_nomina) from no_concep_nomina where no_concep_nomina.id_concep_nomina = tab.id_concep_nomina ) as id_concep_rein
from no_concep_vac tab
where tab.id_tipo_nov_vac = $id_tipo_nov_vac   
EOD;
                //Ejecutar SQL
                $records_tipnov = CN_TABLE::executeSQL($sql);

                //recorre cada concepto
                foreach ($records_tipnov as $value_tipnov) {

                    $id_concep_nomina = $value_tipnov['id_concep_nomina'];
                    $id_concep_rein = $value_tipnov['id_concep_rein'];

                    //Actualizar cada funcionario-concepto de la liquidacion                
                    $sql = <<<EOD
update no_liquida_nomina set id_concep_nomina = $id_concep_rein  
where num_doc = $num_doc 
and id_concep_nomina = $id_concep_nomina 
and id_periodo = $id_periodo 
and fecha_desde = to_date('$fecha_ini','YYYY-MM-DD')
and fecha_hasta = to_date('$fecha_fin','YYYY-MM-DD') 
EOD;
                    //Ejecutar SQL
                    $this->conn->execute($sql);
                }
            }


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

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

            /**
             * Incidente #5032, Se coloca para nominas adicionales conceptos de deducciones - 20161125
             */
            if ($id_tipo_periodo == 2) {

                //Se agrega filtro de funcionario - 20170303
                //Sql
                $sql = <<<EOD
select distinct tab0.num_doc, tab0.id_tipo_doc 
from no_liquida_nomina tab0
where 
tab0.id_periodo = $id_periodo 
$whereFuncionarioNumDoc    
order by tab0.num_doc  
EOD;
                //Ejecutar SQL
                $records = CN_TABLE::executeSQL($sql);

                foreach ($records as $value) {

                    $num_doc = $value['num_doc'];
                    $id_tipo_doc = $value['id_tipo_doc'];

                    /**
                     * INICIO :: Calculo Salud / Pension Liq Def - 20141014
                     */
                    $this->logMessage("[Liquidación Adicional] Calculo Salud / Pension Liq Def");

                    /*
                     * Traer conceptos por funcionario de salud / pension
                     * Se trae solo conceptos que no esten en concepto_periodo a liquidar, para no generar registro doble por nombramiento - 20170303
                     */
                    $sql = <<<EOD
select distinct
desdet.porcentaje_func,
desdet.porcentaje_patrono,
foncon.id_descuento_ss,
foncon.id_concep_nomina,
afifon.* 
from no_afilia_fondo afifon

join no_fondo_concepto foncon
on foncon.id_mae_fondos = afifon.id_mae_fondos

join no_descto_detalle desdet
on desdet.id_tipo_aporte = afifon.id_tipo_aporte
and foncon.id_descuento_ss = desdet.id_descuento_ss

where
afifon.NUM_DOC = $num_doc
and afifon.estado = 1
and afifon.id_clase_fondo in (1,2)

and foncon.id_concep_nomina not in (
    select conper.id_concep_nomina 
    from no_concepto_periodo conper
    where
    conper.num_doc = $num_doc
    and conper.periodo = $id_periodo
)

order by
afifon.id_clase_fondo     
EOD;
                    //Ejecutar SQL
                    $recordsFondo = CN_TABLE::executeSQL($sql);

                    /**
                     * Recorrer Agrupaciones
                     */
                    foreach ($recordsFondo as $valueFondo) {

                        /*
                         * Variables agrup_concep
                         */
                        $id_concep_nomina = $valueFondo['id_concep_nomina'];
                        $porcentaje = $valueFondo['porcentaje_func'];
                        $caracter = "M";


                        /*
                         * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
                         * Dias de descuenctos segun 1001, o por defecto 30 - 20170323
                         */
                        $sql = <<<EOD
select
1 as tag_def,
$salario_minimo as salario_minimo,
1 as tag,
0 as tg_retro,
0 as promedio,
$id_anhos_tipter as vig_ini,
$id_meses_tipter as per_ini,
$id_anhos_tipter as vig_fin,
$id_meses_tipter as per_fin,
0 as meses_liq,
nvl((select max(num_dias) as num_dias from no_liquida_nomina 
  where id_periodo = $id_periodo and id_concep_nomina = (select no_param_concep.id_concep_basica from no_param_concep where no_param_concep.id_param_concep = 1)
  and num_doc = $num_doc),30) as dias_liq,
                            
nvl((
select 
    /*novvac.id_tipo_doc,                  
    novvac.num_doc,
    nvl(sum(dias_rango_mes(novvac.fecha_ini,novvac.fecha_fin,(select id_meses 
        from no_periodo where id_periodo =  $id_periodo))),0) as dias,
    nvl(sum( novvac.fecha_fin - novvac.fecha_ini + 1),0) as num_dias_vac,*/
    nvl(sum(FECHA_RANGO_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin)),0) as dias_vac
                        
    from no_novedad_vac novvac
    left join no_tipo_nov_vac tipnov on tipnov.id_tipo_nov_vac = novvac.id_tipo_nov_vac
    where tipnov.tiempo_liqui = 1 and tipnov.operador = 1 
    and novvac.num_doc = $num_doc
    and novvac.id_periodo in ( $id_periodo )
    group by novvac.id_tipo_doc, novvac.num_doc
),0) as wdiasv,
                            
0 as dias_otra_ent,
0 as dias_ausenc,
'$caracter' as caracter_adic,
nvl('$fecha_desde_tipter', '') as fecha_desde,
nvl('$fecha_hasta_tipter', '') as fecha_hasta,
nvl('', '') as fecha_ingreso,
nvl('', '') as fecha_termina,
nvl('', '') as fecha_retiro,
nvl((select max(num_dias) as num_dias from no_liquida_nomina 
  where id_periodo = $id_periodo and id_concep_nomina = (select no_param_concep.id_concep_basica from no_param_concep where no_param_concep.id_param_concep = 1)
  and num_doc = $num_doc),30) as num_dias,
0 as num_dias_base,
$porcentaje 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
                        $records = CN_TABLE::executeSQL($sql);

                        /*
                         * Recorre los registros de funcionario - concepto nomina
                         * para ser liquidados
                         */
                        foreach ($records as $value) {
                            $this->logMessage("[Liquidación Adicional] Existen liquidaciones.");

                            $id_periodo = $value['periodo'];
                            $num_doc = $value['num_doc'];
                            $id_tipo_doc = $value['id_tipo_doc'];
                            $id_concep_nomina = $value['id_concep_nomina'];

                            /*
                             * Liquidar periodo-funcionario-concepto nomina
                             */
                            $this->liquidar($id_periodo, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta);
                        }
                    }


                    /*
                     * FSP - 20141014
                     */
                    /**
                     * Consultar salario minimo
                     * Se cambia a vigencia el periodo del filtro - 20140403
                     * (select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = extract(year from sysdate))  
                     */
                    $salario_minimo = 550000;
                    //Sql
                    $sql = <<<EOD
(select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = (select id_anhos from no_periodo where id_periodo = $id_periodo ))  
EOD;
                    //Ejecutar SQL
                    $record_smlv = CN_TABLE::executeSQL($sql);

                    if (count($record_smlv) > 0) {
                        $salario_minimo = $record_smlv[0]['valor_mensual'];
                    }

                    $valor_base = 0;



                    /*
                     * Tag_retro para cuando es retroactivo, para retencion tiene encuenta todo el mes con lo del retroactivo - 20150610
                     */
                    //Sql
                    $sql = <<<EOD
select 
$salario_minimo as salario_minimo,
1 as tag,
0 as tg_retro,
$id_periodo as periodo,                    
tab0.* 
from no_liquida_nomina tab0
left join no_fondo_concepto foncon
on tab0.id_concep_nomina = foncon.id_concep_nomina
where foncon.id_descuento_ss = 2
and tab0.id_periodo = $id_periodo
and tab0.num_doc = $num_doc
order by 
tab0.id_tipo_doc,
tab0.num_doc
EOD;

                    //Ejecutar SQL
                    $record_fsp = CN_TABLE::executeSQL($sql);

                    foreach ($record_fsp as $value) {

                        $id_liquida_nomina = $value['id_liquida_nomina'];
                        $valor_base = $value['valor_liquidado'];
                        $valor_base_vac = 0;
                        $num_doc = $value['num_doc'];
                        $id_tipo_doc = $value['id_tipo_doc'];
                        $num_dias_fsp = $value['num_dias'];
                        $id_concep_nomina = $value['id_concep_nomina'];


                        /*
                         * Valor base formula FSP
                         */
                        $valor_base = round($valor_base, -3);
                        //                $valor_base = round($valor_base);
                        //valor base no puede superar 25 salarios minimos
                        if ($valor_base > ($salario_minimo * 25)) {
                            $valor_base = round(($salario_minimo * 25) - 1, -3);
                            //                    $valor_base = round(($salario_minimo * 25) - 1);
                        }

                        $dias_liq = 30;
                        $wdiasv_tot = 0;



                        //Sql
                        $sql = <<<EOD
select nvl(sum(valor),0) as valor from no_concepto_func 
    where num_doc = $num_doc and id_tipo_doc = 1 
        and id_concep_nomina = (select no_param_concep.id_concep_basica from no_param_concep where no_param_concep.id_param_concep = 1) 
            and estado = 1 and actual = 1
EOD;

                        //Ejecutar SQL
                        $record_asig = CN_TABLE::executeSQL($sql);

                        $salario = $record_asig[0]['valor'];


                        //Anexo dias totales y de vacaciones totales - 20131217
                        $array_valor_base = $this->valor_base_fsp($valor_base, $salario_minimo, $valor_base_vac, $wdiasv_tot, $dias_liq, $num_doc, $id_periodo, $salario);
                        $valor_fsp = $array_valor_base['valor_fsp'];
                        $porcentaje_fsp = $array_valor_base['porcentaje_fsp'];

                        /**
                         * SQL de consulta para validar si el concepto de FSP es por ajuste - 20131129
                         */
                        //Sql
                        $sql = <<<EOD
select 
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_concep_nomina,
tab0.id_periodo,
tab0.valor_ajuste,
 to_date( '01/' || per.id_meses || '/' || per.id_anhos, 'dd/mm/yyyy')  as fecha_desde,
TRUNC(LAST_DAY( to_date(per.id_meses || '/' || per.id_anhos, 'mm/yyyy')  )) as fecha_hasta,
tab0.num_dias
from no_ajuste_nomina tab0
join no_periodo per
on per.id_periodo = tab0.id_periodo 
WHERE tab0.id_periodo = $id_periodo 
and tab0.NUM_DOC = $num_doc
and tab0.id_concep_nomina = $id_concep_nomina
EOD;

                        //Ejecutar SQL
                        $record_fsp_ver = CN_TABLE::executeSQL($sql);

                        /*
                         * Validar si el FSP es por ajuste - 20131129
                         */
                        if (count($record_fsp_ver) == 0) {
                            if ($valor_fsp > 0) {

                                /*
                                 * Actualizar valores de FSP
                                 */
                                //sentencia sql
                                $sql = <<<EOD
update NO_LIQUIDA_NOMINA set valor_liquidado =  $valor_fsp
        , porcentaje = $porcentaje_fsp
            , valor_base = round( valor_liquidado, -3 ) 
    where id_liquida_nomina = $id_liquida_nomina 
        and id_periodo = $id_periodo
EOD;
                                //ejecuta y obtiene el resultado del sql
                                CN_TABLE::executeSQL($sql);
                            } else {

                                /*
                                 * Borrar del FSP
                                 */
                                //sentencia sql
                                $sql = <<<EOD
delete from NO_LIQUIDA_NOMINA where id_liquida_nomina = $id_liquida_nomina 
and id_periodo = $id_periodo
EOD;
                                //ejecuta y obtiene el resultado del sql
                                CN_TABLE::executeSQL($sql);
                            }
                        } else {

                            $valor_ajuste = $record_fsp_ver[0]["valor_ajuste"];

                            /*
                             * Borrar del FSP que no estan en la tabla de ajustes - 20140515
                             */
                            //sentencia sql
                            $sql = <<<EOD
delete from NO_LIQUIDA_NOMINA where id_liquida_nomina = $id_liquida_nomina 
and id_periodo = $id_periodo
and valor_liquidado != $valor_ajuste
EOD;
                            //ejecuta y obtiene el resultado del sql
                            CN_TABLE::executeSQL($sql);
                        }
                    }


                    /**
                     * FIN :: Calculo Salud / Pension Liq Def
                     */
//                    die();



                    /*
                     * Inicio del proceso de calculo de Retencion en la fuente Nomina Adicional - 20180307
                     */
                    //Sql
                    $sql = <<<EOD
select 
$salario_minimo as salario_minimo,
1 as tag,
1 as tg_retro,
nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt,  
nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif,                      
tab0.*,
tab0.num_dias as dias_liq,
tipcon.orden,
connom.codigo,
connom.usa_dias_calen

from (
    select distinct   
    tab0.id_concepto_periodo,
    tab0.id_anhos,
    tab0.id_meses,
    $id_periodo as periodo,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.id_concep_nomina,
    tab0.fecha_desde,
    tab0.fecha_hasta,
    tab0.valor,
    tab0.porcentaje,
    30 as num_dias,
    tab0.id_periodo_ajuste
    from no_concepto_periodo tab0
    where tab0.periodo in (select per.id_periodo from no_periodo per where per.id_tipo_periodo = 1 
        and per.id_anhos = (select id_anhos from no_periodo where id_periodo = $id_periodo) 
            and per.id_meses = (select id_meses from no_periodo where id_periodo = $id_periodo))
    and tab0.id_concep_nomina in (select no_param_concep.id_concep_rete from no_param_concep where no_param_concep.id_param_concep = 1) 

    union

    select     
    rownum as id_concepto_periodo,
    id_anhos,
    id_meses,
    periodo,
    id_tipo_doc,
    num_doc,
    id_concep_nomina,
    fecha_desde,
    fecha_hasta,
    valor,
    porcentaje,
    num_dias,
    id_periodo_ajuste

    from(
        select distinct 
        rownum id_concepto_periodo,
        per.id_anhos as id_anhos,
        per.id_meses as id_meses,
        per.id_periodo as periodo,
        aut.id_tipo_doc,
        aut.num_doc,
        param.id_concep_rete as id_concep_nomina,
        per.fecha_ini as fecha_desde,
        per.fecha_fin as fecha_hasta,
        null as valor,
        1 as porcentaje,
        30 as num_dias,
        per.id_periodo as id_periodo_ajuste,
        per.id_tipo_periodo,
        aut.id_tipo_proced_rete

        from no_novedad_proced_rete aut

        left join no_nombramiento_v nom
        on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc

        left join no_periodo per
        on per.id_periodo = $id_periodo

        left join no_param_concep param
        on param.id_param_concep = 1

        where
        aut.estado = 1                
        and aut.id_tipo_proced_rete = 1
        or (
            aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  
                and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
        ) 
    )
    where
    id_tipo_periodo = 2 
    and id_tipo_proced_rete = 1
)tab0                    

join no_concep_nomina connom
on connom.id_concep_nomina = tab0.id_concep_nomina

join no_tipo_concepto tipcon
on tipcon.id_tipo_concepto = connom.id_tipo_concepto

where tab0.periodo = $id_periodo
and tab0.num_doc = $num_doc
and tab0.id_concep_nomina = (select id_concep_rete from no_param_concep where id_param_concep = 1)
and tab0.porcentaje > 0

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


                    /*
                     * Recorre los registros de funcionario - concepto nomina
                     * para ser liquidados
                     */
                    $i = 0;
                    $nom_conceptos_a_procesar = count($records);
                    foreach ($records as $value) {
                        $this->logMessage("[Liquidación] Existen liquidaciones - RETE Nomina Adicional.");

                        $id_periodo_rete = $value['periodo'];
                        $num_doc = $value['num_doc'];
                        $id_tipo_doc = $value['id_tipo_doc'];
                        $id_concep_nomina = $value['id_concep_nomina'];


                        /*
                         * Liquidar periodo-funcionario-concepto nomina
                         */
                        $this->liquidar($id_periodo_rete, $num_doc, $id_tipo_doc, $id_concep_nomina, $value, $arrayConstantes, $record_consulta);

                        $i++;
                        $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE Nomina Adicional - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");
                    }

                    $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE - Termino Mencache.\n");
                    MemcacheHandler::getInstance()->set($progress_key, 95);
                }
            }

            /*
             * COMMIT DE TODAS LAS TRANSACCIONES
             */
            $this->conn->commit();
            MemcacheHandler::getInstance()->set($progress_key, 100);

            $this->status = 0;
            $this->list_data = array();
            $this->logMessage("[Liquidación] Liquidación exitosa");
        } 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] Ocurrio un error: " . $e->getMessage();
            $this->list_data = array();
            $this->logMessage("[Liquidación] ERROR!");
            $this->logMessage($e->getMessage());
        }
    }

    /**
     * Calcular FSP aporte funcionario
     * @param type $valor_base
     * @param type $salario_minimo
     * @return int
     */
    private function valor_base_fsp($valor_base, $salario_minimo, $valor_base_vac = 0, $wdiasv = 0, $dias_liq, $num_doc, $id_periodo) {

        $this->logMessage("[Liquidación] valor_base_fsp:: valor_base: " . $valor_base . " - valor_base_vac: " . $valor_base_vac);
        $this->logMessage("[Liquidación] valor_base_fsp:: wdiasv: " . $wdiasv . " - dias_liq: " . $dias_liq);


        /*
         * (SGC-1, ANM-2, SGR-3, CYC-4, COL-5, INCI-6, LOCAL-7)
         */
        $array = sfYaml::load(dirname(__FILE__) . '/../../../config/app-gwt.yml');

        $int = 0;
        foreach ($array as $routeName => $routeData) {
            //echo $routeName . "\n";
            if ('entidad_cliente' == $routeName) {
                foreach ($routeData as $key => $value) {
                    //echo $value . "\n";
                    if ($key == 'value') {
                        $entidadCliente = $value;
                    }
                }
            }
            $int++;
        }

        /*
         * WBASE=   BASE TOTAL que ya estamos hayando
         * WVRBASE=(WBASE/(WDIAST+WDIASV))*30
         * Sobre WVRBASE  verifica si debe calcular FSP y sobre ella misma ubicar el porcentaje 
         * Si aplica y tiene el porcentaje,  aplica el porcentaje sobre WBASE
         * 20131216
         */
        $valor = 0;
        $valorfps1 = 0;
        $valorfps2 = 0;
        $porcentaje = 0;
        $valor_bonif = 0;
        $valor_bonifs = 0;
        $horas_extras = 0;


        /**
         * Para las personas que tienen bonificacion por servicios se toma este valor proporcional a los dias laborados - 20140605
         */
        //Sql
        $sql = <<<EOD
select nvl(sum(valor_liquidado),0) as valor from no_liquida_nomina 
where num_doc = $num_doc and id_tipo_doc = 1 
and id_concep_nomina = (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1) 
and id_periodo = $id_periodo            
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        /*
         * Valida si posee el concepto
         */
        if (count($records) > 0 && $dias_liq > 0) {
            $valor_bonifs = $records[0]['valor']; //bonificacion completa
            $valor_bonif = (($valor_bonifs * $dias_liq) / 30); //bonificacion por dias laborales
        }
        $this->logMessage("[Liquidación] Valida si la persona - valor_bonif :: " . $valor_bonif);


        /**
         * Para las personas que tienen horas extras se toma solo el valor completo y no por los dias de trabajo 30 - 20150617
         */
        //Sql
        $sql = <<<EOD
select nvl(sum(valor_liquidado),0) as valor 
from no_liquida_nomina 
where num_doc = $num_doc and id_tipo_doc = 1 
and id_concep_nomina in (select distinct no_tipo_hr_extra.id_concep_nomina from no_tipo_hr_extra)  
and id_periodo = $id_periodo            
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        /*
         * Valida si posee el concepto
         */
        if (count($records) > 0 && $dias_liq > 0) {
            $horas_extras = $records[0]['valor']; //horas_extras completa
        }
        $this->logMessage("[Liquidación] Valida si la persona - horas extras :: " . $horas_extras);


        /*
         * Operaciones
         * Se quita la resta (- $valor_bonifs), toma el valor proporcional de los dias trabajados - 20150203 NO VA, porque el valor esta en la base por la agrupacion
         * Se separa el valor bonif del redondeo a 30 dias laborales, ya que en el proceso anterior ya se realiza su calculo para los 30 dias - 20150218
         */
        //$wvalor_base = (($valor_base + $valor_bonif) / ($dias_liq + $wdiasv)) * 30;
        //$wvalor_base = (($valor_base - $valor_bonifs + $valor_bonif) / ($dias_liq + $wdiasv)) * 30;
        $wvalor_base = (($valor_base - $valor_bonifs - $horas_extras) / ($dias_liq + $wdiasv) * 30 ) + ($valor_bonif + $horas_extras);

        // 9 - CEV PUB, se omite si supera el tope de 20 smlv, par aque no tome segun dias de vac - 20191213
        if ($entidadCliente == 9) {
            $wvalor_base = $valor_base;
        }

        /**
         * Valida si la persona ingreso en el mes o se retira para tomar los dias en cuenta - 20140307
         */
        $this->logMessage("[Liquidación] Valida si la persona - wvalor_base :: " . $wvalor_base . " - Salario Minimo :: " . $salario_minimo);
        //Sql
        $sql = <<<EOD
select 
nom.* 
from no_nombramiento_v nom
where 
nom.id_tipo_doc = 1
and nom.num_doc = $num_doc
and (
nom.fecha_ingreso between (select per.fecha_ini from no_periodo per where per.id_periodo = $id_periodo) and (select per.fecha_fin from no_periodo per where per.id_periodo = $id_periodo)
or 
nom.fecha_termina between (select per.fecha_ini from no_periodo per where per.id_periodo = $id_periodo) and (select per.fecha_fin from no_periodo per where per.id_periodo = $id_periodo)
)                
EOD;
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);

        /*
         * Valida si posee formula el concepto
         */
        if (count($records) > 0) {
            $wvalor_base = $valor_base + $valor_base_vac + $valor_bonif;
            $this->logMessage("[Liquidación] Valida si posee formula el concepto - wvalor_base :: " . $wvalor_base);
        }

        //Cambio de verificacion del valor base - 20131216
        if (($wvalor_base) > ($salario_minimo * 4) && ($wvalor_base) <= ($salario_minimo * 16)) {
            $porcentaje = 1;
        } elseif (($wvalor_base) > ($salario_minimo * 16) && ($wvalor_base) <= ($salario_minimo * 17)) {
            $porcentaje = 1.2;
        } elseif (($wvalor_base) > ($salario_minimo * 17) && ($wvalor_base) <= ($salario_minimo * 18)) {
            $porcentaje = 1.4;
        } elseif (($wvalor_base) > ($salario_minimo * 18) && ($wvalor_base) <= ($salario_minimo * 19)) {
            $porcentaje = 1.6;
        } elseif (($wvalor_base) > ($salario_minimo * 19) && ($wvalor_base) <= ($salario_minimo * 20)) {
            $porcentaje = 1.8;
        } elseif (($wvalor_base) > ($salario_minimo * 20)) {
            $porcentaje = 2;
        }

        /* INCI - 20140122
         * Patricia Montoya Falla, C.C. 35.462.698,
          Esperanza Verdugo, C.C.  46.662.659
          Yanerys Irina de la Hoz, C.C.  57.290.110
          Vladimir Yanken Cifuentes, C.C. 79.526.123
          Gustavo Pulido Casas, C.C. 93.288.443
         * 39773464
         */
        /* if ($num_doc == '35462698' || $num_doc == '46662659' || $num_doc == '57290110' || $num_doc == '79526123' || $num_doc == '93288443' || $num_doc == '51788859') {
          if (($valor_base + $valor_base_vac) > ($salario_minimo * 4) && ($valor_base + $valor_base_vac) <= ($salario_minimo * 16)) {
          $porcentaje = 1;
          } elseif (($valor_base + $valor_base_vac) > ($salario_minimo * 16) && ($valor_base + $valor_base_vac) <= ($salario_minimo * 17)) {
          $porcentaje = 1.2;
          } elseif (($valor_base + $valor_base_vac) > ($salario_minimo * 17) && ($valor_base + $valor_base_vac) <= ($salario_minimo * 18)) {
          $porcentaje = 1.4;
          } elseif (($valor_base + $valor_base_vac) > ($salario_minimo * 18) && ($valor_base + $valor_base_vac) <= ($salario_minimo * 19)) {
          $porcentaje = 1.6;
          } elseif (($valor_base + $valor_base_vac) > ($salario_minimo * 19) && ($valor_base + $valor_base_vac) <= ($salario_minimo * 20)) {
          $porcentaje = 1.8;
          } elseif (($valor_base + $valor_base_vac) > ($salario_minimo * 20)) {
          $porcentaje = 2;
          }
          }
          //num_doc in (13507148, 51653492 ,79250331 ,52779827 ,20404209)
          if ($num_doc == '51653492' || $num_doc == '79250331') {
          $porcentaje = 0;
          }
         */
        /**
         * Se redondea valor al sumar al final y no $valorfps1 / $valorfps2, por separado  - 20140616
         */
        $this->logMessage("[Liquidación] valor_base_fsp:: valor_base: " . $valor_base);
//        $valorfps1 = round($valor_base * 0.5 / 100, -2);
//        $valorfps2 = round($valor_base * ($porcentaje - 0.5) / 100, -2);
        $valorfps1 = $valor_base * 0.5 / 100;
        $valorfps2 = $valor_base * ($porcentaje - 0.5) / 100;
        $this->logMessage("[Liquidación] valor_base_fsp:: porcentaje: " . $porcentaje);
        $this->logMessage("[Liquidación] valor_base_fsp:: valorfps1: " . $valorfps1 . " - valorfps2: " . $valorfps2);

        //se cambia el redondeo al sumar valores como esta en autoliquidacion
//        $valor = round(($valorfps1 + $valorfps2) - 1, -2);
//        $valor = CN_TABLE::redondeoValor($valorfps1, -2) + CN_TABLE::redondeoValor($valorfps2, -2);
        $valor = CN_TABLE::ceiling($valorfps1, 100) + CN_TABLE::ceiling($valorfps2, 100);

        //Valida que si porcentaje 0, el valor de aporte es 0 - 20170307
        if ($porcentaje == 0) {
            $valor = 0;
        }

        $array_fsp = array(
            'valor_fsp' => $valor,
            'porcentaje_fsp' => $porcentaje
        );

        return $array_fsp;
    }

    /**
     * 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, $record_consulta, $tag_rete_contingente = 0) {

        $this->logMessage("[Liquidación] Liquidar: periodo " . $id_periodo . " - funcionario " . $num_doc . " - concepto nomina " . $id_concep_nomina);
        $this->logMessage("[Liquidación] Liquidar: tag_rete_contingente " . $tag_rete_contingente);

        $id_concep_nomina_inicial = $id_concep_nomina;

        /*
         * (SGC-1, ANM-2, SGR-3, CYC-4, COL-5, INCI-6, LOCAL-7)
         */
        $array = sfYaml::load(dirname(__FILE__) . '/../../../config/app-gwt.yml');

        $int = 0;
        foreach ($array as $routeName => $routeData) {
            //echo $routeName . "\n";
            if ('entidad_cliente' == $routeName) {
                foreach ($routeData as $key => $value) {
                    //echo $value . "\n";
                    if ($key == 'value') {
                        $entidadCliente = $value;
                    }
                }
            }
            $int++;
        }



        /**
         * Consultar salario minimo
         * Se cambia a vigencia el periodo del filtro - 20140403
         * (select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = extract(year from sysdate))  
         */
        $salario_minimo = 550000;
        //Sql
        $sql = <<<EOD
(select nvl(valor_mensual, 0) as valor_mensual from no_smdlv where vigencia = (select id_anhos from no_periodo where id_periodo = $id_periodo ))  
EOD;
        //Ejecutar SQL
        $record_smlv = CN_TABLE::executeSQL($sql);

        if (count($record_smlv) > 0) {
            $salario_minimo = $record_smlv[0]['valor_mensual'];
        }

        /**
         * Consulta a procedimiento de retencion, para el calculo de retencion en la fuente - 20161213
         * Incidente #6468 <-> Se agrega valor_bonif - 20170613
         * Incidente #7791 <-> Concepto nuevo para calculo procedimiento 1 - 20171215
         * Validacion para el valor que toma de no_liquida_nomina, se agrega sum - 20180118
         */
        //Sql
        $sql = <<<EOD
select 
nvl((select no_param_concep.id_concep_rete_proc1 from no_param_concep where no_param_concep.id_param_concep=1),0) as id_concep_rete_proc1,
(select no_param_concep.id_concep_rete from no_param_concep where no_param_concep.id_param_concep=1) as id_concep_rete,
$id_periodo as id_periodo,
$id_periodo as periodo,     
(select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo) as vig_ini,
(select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo) as vig_fin,
(select no_periodo.id_meses from no_periodo where id_periodo = $id_periodo) as per_ini,
(select no_periodo.id_meses from no_periodo where id_periodo = $id_periodo) as per_fin,
nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt,
nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif,                      
nvl( (select sum(valor_liquidado) as valor_liquidado from no_liquida_nomina where id_periodo = $id_periodo and NUM_DOC = tab0.NUM_DOC and id_concep_nomina = (select par.id_concep_rete from no_param_concep par where par.id_param_concep = 1 )) , -1) as rete,
tab0.id_novedad_proced_rete,
tab0.id_tipo_doc,
tab0.num_doc,
tab0.id_tipo_proced_rete,
--tab0.id_periodo,
tab0.observacion,
tab0.fecha_inicial,
tab0.fecha_terminacion,
tab0.declara_renta,
tab0.estado ,
null as porcentaje  
from (

  select 
  aut.*,
   ROW_NUMBER() OVER (
    partition by aut.num_doc
    ORDER BY aut.id_novedad_proced_rete desc
   ) AS rn
  from no_novedad_proced_rete aut
  left join no_nombramiento_v nom
  on nom.num_doc = aut.num_doc and nom.id_tipo_doc = aut.id_tipo_doc
  where
  aut.estado = 1 
  or (
    aut.estado = 0 and nom.fecha_termina between (select no_periodo.fecha_ini from no_periodo where id_periodo = $id_periodo )  and (select no_periodo.fecha_fin from no_periodo where id_periodo = $id_periodo ) 
  )

)tab0
where
id_tipo_doc = $id_tipo_doc
and num_doc = '$num_doc'

order by
tab0.estado desc,
tab0.id_novedad_proced_rete desc   
EOD;
        //Ejecutar SQL
        $record_proc_rete = CN_TABLE::executeSQL($sql);

        $id_tipo_proced_rete = 0;
        $id_concep_rete = 0;
        $id_concep_rete_proc1 = 0;
        if (count($record_proc_rete) > 0) {
            $id_tipo_proced_rete = $record_proc_rete[0]['id_tipo_proced_rete'];
            $id_concep_rete = $record_proc_rete[0]['id_concep_rete'];
            $id_concep_rete_proc1 = $record_proc_rete[0]['id_concep_rete_proc1'];
        }

        //Cambia concepto nomina si es retefuente y es procedimiento 1 - 20171215
        if ($id_concep_rete_proc1 != 0 && $id_tipo_proced_rete == 1 && $id_concep_nomina == $id_concep_rete) {
            $id_concep_nomina = $id_concep_rete_proc1;
        }

        /*
         * Valores de UVT y Tope Bonif Globales - 20170614
         */
        $record_uvt_bonif = array();
        //Sql
        $sql = <<<EOD
select nvl((select valor_uvt from ts_uvt where vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)) , 1) as valor_uvt from dual  
EOD;
        //Ejecutar SQL
        $record_uvt = CN_TABLE::executeSQL($sql);

        if (count($record_uvt) > 0) {
            $valor_uvt = $record_uvt[0]['valor_uvt'];
        }
        $record_uvt_bonif['valor_uvt'] = $valor_uvt;

        //Incidente #6468 <-> Se agrega valor_bonif - 20170613l
        $sql = <<<EOD
select nvl((select valor_fijo from no_concep_ab where id_concep_nomina in (select no_param_concep.id_concep_bonif from no_param_concep where no_param_concep.id_param_concep = 1)) , 1) as valor_bonif from dual  
EOD;
        //Ejecutar SQL
        $record_bonif = CN_TABLE::executeSQL($sql);

        if (count($record_bonif) > 0) {
            $valor_bonif = $record_bonif[0]['valor_bonif'];
        }
        $record_uvt_bonif['valor_bonif'] = $valor_bonif;

        //Mes del periodo - 20181212
        $sql = <<<EOD
select id_meses from no_periodo where id_periodo = $id_periodo  
EOD;
        //Ejecutar SQL
        $record_per = CN_TABLE::executeSQL($sql);
        $mes = $record_per[0]['id_meses'];

        /**
         * Varibles
         */
        $arrayParametros = array();
        /*
         * Variable para optimizar consultas de formulas en las liquidaciones - 20140117
         */
        $vals_calc = array();
        $valor_liquidado = 0;
        $fecha_desde = $record_liq['fecha_desde'];
        $fecha_hasta = $record_liq['fecha_hasta'];
        $num_dias = $record_liq['num_dias'];

        //Concepto Nomina 1009 Vacaciones
        if ($id_concep_nomina == 9) {
            $record_liq['vig_ini'] = $record_liq['id_anhos'];
            $record_liq['per_ini'] = 1;
            $record_liq['vig_fin'] = $record_liq['id_anhos'];
            $record_liq['per_fin'] = $record_liq['id_meses'];
        }
        /**
         * Concepto Nomina 1016 y 1017, para liquidar en la mensual - 20151218
         */
        if ($id_concep_nomina == 16 || $id_concep_nomina == 17) {
            $record_liq['vig_ini'] = $record_liq['id_anhos'];
            $record_liq['per_ini'] = $record_liq['id_meses'];
            $record_liq['vig_fin'] = $record_liq['id_anhos'];
            $record_liq['per_fin'] = $record_liq['id_meses'];
        }

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

        /*
         * Cargar fórmulas por concepto
         * Se modifico formula Para aporte en salud, pensión y FSP  existe un tope máximo de aporte de 25 SMLV
         * se toma del id_concep_nomina asociado al descuento - 20130814
         */
        //Sql
        $sql = <<<EOD
select distinct * from no_formula 
   WHERE id_concep_nomina =   (    
   
  select distinct 
  nvl( id_concep_nomina_ss, ID_CONCEP_NOMINA) as ID_CONCEP_NOMINA 
  from
  (
  
      select 
      formula.ID_FORMULA,
      formula.ID_CONCEP_NOMINA,
      formula.FORMULA,
      formula.NOMBRE,
      formula.COD_TIPO,
      foncon.id_descuento_ss,
      des.id_concep_nomina as id_concep_nomina_ss
      from no_formula formula
      left join no_fondo_concepto foncon
      on formula.id_concep_nomina = foncon.id_concep_nomina
      left join no_descuento_ss des
      on foncon.id_descuento_ss = des.id_descuento_ss
      where formula.id_concep_nomina = $id_concep_nomina 
  
  )

)   
EOD;

        /*
         * Variables y estructura para manejo de consultas con variables bind - 20130829
         */
//        $record_var_bind = array(
//            'id_concep_nomina' => 'id_concep_nomina'
//        );
//        $record_bind = array(
//            'id_concep_nomina' => $id_concep_nomina
//        );
        //Ejecutar SQL
        $records = CN_TABLE::executeSQL($sql);
//        $records = CN_TABLE::executeBindSQL($sql, null, $record_var_bind, $record_bind);

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

            foreach ($records as $value) {

                $formula = $value['formula'];
                $this->logMessage("[Liquidación] 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] 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
                 */
                $formula = CN_TABLE::reemplazoConsulta($formula, $record_uvt_bonif); //Solo para valores uvt y bonif - 20170614
                $formula = CN_TABLE::reemplazoConsulta($formula, $record_liq);
                $this->logMessage("[Liquidación] 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'
                         */
                        $this->logMessage("[Liquidación] vals_calc: " . $var);
                        if (!isset($vals_calc[$var])) {
                            $formula_agrup = $this->reemplazoAgrupacion(substr($var, 1));
                            $this->logMessage("[$var] [Liquidación Agrupación] Agrupacion: " . $formula_agrup);

                            // $formula = str_replace('{' . $var . '}', $agrup, $formula);
                            $params_agrup = $this->parametrosFormula($formula_agrup);
                            $res_agrup = $this->resultadoParametros($params_agrup, $record_liq, $record_consulta, $vals_calc, $id_concep_nomina, $id_tipo_proced_rete, $id_concep_rete, $id_concep_rete_proc1, $tag_rete_contingente);
                            $formula_agrup = $this->reemplazoParametros($formula_agrup, $res_agrup);

                            $formula_agrup = str_replace('{', ' ', $formula_agrup);
                            $formula_agrup = str_replace('}', ' ', $formula_agrup);
                            $result_agrup = CN_TABLE::aplicarEval($formula_agrup);

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

                            $vals_calc[$var] = $result_agrup;
                        }

                        $formula = str_replace('{' . $var . '}', $vals_calc[$var], $formula);
                    }
                }
                $this->logMessage("[Liquidación] 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'
                 * );
                 */
                $arrayParametros2 = $this->resultadoParametros($arrayParametros, $record_liq, $record_consulta, $vals_calc, $id_concep_nomina, $id_tipo_proced_rete, $id_concep_rete, $id_concep_rete_proc1, $tag_rete_contingente);


                /*
                 * Reemplazo de parametros(variables) a la formula
                 * Ejemplo: $arrayParametros = array(
                 * 'C1' => '1100',
                 * 'C2' => '55'
                 * );
                 */
                $formula = $this->reemplazoParametros($formula, $arrayParametros2);
                $this->logMessage("[Liquidación] 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) {
                    $this->logMessage("[Liquidación] Formula No cumple con la condicion: " . $formula);
                    $result = 0;
                }

                //CYC: Valor y base extra rete contingente, quitar valor de resta; negativo - 20191128
                if ($tag_rete_contingente == 1 && $result < 0) {
                    $result = 0;
                }


                /*
                 * Acumulan resultados de liquidacion
                 */
                if ($result !== -9999) { // Validar al cumplir condicion -9999 - no cumplue con la condicion de la formula
                    $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)
                 */
                $porcentaje = $record_liq['porcentaje'];
                $this->logMessage("[Liquidación] Valor base salarios minimos valor_liquidado:: " . $valor_liquidado);
                if ($value['cod_tipo'] == 'V') {
                    $this->logMessage("[Liquidación] Formula CodTipo: " . $value['cod_tipo']);

                    /*
                     * Valor Base y porcentaje
                     */
                    $valor_base = round(($valor_liquidado * 100) / $record_liq['porcentaje']);
                    $this->logMessage("[Liquidación] Valor base salarios minimos antes:: " . $valor_base);

                    /*
                     * No puede superar el salario_minimo - solo conceptos de fondos - 20151019
                     */
                    //Sql
                    $sql = <<<EOD
select * from no_fondo_concepto
where id_concep_nomina = $id_concep_nomina  
EOD;
                    //Ejecutar SQL
                    $record_foncon = CN_TABLE::executeSQL($sql);
                    if (count($record_foncon) > 0) {
                        $id_descuento_ss = $record_foncon[0]['id_descuento_ss'];
                        $this->logMessage("[Liquidación] Conceptos de fondos:: " . $id_concep_nomina);

                        /**
                         * Valor base no puede superar 25 salarios minimos - 20151019
                         */
                        //solo para $id_descuento_ss - id=2 FSP
                        if ($valor_liquidado >= ($salario_minimo * 25)) {
                            $valor_base = round(($salario_minimo * 25) - 1, -1);
                            $valor_liquidado = round(($salario_minimo * 25) - 1, -1);
                        } else if ($valor_liquidado >= $salario_minimo && $id_descuento_ss != 2) {
                            $valor_base = round(($salario_minimo * 25) - 1, -1);
                            $valor_liquidado = $salario_minimo;
                        }

                        $this->logMessage("[Liquidación] Valor base no puede superar 25 salarios minimos - valor_liquidado:: " . $valor_liquidado);
                        $this->logMessage("[Liquidación] Valor base no puede superar 25 salarios minimos:: " . $valor_base);
                    }

                    /**
                     * Valor liquidado 0 por dias 0 - 20191119
                     */
                    if ($num_dias <= 0) {
                        $this->logMessage("[Liquidación] Valor liquidado 0 por dias 0:: " . $num_dias);
                        $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] 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;
                    $this->logMessage("[Liquidación] No hay registros id_concep_basica ");
                } else {
                    $this->logMessage("[Liquidación] Hay registros id_concep_basica ");
                }

                //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'];
                $this->logMessage("[Liquidación] porcentaje - " . $porcentaje . " :: valor_base - " . $valor_base);

                /*
                 * usa_dias_calen - 20160311
                 */
                if (!is_null($record_liq['num_dias'])) {
                    if ($record_liq['usa_dias_calen'] == 0) { //Mensual
                        $num_dias_pre = 30;
                        //Incidente #4012 <-> Se deja dias 30 para, que tome en base 30 - 20160719
                        //$num_dias_pre = $record_liq['num_dias']; // ? Revisar
                    } else { //Por días calendario
                        $num_dias_pre = $record_liq['num_dias'];
                    }
                    //para dias diferentes de  30 - 20160311
                    if ($num_dias_pre != 30) {

                        /*
                         * Se deja como estaba error ceil, se arreglo para que si no es por formula ni porcentaje, camcule correctamente, y no den decimales erroneos - 20171211
                         * Antes: $result = ($result / 30) * $num_dias_pre;
                         */
                        $result = ($result * $num_dias_pre) / 30;
                    }
                }
            } else {
                $this->logMessage("[Liquidación] 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'];
                    }
                    /*
                     * Se deja como estaba error ceil, se arreglo para que si no es por formula ni porcentaje, camcule correctamente, y no den decimales erroneos - 20171211
                     * Antes: $result = ($record_liq['valor'] / 30) * $num_dias;
                     */
                    $result = ($record_liq['valor'] * $num_dias) / 30;
                } else {
                    $num_dias = 'null';
                    $result = $record_liq['valor'];
                }
            }

            $valor_liquidado += $result;
        }


        //Reversa el concepto nomina si es retefuente y es procedimiento 1 - 20171215
        if ($id_concep_rete_proc1 != 0 && $id_tipo_proced_rete == 1 && $id_concep_nomina_inicial == $id_concep_rete) {
            $id_concep_nomina = $id_concep_nomina_inicial;

            $valor_uvt_rete = $valor_liquidado;
            $valor_liquidado = 0;
            $this->logMessage("[Liquidación] Valor de uvt de retencion = " . $valor_uvt_rete);

            /**
             * Se adiciona para la consulta en diciembre que no tome el periodo 4-Prima Navidad, 
             * y es formula de concepto de retencion, solo procedimiento 1 - 20181212
             * Se coloca que omita tambien prima de servicios, solo procedimiento 1, (&& $mes == 12) - 20190614
             */
            $consulta_adic = " ";
            if (($id_concep_nomina == $id_concep_rete || $id_concep_nomina == $id_concep_rete_proc1) /* && $mes == 12 */ && $id_tipo_proced_rete == 1) {
                $consulta_adic = " and per.id_tipo_periodo not in (4,3) ";
            }

            /*
             * Para retencion procedimiento 1, se aplica reten383 de la tabla uvt - 20171215
             */
            //Sql
            $sql = <<<EOD
select  
reten.* 
from ts_reten383 reten
where 
reten.vigencia = (select no_periodo.id_anhos from no_periodo where id_periodo = $id_periodo)
and $valor_uvt_rete between reten.rango_desde and reten.rango_hasta
order by
reten.tarifa                       
EOD;
            //Ejecutar SQL
            $record_rete = CN_TABLE::executeSQL($sql);

            if (count($record_rete) > 0) {
                $tarifa_rete = $record_rete[0]['tarifa'];
                $uvt_mas = $record_rete[0]['uvt_mas'];
                $uvt_menos = $record_rete[0]['uvt_menos'];

                //Calculo segun uvt y tarifa
                if ($valor_uvt_rete < 95) {
                    $valor_liquidado = 0;
                    $valor_base = 0;
                }
                if (95 < $valor_uvt_rete) {
                    $valor_liquidado = round((($valor_uvt_rete - $uvt_menos) * ($tarifa_rete / 100) * $valor_uvt) + ($uvt_mas * $valor_uvt));
                    $valor_base = $valor_uvt_rete * $valor_uvt;

                    //Resta los valores de retencion anteriores, diferentes al periodo
                    //Sql
                    $sql = <<<EOD
select nvl(sum(liqnom.valor_liquidado),0) as valor  
from no_liquida_nomina liqnom   

join no_periodo per on per.id_periodo = liqnom.id_periodo 
where    
1 = 1 
and per.id_meses = ( select id_meses from no_periodo where id_periodo = $id_periodo)  
and per.id_anhos = ( select id_anhos from no_periodo where id_periodo = $id_periodo)   
and liqnom.num_doc = '$num_doc'  and liqnom.id_tipo_doc = $id_tipo_doc  
    and liqnom.id_concep_nomina = $id_concep_nomina_inicial  
and per.id_periodo != $id_periodo      
$consulta_adic     
EOD;
                    //Ejecutar SQL
                    $record_rete_t = CN_TABLE::executeSQL($sql);
                    //Resta retencion de otros periodos proc1 - 20180705
                    if (count($record_rete_t) > 0) {
                        $valor_liquidado = $valor_liquidado - $record_rete_t[0]['valor'];
                    }
                }
            }
        }


        /*
         * Valida creacion de registro
         */
        $this->logMessage("[Liquidación] Valor de liquidacion = " . $valor_liquidado);
        if ($valor_liquidado > 0) {

            //Redondeo por decimales, hacia arriba, por calculo de AB en Autoliquidacion - 20171117
            //Se deja como estaba error ceil, se arreglo para que si no es por formula ni porcentaje, camcule correctamente, y no den decimales erroneos - 20171211
            $valor_liquidado = CN_TABLE::ceiling($valor_liquidado, 1);

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


            /**
             * SGC: Valida si es retefuente y redondea al mil - 20140320
             */
            $id_concep_nomina_rete = 0;

            //Sql para tomar id de retefuente
            $sql = <<<EOD
select * from no_param_concep where id_param_concep = 1
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

            if (count($records) > 0) {
                $id_concep_nomina_rete = $records[0]['id_concep_rete'];
            }
            //SGC: Valida si es retefuente y redondea al mil - 20140320
            //CYC: Valor y base extra rete contingente - 20191128
            $tag_concep_contingente = 0;
            if ($id_concep_nomina == $id_concep_nomina_rete) {

                $tag_concep_contingente = 1;

                $valor_liquidado = round($valor_liquidado, -3);

                //borra registro de retefuente si tenia registrado un valor antes - 20190530
                $sql = <<<EOD
DELETE FROM no_liquida_nomina 
    where id_concep_nomina = $id_concep_nomina_rete and id_periodo = $id_periodo  
        and num_doc = '$num_doc' and id_tipo_doc = $id_tipo_doc
EOD;
                //Ejecutar SQL
                if ($tag_rete_contingente == 0) {
                    CN_TABLE::executeSQL($sql);
                }
            }

            /**
             * Valor base no puede superar 25 salarios minimos - 20151019
             */
            $this->logMessage("[Liquidación] Valor base salarios minimos:: " . $valor_base);
            /* if ($valor_base > ($salario_minimo * 25)) {
              $valor_base = round(($salario_minimo * 25) - 1, -1);
              $this->logMessage("[Liquidación] Valor base no puede superar 25 salarios minimos:: " . $valor_base);
              $valor_liquidado = $salario_minimo;
              } */

            /*
             * Crear nueva liquidación
             * 
             * Asignar valores encontrados en persona
             * Se valida con nvl los dias, pone null si no hay - 20150324
             */
            if ($tag_rete_contingente == 1 && $tag_concep_contingente == 1) {

                $sql = <<<EOD
update no_liquida_nomina 
set valor_liq_extra = round( $valor_liquidado, 0),
valor_base_extra = round( $valor_base, 0)
where
id_periodo = $id_periodo
and id_tipo_doc = $id_tipo_doc
and num_doc = '$num_doc'
and id_concep_nomina = $id_concep_nomina 
EOD;
            } else {
                //insert into no_liquida_nomina (id_liquida_nomina,id_tipo_doc,num_doc,id_concep_nomina,
                //id_periodo,valor_liquidado,fecha_desde,fecha_hasta,num_dias) 
                //values ('9','1','17304849','1','13','257100',to_date('22/11/12','DD/MM/RR'),
                //to_date('22/11/12','DD/MM/RR'),'30');
                //Sql
                $sql = <<<EOD
insert into no_liquida_nomina (id_tipo_doc, num_doc, id_concep_nomina,
        id_periodo,valor_liquidado,fecha_desde,fecha_hasta,num_dias, valor_base, porcentaje ) 
        values ( $id_tipo_doc, '$num_doc', $id_concep_nomina, $id_periodo, round( $valor_liquidado, 0), 
        to_date('$fecha_desde','YYYY-MM-DD'), to_date('$fecha_hasta','YYYY-MM-DD'), nvl('$num_dias',null), round( $valor_base, 0), $porcentaje ) 
EOD;
            }
            /*
             * Variables y estructura para manejo de consultas con variables bind - 20130829
             */
            /*
             * insert into no_liquida_nomina (id_tipo_doc, num_doc, id_concep_nomina,
              id_periodo,valor_liquidado,fecha_desde,fecha_hasta,num_dias, valor_base, porcentaje )
              values ( :id_tipo_doc, :num_doc, :id_concep_nomina, :id_periodo, round( :valor_liquidado, 0),
              to_date(:fecha_desde,'YYYY-MM-DD'), to_date(:fecha_hasta,'YYYY-MM-DD'), :num_dias, round( :valor_base, 0), :porcentaje )
             */
//            $record_var_bind = array(
//                'id_tipo_doc' => 'id_tipo_doc',
//                'num_doc' => 'num_doc',
//                'id_concep_nomina' => 'id_concep_nomina',
//                'id_periodo' => 'id_periodo',
//                'valor_liquidado' => 'valor_liquidado',
//                'fecha_desde' => 'fecha_desde',
//                'fecha_hasta' => 'fecha_hasta',
//                'num_dias' => 'num_dias',
//                'valor_base' => 'valor_base',
//                'porcentaje' => 'porcentaje'
//            );
//            $record_bind = array(
//                'id_tipo_doc' => $id_tipo_doc,
//                'num_doc' => $num_doc,
//                'id_concep_nomina' => $id_concep_nomina,
//                'id_periodo' => $id_periodo,
//                'valor_liquidado' => $valor_liquidado,
//                'fecha_desde' => $fecha_desde,
//                'fecha_hasta' => $fecha_hasta,
//                'num_dias' => $num_dias,
//                'valor_base' => $valor_base,
//                'porcentaje' => $porcentaje
//            );
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);
//            CN_TABLE::executeBindSQL($sql, null, $record_var_bind, $record_bind);
        }
        //Valida si es retefuente y el valor es negativo - 20130724
        elseif ($valor_liquidado < 0) {
            $this->logMessage("[Liquidación] El valor_liquidado es menor a cero.");

            $id_concep_nomina_rete = 0;

            //Sql para tomar id de retefuente
            $sql = <<<EOD
select * from no_param_concep where id_param_concep = 1
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

            if (count($records) > 0) {
                $id_concep_nomina_rete = $records[0]['id_concep_rete'];
            }

            //Sql para tomar id de retefuente
            $sql = <<<EOD
select 
liq.* 
from no_liquida_nomina liq
join no_periodo per on per.id_periodo = liq.id_periodo
where
liq.num_doc = $num_doc
and liq.id_concep_nomina = $id_concep_nomina
and liq.id_periodo != $id_periodo
and per.id_anhos = (select no_periodo.id_anhos from no_periodo where no_periodo.id_periodo = $id_periodo)
and per.id_meses = (select no_periodo.id_meses from no_periodo where no_periodo.id_periodo = $id_periodo) 
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);
            $tag_rete_per = false;
            if (count($records) > 0) {
                $tag_rete_per = true;
            }

            //Valida si es retefuente y los dias mayores a cero
            //Valida que tenga liquidacion en otro periodo del mismo mes - 20151119
            if ($id_concep_nomina == $id_concep_nomina_rete && $num_dias > 0 && $tag_rete_per) {

                $this->logMessage("[Liquidación] Valida si es retefuente y el valor es negativo.");

                /*
                 * Crear nueva liquidación
                 * 
                 * Asignar valores encontrados en persona
                 */
                $valor_liquidado = $valor_liquidado * (-1);
                //Validar la diferencia entre el redondeo - 20180601
                $porcentaje = str_replace(',', '.', $porcentaje);
                if ($valor_liquidado >= 1000) {

                    //Sql
                    $sql = <<<EOD
insert into no_liquida_nomina (id_tipo_doc, num_doc, id_concep_nomina,
        id_periodo,valor_liquidado,fecha_desde,fecha_hasta,num_dias, valor_base, porcentaje ) 
        values ( $id_tipo_doc, '$num_doc', 
                    (select case when tab0.id_concep_rein is null then tab0.id_concep_nomina 
    else tab0.id_concep_rein end as id_concep_nomina
from no_concep_nomina tab0    
where tab0.id_concep_nomina = $id_concep_nomina)
                        , $id_periodo, round( $valor_liquidado, 0), 
        to_date('$fecha_desde','YYYY-MM-DD'), to_date('$fecha_hasta','YYYY-MM-DD'), $num_dias, round( $valor_base, 0), $porcentaje ) 
EOD;

                    //Para la ANM no aplica registro de devolucion retefuente - 20150715
                    //Se quita por el cambio del 20151119
//                if ($entidadCliente != 2) {
                    /**
                     * Ejecutar SQL
                     */
                    CN_TABLE::executeSQL($sql);
//                }
                }
            } else {
                $this->logMessage("[Liquidación] No es retefuente. Valores- " . $id_concep_nomina_rete . " - " . $id_concep_nomina);
            }
        } else {

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

//        $logPath = sfConfig::get('sf_log_dir') . '/liquidacion.log';
//        $custom_logger = new sfFileLogger(new sfEventDispatcher(), array('file' => $logPath));
//        $custom_logger->info("[Liquidación] memory_get_usage pre liquidar: " . CN_TABLE::convert(memory_get_usage()) . "\n");
//        unset($records, $record_var_bind, $record_bind, $record_liq, $record_consulta);
//        $custom_logger->info("[Liquidación] memory_get_usage post liquidar: " . CN_TABLE::convert(memory_get_usage()) . "\n");
    }

    /**
     * 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);
            $formula = str_replace($key, $value, $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'
     * 
     * Conceptos de $id_concep_nomina_for = 0, $id_tipo_proced_rete = 0, $id_concep_rete = 0, para retencion en la fuente - 201612123
     * 
     * @param type $arrayParametros
     * @param type $record_liq
     * @param type $record_consulta
     * @param type $vals_calc
     * @return int
     */
    private function resultadoParametros($arrayParametros, $record_liq, $record_consulta, $vals_calc, $id_concep_nomina_for = 0, $id_tipo_proced_rete = 0, $id_concep_rete = 0, $id_concep_rete_proc1 = 0, $tag_rete_contingente = 0) {

//        $logPath = sfConfig::get('sf_log_dir') . '/liquidacion.log';
//        $custom_logger = new sfFileLogger(new sfEventDispatcher(), array('file' => $logPath));
//
//        $custom_logger->info("[Liquidación] memory_get_usage ini resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");

        $tag_adicional = false;
        if (isset($record_liq['caracter_adic']) && $record_liq['caracter_adic'] == 'M') {
            $tag_adicional = true;
        }


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

            //Sacar caracter y numero(id_concep_nomina) para consulta
            $caracter = substr($key, 0, 1);

            //Valida Tag adicional - solo para los T
            if ($tag_adicional && $caracter == 'T') {
                $caracter = "M";
            }

            $id_concep_nomina = substr($key, 1);
            $this->logMessage("[Liquidación] Caracter: " . $caracter . ", numero: " . $id_concep_nomina . ", tag_rete_contingente: " . $tag_rete_contingente);


            /*
             * CYC: Valor y base extra rete contingente - 20191128
             * Se deja quemado por ahora el id agrupacion (114-APORTES VOLUNTARIOS-AFC LIQ RETEN) para no tener en cuenta
             */

            if ($tag_rete_contingente == 1) {

                //Sql
                $sql = <<<EOD
SELECT * FROM no_agrup_deta where id_agrup_concepto = 114 and id_concep_nomina = $id_concep_nomina                              
EOD;

                //Ejecutar SQL
                $record_contingente = CN_TABLE::executeSQL($sql);

                if (count($record_contingente) > 0) {
                    $this->logMessage("[Liquidación] Valor rete contingente por Caracter: " . $id_concep_nomina);
                    $tag_rete_contingente_cal = 1;
                } else {
                    $tag_rete_contingente_cal = 0;
                }
            } else {
                $tag_rete_contingente_cal = 0;
            }
            $this->logMessage("[Liquidación] Valor tag_rete_contingente_cal por Caracter: " . $tag_rete_contingente_cal);

            /*
             * 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
            //CYC: Valor y base extra rete contingente - 20191128
            if (count($record_consulta) > 0 && $tag_rete_contingente_cal == 0) {
//                $this->logMessage("[Liquidación] Caracter: " . $record_consulta[$caracter]['caracter'] . ", consulta: " . $record_consulta[$caracter]['consulta']);
//                die();
//                $consulta = $record[0]['consulta'];

                $this->logMessage("[Liquidación] Concat vals_calc: " . $caracter . $id_concep_nomina);
                if (!isset($vals_calc[$caracter . $id_concep_nomina])) {
                    $consulta = $record_consulta[$caracter]['consulta'];


                    /*
                     * Calculo cesantias intereses - 20200113
                     */
                    if (isset($record_liq['periodo_ces']) && $caracter == 'X') {
                        $this->logMessage("[Liquidación] Calculo cesantias intereses: " . $caracter . " - Periodo: " . $record_liq['periodo_ces']);
                        $consulta = str_replace('$id_periodo', $record_liq['periodo_ces'], $consulta);
                    }


                    /*
                     * Variables y estructura para manejo de consultas con variables bind - 20130829
                     */
                    //Reemplazo de $ por : para variables bind
//                $consulta = str_replace('$', ':', $consulta);
                    //Reemplazo de id_concep_nomina
                    $consulta = str_replace('$id_concep_nomina', $id_concep_nomina, $consulta);

                    /**
                     * Se adiciona para la consulta T que no tome el periodo 4-Prima Navidad, 
                     * y es formula de concepto de retencion, solo procedimiento 1 - 20161213
                     * Se coloca que omita tambien prima de servicios, solo procedimiento 1, (&& $mes == 12) - 20190614
                     */
                    $consulta_adic = " ";
                    if (($id_concep_nomina_for == $id_concep_rete || $id_concep_nomina_for == $id_concep_rete_proc1) && $caracter == 'T' && $id_tipo_proced_rete == 1) {
                        $consulta_adic = "  and per.id_tipo_periodo not in (4,3) ";
                    }

                    /*
                     * 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
                     * select nvl(sum(valor_liquidado),0) as valor from no_liquida_nomina where id_periodo = :periodo - ejemplo bind
                     */
                    //Sql
                    $sql = <<<EOD
$consulta
$consulta_adic                             
EOD;
                    /*
                     * Variables y estructura para manejo de consultas con variables bind - 20130829
                     */
//                $record_var_bind = array(
//                    'id_tipo_doc' => 'id_tipo_doc',
//                    'num_doc' => 'num_doc',
//                    'id_concep_nomina' => 'id_concep_nomina',
//                    'id_periodo' => 'id_periodo'
//                );
                    //Get the variables within the consulta
//        $custom_logger->info("[Liquidación] memory_get_usage 1 resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");
//                $vars = array();
//                CN_TABLE::getVarsInConsulta($vars, $sql);
//                $record_var_bind = $vars;
////                var_dump($record_var_bind);
//                $record_bind = $record_liq;
//                $record_bind['id_concep_nomina'] = $id_concep_nomina;
                    //Ejecutar SQL
                    $record = CN_TABLE::executeSQL($sql);
//                $sql = str_replace("'", null, $sql);
//                $custom_logger->info("[Liquidación] memory_get_usage 2 resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");
//                $record = CN_TABLE::executeBindSQL($sql, null, $record_var_bind, $record_bind);
//                $custom_logger->info("[Liquidación] memory_get_usage 3 resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");
                    /*
                     * Validar registros SQL
                     */
                    if (count($record) > 0) {
                        $valor = $record[0]['valor'];
                    } else {
                        $valor = 0;
                    }
                    $vals_calc[$caracter . $id_concep_nomina] = $valor;
                }
                $valor = $vals_calc[$caracter . $id_concep_nomina];
            } else {
                $valor = 0;
            }

            $arrayParametros[$key] = $valor;

            $this->logMessage("[Liquidación] Valor por Caracter: " . $valor);
        }
        //Destruye una variable especificada
//        $custom_logger->info("[Liquidación] memory_get_usage pre resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");
//        unset($vars, $record_var_bind, $record_bind, $record_liq, $record, $key, $sql, $valor, $record_consulta, $consulta, $caracter);
//        $custom_logger->info("[Liquidación] memory_get_usage post resultadoParametros: " . CN_TABLE::convert(memory_get_usage()) . "\n");
        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();
        $arrayParametros = 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;
    }

    /**
     * Ejecutar Formula, para la minima 20150429
     * 
     * @param type $formula
     * @param type $arrayConstantes
     * @param int $record_liq
     * @param type $record_consulta
     * @param type $vals_calc
     * @return int
     */
    public function ejecutarFormula($formula, $arrayConstantes, $record_liq, $record_consulta, $vals_calc, $id_concep_nomina_for = 0, $id_tipo_proced_rete = 0, $id_concep_rete = 0, $tag_rete_contingente = 0) {

        $this->logMessage("[Liquidación] Entro a calcular Formula.");


        $this->logMessage("[Liquidación] 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, $record_consulta);
        $this->logMessage("[Liquidación] 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] 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] Agrupacion: " . $agrup);

                $formula = str_replace('{' . $var . '}', $agrup, $formula);
            }
        }
        $this->logMessage("[Liquidación] 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, $record_consulta, $vals_calc, $id_concep_nomina_for, $id_tipo_proced_rete, $id_concep_rete, $tag_rete_contingente);

        /*
         * Reemplazo de parametros(variables) a la formula
         * Ejemplo: $arrayParametros = array(
         * 'C1' => '1100',
         * 'C2' => '55'
         * );
         */
        $formula = $this->reemplazoParametros($formula, $arrayParametros);
        $this->logMessage("[Liquidación] 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] Formula No cumple con la condicion: " . $formula);
            $result = 0;
        }


        /*
         * Acumulan resultados de liquidacion
         */
        $valor_liquidado = $result;

        return $valor_liquidado;
    }

}
