<?php

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

    /**
     * Executes List actions
     *
     * @param sfRequest $request A request object
     */
    public function executeList(sfWebRequest $request) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("Entro a executeAdd");


        $records = array();
        $arrayConstantes = array();


        /*
         * Abrir conexion transaccion
         */
        $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
        $this->conn->beginTransaction();


        /*
         * Manejar Errores
         */
        try {

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

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



            //PARAMETROS
            $id_periodo = $periodo = $request['id_periodo_filtro'];
            $id_periodo_ini = $request['id_periodo_ini'];
            $id_periodo_fin = $request['id_periodo_fin'];
            $progress_key = $request['progress_key'] . $request['username'];


            /*
             * Variables opcionales
             */
            //funcionario
            if (isset($request['num_doc'])) {
                $whereFuncionarioNumDoc = " AND tab0.num_doc = " . $request['num_doc'];
            } else {
                $whereFuncionarioNumDoc = ' ';
            }
            //funcionario
            if (isset($request['id_tipo_doc'])) {
                $whereFuncionarioTipoDoc = " AND tab0.id_tipo_doc = " . $request['id_tipo_doc'];
            } else {
                $whereFuncionarioTipoDoc = ' ';
            }

            //sentencia sql
            $sql = <<<EOD
ALTER SESSION SET NLS_DATE_FORMAT = "YYYY-MM-DD"
EOD;
            //ejecuta y obtiene el resultado del sql
            CN_TABLE::executeSQL($sql);

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

            $sql = <<<EOD
delete from no_liquida_nomina tab0 
                    
where 
tab0.id_concep_nomina in (
select distinct tab2.id_concep_nomina    
from no_param_concep tab1 
left join no_concep_nomina tab2 ON tab2.id_concep_nomina = tab1.id_concep_rete

union

select case when tab0.id_concep_ajuste is null then tab0.id_concep_nomina 
    else tab0.id_concep_ajuste end as id_concep_nomina
from no_concep_nomina tab0    
where tab0.id_concep_nomina = (select tab2.id_concep_nomina from no_param_concep tab1 
left join no_concep_nomina tab2 ON tab2.id_concep_nomina = tab1.id_concep_rete)

)     
and tab0.id_periodo = $periodo    
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc                        
EOD;
            //ejecuta y obtiene el resultado del sql
            //Se deja quemado id-44 periodo de retroactivo inactivos INCI para no liquidar - 20130913
            if ($id_periodo != 44) {
                CN_TABLE::executeSQL($sql);
            }


            /*
             * Liquida el periodo nuevo de retroactivo
             */
            $sql = <<<EOD
select
$id_periodo as id_periodo
from dual
EOD;

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


            $this->conn->commit();

            /*
             * Recorre los registros de funcionario - concepto nomina
             * para ser liquidados
             */
            $i = 1;
            $nom_conceptos_a_procesar = count($results);

//            // 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 Retroactivo Retefuente] 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));
            //For de liquidar por cada periodo entre el rango
            foreach ($results as $resul) {


                $id_periodo_ajuste = $resul['id_periodo'];

                //llamar para cada periodo y liquidar
                //Se deja quemado id-44 periodo de retroactivo inactivos INCI para no liquidar - 20130913
                if ($id_periodo != 44) {
                    $this->liquidarRetroactivo($id_periodo, $id_periodo_ajuste, $progress_key, $record_consulta, $arrayConstantes, $whereFuncionarioNumDoc, $whereFuncionarioTipoDoc);
//MemcacheHandler::getInstance()->set($progress_key, 100);
//exit();
                    // Guardar un valor en el proceso largo
//                if ($i % $brecha == 0) {
//                    MemcacheHandler::getInstance()->set($progress_key, round(($i / $nom_conceptos_a_procesar) * 100, 0));
//                }
                }

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

                $i++;
//                break;
            }



            /*
             * Abrir conexion transaccion
             */
            $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
            $this->conn->beginTransaction();

            /*
             * Cambiar id_concepto_nomina por el de ajuste
             */
            //sentencia sql
            $sql = <<<EOD
update no_liquida_nomina tab0
set tab0.id_concep_nomina = (
select case when tab0.id_concep_ajuste is null then tab0.id_concep_nomina 
    else tab0.id_concep_ajuste end as id_concep_nomina
from no_concep_nomina tab0    
where tab0.id_concep_nomina = (select tab2.id_concep_nomina from no_param_concep tab1 
left join no_concep_nomina tab2 ON tab2.id_concep_nomina = tab1.id_concep_rete)
)

where 
tab0.id_periodo = $id_periodo
and tab0.id_concep_nomina = (select tab2.id_concep_nomina from no_param_concep tab1 
left join no_concep_nomina tab2 ON tab2.id_concep_nomina = tab1.id_concep_rete)
$whereFuncionarioNumDoc
$whereFuncionarioTipoDoc                      
EOD;
            //ejecuta y obtiene el resultado del sql
            //CN_TABLE::executeSQL($sql);
//            MemcacheHandler::getInstance()->set($progress_key, 90);
            //COMMIT DE TODAS LAS TRANSACCIONES
            //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,ID_PERIODO_AJUSTE) 

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.ID_PERIODO_AJUSTE
from no_ajuste_nomina tab0
join no_periodo per
on per.id_periodo = tab0.id_periodo 
WHERE tab0.id_periodo = $id_periodo
--and tab0.id_periodo_ajuste in ( $id_periodo_ajuste )
and tab0.id_concep_nomina = (select id_concep_rete from no_param_concep where  id_param_concep = 1)                     
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);




            $this->conn->commit();
//            MemcacheHandler::getInstance()->set($progress_key, 100);



            /*
             * Abrir conexion transaccion 
             * Deducidos de no ley - 20150623
             */
            $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
            $this->conn->beginTransaction();
            $this->logMessage("[Liquidación Retroactivo Def] Deducidos de no ley.");

            /**
             * Trae registros de ded no ley para el periodo
             */
            $sql = <<<EOD
select 
                    
per.fecha_ini as fecha_desde,
per.fecha_fin as fecha_hasta,
tab0.* 
                    
from no_ded_noley tab0
join no_periodo per on tab0.id_periodo = per.id_periodo
                    
where
tab0.id_periodo = $id_periodo and tab0.estado = 1 
and tab0.num_doc in (select distinct num_doc from no_estado_func_v where periodo = $id_periodo)                   
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc  
                    
order by
tab0.num_doc  
EOD;
            //Ejecutar SQL
            $records = CN_TABLE::executeSQL($sql);

            //recorre cada ded no ley
            foreach ($records as $value) {

                $id_tipo_doc = $value['id_tipo_doc'];
                $num_doc = $value['num_doc'];
                $id_concep_nomina = $value['id_concep_nomina'];
                $valor_liquidado = $value['valor_cuota'];
                $fecha_desde = $value['fecha_desde'];
                $fecha_hasta = $value['fecha_hasta'];
                $num_dias = 30;
                $valor_base = 'null';
                $porcentaje = 'null';

                //elimina registro anterior
                $sql = <<<EOD
delete from no_liquida_nomina tab0 
where 
tab0.id_periodo = $id_periodo
and tab0.id_tipo_doc = $id_tipo_doc
and tab0.num_doc = $num_doc
and tab0.num_doc in (select distinct num_doc from no_estado_func_v where periodo = $id_periodo)
and tab0.id_concep_nomina = $id_concep_nomina  
EOD;
                //Ejecutar SQL
                $this->conn->execute($sql);

                //registra en no_liquida_nomina cada registro
                $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, id_periodo_ajuste ) 
        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, $id_periodo )  
EOD;
                //Ejecutar SQL
                $this->conn->execute($sql);
            }

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




            $records = array();

            $this->totalRows = 0;
            $this->startRow = 0;
            $this->endRow = 0;
            $this->list_data = $records;
            $this->logMessage("[Liquidación Retroactivo Retefuente] Liquidación exitosa.");
        } catch (Exception $e) {
//            MemcacheHandler::getInstance()->set($progress_key, 99);
            //ROLLBACK DE TODAS LAS TRANSACCIONES EN CASO DE QUE OCURRA ALGUN ERROR
            $this->conn->rollback();
//            MemcacheHandler::getInstance()->set($progress_key, 100);

            $this->status = 1;
            $this->totalRows = 0;
            $this->startRow = 0;
            $this->endRow = 0;
            $this->mensajeError = "[Liquidación Retroactivo Retefuente] Ocurrio un error: " . $e->getMessage();
            $this->list_data = array();
            $this->logMessage("[Liquidación Retroactivo Retefuente] 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 = 0;
        $valorfps1 = 0;
        $valorfps2 = 0;
        $porcentaje = 0;

        /*
         * Operaciones
         */

        if ($valor_base > ($salario_minimo * 4) && $valor_base <= ($salario_minimo * 16)) {
            $porcentaje = 1;
        } elseif ($valor_base > ($salario_minimo * 16) && $valor_base <= ($salario_minimo * 17)) {
            $porcentaje = 1.2;
        } elseif ($valor_base > ($salario_minimo * 17) && $valor_base <= ($salario_minimo * 18)) {
            $porcentaje = 1.4;
        } elseif ($valor_base > ($salario_minimo * 18) && $valor_base <= ($salario_minimo * 19)) {
            $porcentaje = 1.6;
        } elseif ($valor_base > ($salario_minimo * 19) && $valor_base <= ($salario_minimo * 20)) {
            $porcentaje = 1.8;
        } elseif ($valor_base > ($salario_minimo * 20)) {
            $porcentaje = 2;
        }

        $valorfps1 = round($valor_base * 0.5 / 100, -2);
        $valorfps2 = round($valor_base * ($porcentaje - 0.5) / 100, -2);

        $valor = $valorfps1 + $valorfps2;

        $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, $id_periodo_ajuste) {

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

        $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'   
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;

        /**
         * 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'];
        }


        //SGC - Se deja quemado id-518 periodo de retroactivo activos retefuente SGC para cambio al liquidar - 20140407
        if ($id_periodo == 518) {
            $id_concep_nomina = 61;
        }


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

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

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

            foreach ($records as $value) {

                //se adiciona un nuevo campo de formula para completar la retencion que es muy grande el proceso - 20210415::LAVILA
                $formula = $value['formula'] . $value['formula_adic'];
                $this->logMessage("[Liquidación Retroactivo] 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 Retroactivo] 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_liq);
                $this->logMessage("[Liquidación Retroactivo] 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 Retroactivo] 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);


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

                        /*
                         * Valor Base y porcentaje
                         */
                        $porcentaje = $record_liq['porcentaje'];
                        $valor_base = ($result * 100) / $record_liq['porcentaje'];
                    }
                }
            }
        } 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 Retroactivo] Calcular porcentaje - " . $record_liq['porcentaje']);


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

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

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

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

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

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

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

            $valor_liquidado += $result;
        }



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

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

            /**
             * Compara con la retencion anterior del mes del retro, consulta T - 20180227
             */
            //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  
EOD;
            //Ejecutar SQL
            $record_rete_t = CN_TABLE::executeSQL($sql);
            $this->logMessage("[Liquidación] Valor de consulta T = " . $record_rete_t[0]['valor']);

            $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) {

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

            /*
             * Crear nueva liquidación
             * 
             * Asignar valores encontrados en persona
             */
            //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, id_periodo_ajuste ) 
        values ( $id_tipo_doc, '$num_doc', $id_concep_nomina, $id_periodo, round( $valor_liquidado, -3), 
        to_date('$fecha_desde','YYYY-MM-DD'), to_date('$fecha_hasta','YYYY-MM-DD'), $num_dias, round( $valor_base, 0), 
                    $porcentaje, $id_periodo_ajuste ) 
EOD;
            //Ejecutar SQL
            CN_TABLE::executeSQL($sql);
        } else {

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

    /**
     * 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) {
            if (isset($value['valor'])) {
                $formula = str_replace($key, $value['valor'], $formula);
            }
        }

        return $formula;
    }

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

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

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

        return $formula;
    }

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

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

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

            /*
             * Obtener consulta por caracter
             */
//            //Sql
//            $sql = <<<EOD
//select * from NO_CONSULTA where caracter = '$caracter' 
//EOD;
//            //Ejecutar SQL
//            $record = CN_TABLE::executeSQL($sql);
            //Validar registros SQL
            if (count($record_consulta) > 0) {
//                $this->logMessage("[Liquidación] Caracter: " . $record_consulta[$caracter]['caracter'] . ", consulta: " . $record_consulta[$caracter]['consulta']);
//                die();
//                $consulta = $record[0]['consulta'];
                $consulta = $record_consulta[$caracter]['consulta'];

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

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

                /*
                 * No tener encuenta prima navidad - 20201113
                 */
                $consulta_adic = " ";
                if ($caracter == 'T') {
                    $consulta_adic = "  and per.id_tipo_periodo not in (4) ";
                }

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

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

            $arrayParametros[$key] = $valor;

            $this->logMessage("[Liquidación Retroactivo] Valor por Caracter: " . $valor);
        }
        return $arrayParametros;
    }

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

        $vars = array();

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

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

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

        return $arrayParametros;
    }

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

        $agrup = '( ';

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

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

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

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

        $agrup .= ' )';

        return $agrup;
    }

    /**
     * Metodo para liquidar un periodo unicamente
     * 
     * @param type $id_periodo
     * @param type $id_periodo_ajuste
     * @param type $progress_key
     * @param type $record_consulta
     * @param type $arrayConstantes
     * @param type $whereFuncionarioNumDoc
     * @param type $whereFuncionarioTipoDoc
     */
    public function liquidarRetroactivo($id_periodo, $id_periodo_ajuste, $progress_key, $record_consulta, $arrayConstantes, $whereFuncionarioNumDoc, $whereFuncionarioTipoDoc) {
        $this->logMessage("[Liquidación Retroactivo] Entro a liquidarRetroactivo");

        $i = 0;

        /**
         * Manejador de errores
         */
        try {
            /*
             * Abrir conexion transaccion
             */
            $this->conn = Doctrine_Manager::getInstance()->getCurrentConnection();
            $this->conn->beginTransaction();

            /*
             * 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,ID_PERIODO_AJUSTE) 

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.ID_PERIODO_AJUSTE
from no_ajuste_nomina tab0
join no_periodo per
on per.id_periodo = tab0.id_periodo 
WHERE tab0.id_periodo = $id_periodo
and tab0.id_periodo_ajuste = $id_periodo_ajuste 
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
EOD;
            //Ejecutar SQL
            //CN_TABLE::executeSQL($sql);


            /**
             * 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'];
            }

            /*
             * 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
             * Se agrega valor_uvt, 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
             * Solo retefunte
             * Campos de tabla no_concepto_periodo los que son no usar * - 20220426::LAVILA
             * Incidente #36193, se cambia id_tipo_periodo = 6 por in (6,7) para que tome tambien en retro retirado, 
             * se activa no_novedad_proced_rete a los que requiera - 20230808::LAVILA
             */
            //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
    
    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 in (6,7)
    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

join no_estado_func_v est
on est.periodo = $id_periodo
and est.id_tipo_doc = tab0.id_tipo_doc
and est.num_doc = tab0.num_doc

where tab0.periodo = $id_periodo
and tab0.id_periodo_ajuste = $id_periodo_ajuste     
$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 Retroactivo Retefuente] 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, $id_periodo_ajuste);

                // Termina procesamiento de concepto
//                file_put_contents('/home/lavila/Escritorio/liquidacion.log', "RETE - Procesado $i de $nom_conceptos_a_procesar conceptos.\n", FILE_APPEND);
//                $i++;
//                $custom_logger->info(MemcacheHandler::getInstance()->get($progress_key) . " - RETE - Procesado $i de $nom_conceptos_a_procesar conceptos. Funcionario: " . $num_doc . "\n");
            }

            //commit de las transacciones
            $this->conn->commit();
        } catch (Exception $exc) {
            $this->logMessage("[Liquidación Retroactivo Retefuente] ERROR!!! LiquidarRetroactivoRetefuente");
            $this->conn->rollback();
        }
    }

}
