<?php

// Ignorar los abortos hechos por el usuario y permitir que el script
// se ejecute para siempre
ignore_user_abort(true);
set_time_limit(0);

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

    public function executeList(sfWebRequest $request) {

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

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


        /*
         * Manejar Errores
         */
        try {


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


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

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

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

            /**
             * Operacion
             */
            if (isset($request['accion_filtro'])) {
                $accion_filtro = true;
            } else {
                $accion_filtro = false;
            }
//            $accion_filtro = true;


            /*
             * Paginacion
             */
            if (isset($request['_startRow'])) {
                $rowStart = $request['_startRow'];
            } else {
                $rowStart = 0;
            }

            if (isset($request['_endRow'])) {
                $rowEnd = $request['_endRow'];
            } else {
                $rowEnd = 75;
            }

            //ordenar consulta
            if (isset($request['_sortBy'])) {
                $sortBy = " Order by " . $request['_sortBy'];
            } else {
                $sortBy = ' Order by num_doc, id_clase_fondo, tipo_planilla ';
            }

            /*
             * Variables
             */
            //"A" para el registro que se mando en ese mes  y una 
            //"C" para el registro de correción, de como debio haber sido.
            $vigencia = date('Y');
            $mes = date('m');
            $id_periodo = $request['id_periodo_filtro'];
            $id_periodo_actual = $request['id_periodo'];
            $progress_key = $request['progress_key'] . $request['username'];

            //extras de correccion
            $id_periodo_retro = $request['id_periodo_retroA'] . ',' . $request['id_periodo_retroB'];
            $num_planilla = $request['num_planilla'];
            $fecha_pago = $request['fecha_pago'];

            //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'];
            }
            //id_clase_fondo
            $whereClaseFondo = "";
            if (isset($request['id_clase_fondo'])) {
                $whereClaseFondo = " AND tab0.id_clase_fondo = " . $request['id_clase_fondo'];
            }
            //id_mae_fondos
            $whereMaestroFondos = "";
            if (isset($request['id_mae_fondos'])) {
                $whereMaestroFondos = " AND tab0.id_mae_fondos = " . $request['id_mae_fondos'];
            }

            //solo imprime log la primera vez de consulta
            if ($rowStart == 0) {
                $this->logMessage("Generar aportes.");

                if ($accion_filtro) {

                    //sentencia sql
                    $sql = <<<EOD
delete from NO_LIQUIDA_APORTE tab0 
where tab0.id_periodo = $id_periodo 
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab0.tipo_planilla = 'C'                            
EOD;
                    //ejecuta y obtiene el resultado del sql
                    CN_TABLE::executeSQL($sql);

                    /*
                     * Verifique que el funcionario este afiliado a todos los fondos.
                     */
                    //Sql
                    $sql = <<<EOD
select tab0.num_doc, count(tab0.id_afilia_fondo) 
from no_afilia_fondo tab0
where tab0.estado = 1
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
having count(tab0.id_afilia_fondo) < (select count(*) from no_clase_fondo)
group by tab0.num_doc 
EOD;
                    //Ejecutar SQL
                    $record_total = CN_TABLE::executeSQL($sql);
//                    if (count($record_total) == 0) {
                    if (0 == 0) {

                        //sentencia sql
                        $sql = <<<EOD
INSERT INTO NO_LIQUIDA_APORTE (ID_CLASE_FONDO,ID_MAE_FONDOS,ID_CONCEP_NOMINA,ID_TIPO_DOC,NUM_DOC,
    VALOR_BASE,NUM_DIAS,
APORTE_FUNC,APORTE_PATRONO,ID_CEN_OP,ID_TIPO_APORTE,PORCENTAJE_FUNC,PORCENTAJE_PATRONO,TARIFA,
    ID_PERIODO, UPC_ADICIO, VALOR_BASE_FSP,
    ID_TAE, ID_TAP, TIPO_PLANILLA, NUM_PLANILLA, FECHA_PAGO )

select 
tab0.id_clase_fondo,
tab0.id_mae_fondos,
tab0.id_concep_nomina,
tab0.id_tipo_doc,
tab0.num_doc,
                                
0 as valor_base,                                
tab0.num_dias,

(   
select nvl(sum(valor_liquidado),0) from no_liquida_nomina 
where id_periodo = tab0.id_periodo and id_tipo_doc = tab0.id_tipo_doc 
and num_doc = tab0.num_doc and id_concep_nomina = tab0.id_concep_nomina
) + (   
select nvl(sum(valor_liquidado),0) from no_liquida_nomina 
where id_periodo_ajuste = tab0.id_periodo and id_tipo_doc = tab0.id_tipo_doc 
and num_doc = tab0.num_doc and id_concep_nomina = tab0.id_concep_nomina
) AS aporte_func,
0 AS aporte_patrono, 
                                
tab0.id_cen_op,
tab0.id_tipo_aporte,
tab0.porcentaje_func,
tab0.porcentaje_patrono,
tab0.tarifa,
tab0.id_periodo,
tab0.upc_adicio,
tab0.valor_base_fsp,
tab0.id_tae,
tab0.id_tap,
                                
'C' as tipo_planilla,
'$num_planilla' as num_planilla,
to_date('$fecha_pago','yyyy-mm-dd') as fecha_pago

from NO_LIQUIDA_APORTE  tab0

where tab0.id_periodo= $id_periodo 
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc 
and tab0.tipo_planilla = 'A' 
/*
Este usuario se deja quemado para que no salga - 20131022
*/
and (
  case when 
  tab0.num_doc = '52992037' and
  (select id_anhos || lpad(id_meses,2,'0') as vigper from no_periodo where id_periodo = $id_periodo) = '201301'
  then 1
  else 0
  end  
) =  0
EOD;

//and tab0.actual = 1 
//and afilia.estado = 1
                        //ejecuta y obtiene el resultado del sql
                        CN_TABLE::executeSQL($sql);

                        $sql = <<<EOD
SELECT 
$salario_minimo as salario_minimo,
1 as tag,    
tab0.num_dias as num_dias, 
nvl(vac.num_dias_vac,0) as wdiasv,
tab0.porcentaje_func,
tab0.porcentaje_patrono,
tab0.aporte_func,
tab0.aporte_patrono,
tab0.id_tipo_doc,
tab0.num_doc, 
tab0.id_clase_fondo, 
tab0.id_concep_nomina, 
tab1.id_agrup_concepto, 
tab2.id_meses, 
tab2.id_anhos,
tab0.tarifa, 
tab0.id_liquida_aporte, 
tab0.id_periodo as periodo
FROM NO_LIQUIDA_APORTE tab0
LEFT JOIN NO_CLASE_FONDO tab1 ON tab1.id_clase_fondo = tab0.id_clase_fondo
LEFT JOIN NO_PERIODO tab2 ON tab2.id_periodo = tab0.id_periodo

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 dias_vac,
 nvl(sum(DIAS_RANGO_MES_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo))),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
    (select id_anhos || lpad(id_meses,2,'0') as vigper from no_periodo where id_periodo = novvac.id_periodo) <= (select id_anhos || lpad(id_meses,2,'0') as vigper from no_periodo where 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
      or 
      novvac.id_periodo = $id_periodo
    )
 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.ID_PERIODO = $id_periodo
$whereFuncionarioNumDoc $whereFuncionarioTipoDoc
and tab0.tipo_planilla = 'C'    
                                
order by
tab0.num_doc    
EOD;


                        /**
                         * Recorre los registros de no_liquida_aporte
                         */
                        $records = CN_TABLE::executeSQL($sql);



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


                        $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("[generar_aportes] nom_conceptos_a_procesar: " . $nom_conceptos_a_procesar);

                        /*
                         * Log liquidacion.log registros uno a uno - Funcionarios
                         */
                        $logPath = sfConfig::get('sf_log_dir') . '/liquidacion.log';
                        $custom_logger = new sfFileLogger(new sfEventDispatcher(), array('file' => $logPath));

                        foreach ($records as $record) {

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

                            /*
                             * Variables del record
                             */
                            $id_liquida_aporte = $record['id_liquida_aporte'];
                            $id_tipo_doc = $record['id_tipo_doc'];
                            $num_doc = $record['num_doc'];
                            $id_clase_fondo = $record['id_clase_fondo'];
                            $id_concep_nomina = $record['id_concep_nomina'];
                            $id_agrup_concepto = $record['id_agrup_concepto'];
                            $id_meses = $record['id_meses'];
                            $id_anhos = $record['id_anhos'];
                            $tarifa = $record['tarifa'];
                            $aporte_func = $record['aporte_func'];


                            // Termina procesamiento de concepto
                            $custom_logger->info("Procesado $i de $nom_conceptos_a_procesar conceptos. Documento: " . $num_doc . "\n");


                            $arrayParametros = array();

                            $valor_base_vac = 0;

                            //Dias para vacaciones
                            //Se cambia a rango dias sin 31 - 20130705
                            //Se anexa para el operador la suma o resta - 20130726
                            //Se anexa filtro de rango de fechas para tomar solo vacaciones que afecten el periodo  - 20140122
                            //Sql
                            $sql = <<<EOD
select 

id_tipo_doc,                  
num_doc,
/*
dias,
dias_vac,
num_dias_vac,*/
sum( nvl(dias_vaciones,0) ) as num_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(DIAS_RANGO_MES_SIN_TREINTAYUNO(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo))),0) as num_dias_vac,
        tipnov.operador,

        case  when tipnov.operador  = 1 
        then nvl(sum(dias_rango_mes_sin_treintayuno(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo))),0) 
        else nvl(sum(dias_rango_mes_sin_treintayuno(novvac.fecha_ini,novvac.fecha_fin,(select id_meses from no_periodo where id_periodo =  $id_periodo))),0) * (-1)
        --else nvl(sum( novvac.fecha_fin - novvac.fecha_ini + 1),0) * (-1)
        end as dias_vaciones
    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.num_doc = $num_doc
    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
    ) 
    group by novvac.id_tipo_doc, novvac.num_doc,
    tipnov.operador
) 

group by id_tipo_doc, 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]['num_dias_vac'];
                            }
                            $this->logMessage("[Liquidación Vac] Dias Vacaciones: " . $wdiasv);
                            //Validar que hay dias
                            if ($wdiasv != 0) {

                                $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, $record, $record_consulta);

                                $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);
                            $this->logMessage("---------------------------------------------------------------------");


                            // 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("[generar_aportes] Existen aportes.");

                            $arrayParametros = array();

                            // Se agrega al calculo la formula (({A39}/30)*$wdiasv)) - 20130517
                            // Toma los dias de vacaciones para el mes a liquidar
                            $wdiasv = $record['wdiasv'];
                            $num_dias = $record['num_dias'];
                            /*
                             * Solo para ARP id_clase_fondo 3 no se tiene encuenta el tiempo de vacaciones - 20130917
                             * Para el IBC de Riesgos no se tiene en cuenta la novedad de vacaciones, el valor base y los días deben ser sin contemplar estos días. - 20130917
                             * Para los parafiscales tampoco se tiene encuenta el valor base de vacaciones - 20131023
                             */
                            if ($id_clase_fondo == 3 || $id_clase_fondo == 4 || $id_clase_fondo == 5 || $id_clase_fondo == 6) {
                                $formula = "({A$id_agrup_concepto}+(0))";
                            } else {
                                $formula = "({A$id_agrup_concepto}+($valor_base_vac))";
                            }
                            $this->logMessage("[Liquidación Agrupación] Formula Inicial: " . $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);
                            $this->logMessage("[Liquidación Agrupació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 Agrupación] Agrupacion: " . $agrup);

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



                            /*
                             * Cambio de A1 por relacion con los conceptos C1
                             * Ejemplo: 'A1' => '0'
                             */
//                            $agrup = $this->reemplazoAgrupacion($id_agrup_concepto);
//                            $this->logMessage("[Liquidación Agrupación] Agrupacion: " . $agrup);


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


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


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

                            $valor_base = round($result, -3);

                            //Base del valor smlv por los dias del funcionario - 20130625
                            //Valor sin redondeo - 20130923
//                            $valor_base_smlv = round(($salario_minimo / 30) * $num_dias, -3);
                            $valor_base_smlv = ($salario_minimo / 30) * $num_dias;

                            //Valor base no puede superar 25 salarios minimos
                            if ($valor_base > ($salario_minimo * 25)) {
                                $this->logMessage("[Liquidación Agrupación] Valor base no puede superar 25 salarios minimos.");
//                            $this->logMessage("[Liquidación Agrupación] Valor base Calculo: " . ($salario_minimo));
                                $valor_base = round(($salario_minimo * 25) - 1, -3);
                            }
                            //Valida salario minimo - 20130523
                            elseif ($valor_base < $valor_base_smlv) {
                                //Solo para ARP id_clase_fondo 3 - 20130523
                                if ($id_clase_fondo == 3) {
                                    $this->logMessage("[Liquidación Agrupación] ARP id_clase_fondo 3.");
                                    $valor_base = $valor_base_smlv;
                                }
                            }

                            $this->logMessage("[Liquidación Agrupación] Valor base: " . $valor_base);

                            //round ( $valor_base * tarifa / 100 , -2)
                            //Proceos para calcular el total del aporte redondeado a la centena
                            $valor_calculo = ( $valor_base * $tarifa / 100 );

                            if (($valor_calculo + 50) == round($valor_calculo, -2)) {
                                $valor_calculo = $valor_calculo - 50;
                            } else {
                                $valor_calculo = round($valor_calculo, -2);
                            }

                            $aporte_func = $aporte_func;

                            /**
                             * Validar valor base menor al del registro original tipo A < C - 20140506
                             */
                            //Sql
                            $sql = <<<EOD
select 
    MAX(nvl(tab0.valor_base,0)) as valor_base,
    tab0.num_doc, 
    case when sum(tab0.aporte_patrono) != sum(tab1.aporte_patrono) then sum(tab0.aporte_func) else 0 end as aporte, 
    case when sum(tab0.aporte_patrono) != sum(tab1.aporte_patrono) then sum(tab0.aporte_patrono) else 0 end as aporte_patrono,
    case when sum(tab0.aporte_patrono) != sum(tab1.aporte_patrono) then max(tab0.num_dias) else 0 end as dias,
    case when sum(tab0.aporte_patrono) != sum(tab1.aporte_patrono) then MAX(nvl(tab0.valor_base,0)) else 0 end as IBC,
    case when sum(tab0.aporte_patrono) != sum(tab1.aporte_patrono) then max(tab0.tarifa)/100 else 0 end as tarifa,
    sum(tab0.aporte_patrono) as aporte_patrono_a,      
    sum(tab1.aporte_patrono) as aporte_patrono_c
    
    from no_liquida_aporte tab0
    
    left join no_liquida_aporte tab1
    on tab1.id_periodo = tab0.id_periodo
    and tab1.id_tipo_doc = tab0.id_tipo_doc
    and tab1.num_doc = tab0.num_doc
    and tab1.id_mae_fondos = tab0.id_mae_fondos
    and tab1.id_concep_nomina = tab0.id_concep_nomina
    and tab1.id_clase_fondo = $id_clase_fondo
    and tab1.tipo_planilla = 'C'
    and tab1.tarifa = $tarifa
    
    where tab0.id_periodo = $id_periodo
    and tab0.num_doc = $num_doc 
    and tab0.id_clase_fondo = $id_clase_fondo
    and tab0.tipo_planilla = 'A'   
    and tab0.tarifa = $tarifa
    
    group by tab0.num_doc
EOD;

                            //Ejecutar SQL
                            $record_vac_valida = CN_TABLE::executeSQL($sql);
                            $valor_base_valida = $record_vac_valida[0]['valor_base'];
                            //Validar valor base menor al del registro original tipo A < C - 20140506
                            if ($valor_base_valida < $valor_base) {
                                /*
                                 * Actualizar registro aporte
                                 * Se calcula el valor del patrono, valor total aporte calculado menos el aporte funcionario
                                 */
                                //sentencia sql
                                $sql = <<<EOD
update NO_LIQUIDA_APORTE set valor_base = $valor_base
        , aporte_patrono =  case when porcentaje_patrono > 0 then $valor_calculo - $aporte_func else 0 end 
            , aporte_func =  case when porcentaje_patrono = 0 then $valor_calculo else $aporte_func end
    where id_liquida_aporte = $id_liquida_aporte 
EOD;
                                //ejecuta y obtiene el resultado del sql
                                CN_TABLE::executeSQL($sql);
                            } else {


                                $valor_base = $valor_base_valida;
                                $aporte = $record_vac_valida[0]['aporte'];
                                $aporte_patrono = $record_vac_valida[0]['aporte_patrono'];

                                /*
                                 * Actualizar registro aporte
                                 * Se calcula el valor del patrono, valor total aporte calculado menos el aporte funcionario
                                 */
                                //sentencia sql
                                $sql = <<<EOD
update NO_LIQUIDA_APORTE set valor_base = $valor_base
        , aporte_patrono =  $aporte_patrono  
            , aporte_func =  $aporte     
                where id_liquida_aporte = $id_liquida_aporte 
EOD;
                                //ejecuta y obtiene el resultado del sql
                                CN_TABLE::executeSQL($sql);
                            }


                            /*
                             * Valida si es fondo de solidaridad
                             */
                            if ($id_clase_fondo == 1 && $tarifa == 1) {
//                        if (true) {

                                $valor_base_vac = 0;
                                $array_valor_base = $this->valor_base_fsp($valor_base, $salario_minimo, $valor_base_vac);
                                $valor_fsp = $array_valor_base['valor_fsp'];
                                $porcentaje_fsp = $array_valor_base['porcentaje_fsp'];


                                $valor_base_fsp = CN_TABLE::redondeoValor(($valor_base * 0.5 / 100), -2);

                                //Validar que el valor fsp es mayor a cero
                                if ($valor_fsp > 0) {

                                    /*
                                     * Actualizar valor aporte_func
                                     */
                                    //sentencia sql
                                    $sql = <<<EOD
update NO_LIQUIDA_APORTE set aporte_func =  $valor_fsp
        , porcentaje_func = $porcentaje_fsp
            , valor_base_fsp = $valor_base_fsp 
    where id_liquida_aporte = $id_liquida_aporte 
EOD;
                                    //ejecuta y obtiene el resultado del sql
                                    CN_TABLE::executeSQL($sql);
                                } else {

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


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

                            $i++;



                            $this->conn->commit();
                        }
                        MemcacheHandler::getInstance()->set($progress_key, 99);
                    } else {


                        $this->conn->commit();

                        MemcacheHandler::getInstance()->set($progress_key, 99);
                        $mensaje = "Verifique que el funcionario(s) este afiliado a todos los fondos.";

                        $this->status = 2;
                        $this->mensajeError = $mensaje;
                    }
                } else {
                    $this->conn->commit();
                }
            } else {
                $this->conn->commit();
            }




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

            /*
             * sql que trae los resultados
             * por los filtros, para totalizar las filas
             */
            $sql = <<<EOD
select count(*) as count from (

SELECT * 

FROM (

    select 

    tab0.id_liquida_aporte,
    tab0.id_clase_fondo,
    tab0.id_mae_fondos,
    tab0.id_concep_nomina,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.valor_base,
    tab0.num_dias,
    tab0.aporte_func,
    tab0.aporte_patrono,
    tab0.id_cen_op,
    tab0.id_tipo_aporte,
    tab0.porcentaje_func,
    tab0.porcentaje_patrono,
    tab0.tarifa,
    tab0.id_periodo,
    tab0.upc_adicio,
    tab0.valor_base_fsp,
    tab0.id_tae,
    tab0.id_tap,
    tab0.tipo_planilla,
    tab0.num_planilla,
    tab0.fecha_pago,
    tab1.razon_social as fondo, 
    tab2.descripcion as clase_fondo,
    tab3.codigo||' - '||tab3.descripcion as concepto,
    tab4.nombre_apellido as nombre_apellido,
    tab4.nombre_completo as nombre_completo

    from NO_LIQUIDA_APORTE  tab0
    left join NO_DATOS_FUNCIONARIO_V tab4 ON tab4.id_tipo_doc = tab0.id_tipo_doc and tab4.num_doc = tab0.num_doc            
    left join NO_MAE_FONDOS tab1 ON tab1.id_mae_fondos = tab0.id_mae_fondos
    left join NO_CLASE_FONDO tab2 ON tab2.id_clase_fondo = tab0.id_clase_fondo
    left join NO_CONCEP_NOMINA tab3 ON tab3.id_concep_nomina = tab0.id_concep_nomina
    WHERE tab0.id_periodo = $id_periodo 
    $whereFuncionarioNumDoc $whereFuncionarioTipoDoc
    $whereClaseFondo $whereMaestroFondos
    and tab0.tipo_planilla = 'C'   
)

)
EOD;


            $total_record_count = CN_TABLE::executeSQL($sql);
            $total_record_count = $total_record_count[0]["count"];

            /*
             * Obtiene las vigencias/periodo que se encuentre en la tabla de saldos
             */
            $sql = <<<EOD
SELECT * FROM ( SELECT row_.*, ROWNUM rownum_ FROM (
    
SELECT * 

FROM (

    select 

    tab0.id_liquida_aporte,
    tab0.id_clase_fondo,
    tab0.id_mae_fondos,
    tab0.id_concep_nomina,
    tab0.id_tipo_doc,
    tab0.num_doc,
    tab0.valor_base,
    tab0.num_dias,
    tab0.aporte_func,
    tab0.aporte_patrono,
    tab0.id_cen_op,
    tab0.id_tipo_aporte,
    tab0.porcentaje_func,
    tab0.porcentaje_patrono,
    tab0.tarifa,
    tab0.id_periodo,
    tab0.upc_adicio,
    tab0.valor_base_fsp,
    tab0.id_tae,
    tab0.id_tap,
    tab0.tipo_planilla,
    tab0.num_planilla,
    tab0.fecha_pago,
    tab1.razon_social as fondo, 
    tab2.descripcion as clase_fondo,
    tab3.codigo||' - '||tab3.descripcion as concepto,
    tab4.nombre_apellido as nombre_apellido,
    tab4.nombre_completo as nombre_completo

    from NO_LIQUIDA_APORTE  tab0
    left join NO_DATOS_FUNCIONARIO_V tab4 ON tab4.id_tipo_doc = tab0.id_tipo_doc and tab4.num_doc = tab0.num_doc            
    left join NO_MAE_FONDOS tab1 ON tab1.id_mae_fondos = tab0.id_mae_fondos
    left join NO_CLASE_FONDO tab2 ON tab2.id_clase_fondo = tab0.id_clase_fondo
    left join NO_CONCEP_NOMINA tab3 ON tab3.id_concep_nomina = tab0.id_concep_nomina
    WHERE tab0.id_periodo = $id_periodo 
    $whereFuncionarioNumDoc $whereFuncionarioTipoDoc
    $whereClaseFondo $whereMaestroFondos
    and tab0.tipo_planilla = 'C'   
)

$sortBy
          
) row_ WHERE ROWNUM <=  $rowEnd   ) where rownum_ >  $rowStart
EOD;

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

            //Ejecuta sql
            $this->totalRows = $total_record_count;
            $this->startRow = $rowStart;
            $this->endRow = $rowStart + count($records);
            $this->list_data = $records;

            $this->conn->commit();

            MemcacheHandler::getInstance()->set($progress_key, 100);
        } catch (Exception $e) {

            $mensaje = "[generar_aportes] ERROR!!!";

            $this->status = 1;
            $this->mensajeError = $mensaje;
            $this->list_data = array();
            $this->logMessage($mensaje);
            $this->logMessage($e->getMessage());

            $this->conn->rollback();
        }
    }

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

        $valor = 0;
        $valorfps1 = 0;
        $valorfps2 = 0;
        $porcentaje = 0;

        /*
         * Operaciones
         */

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

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

        $valor = CN_TABLE::redondeoValor($valorfps1, -2) + CN_TABLE::redondeoValor($valorfps2, -2);

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

        return $array_fsp;
    }

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

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

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

        return $formula;
    }

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

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

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

        return $formula;
    }

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

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

            $record = array();
            $consulta = "";
            //Sacar caracter y numero(id_concep_nomina) para consulta
            $caracter = substr($key, 0, 1);
            $id_concep_nomina = substr($key, 1);
            $this->logMessage("[Liquidación] 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);

                /*
                 * Ejecutar SQL de consulta
                 */
                //Sql
                $sql = <<<EOD
$consulta  
EOD;
                //Ejecutar SQL
//                $record = CN_TABLE::executeSQL($sql);
                //Validar registros SQL
                if (count($record) > 0) {
                    $valor = $record[0]['valor'];
                } else {
                    $valor = 0;
                }
            } else {
                $valor = 0;
            }


            /*
             * Correccion Autoliquidacion - 20130717
             * Busca valores en los periodo de retroactivo
             * Se anexa consulta de Tipo segun la letra para hacer una sola, con el anexo del retroactivo - 20130731
             */
            //Sql
            $consulta_liq = '
(select nvl(sum(valor_liquidado),0) as valor     
from no_liquida_nomina where id_periodo_ajuste in ( select distinct id_periodo from no_periodo where id_tipo_periodo in (1,2) and (id_anhos, id_meses) in (SELECT ID_ANHOS, id_meses FROM NO_PERIODO WHERE ID_PERIODO = $periodo))  
and num_doc =  $num_doc  
and id_tipo_doc = $id_tipo_doc and id_concep_nomina = $id_concep_nomina )
';
            //Sql
            $consulta = <<<EOD
select 

( 
   $consulta_liq                   
    )
 + ( 
     $consulta 
      )  as valor 

from dual 
EOD;


//            $consulta = str_replace('$', ':', $consulta);
            //$consulta = 'select nvl(sum(valor_liquidado),0) as valor from no_liquida_nomina where id_periodo_ajuste = $periodo and num_doc = $num_doc and id_tipo_doc = $id_tipo_doc and id_concep_nomina = $id_concep_nomina';
            //Reemplazo de id_concep_nomina
            $consulta = str_replace('$id_concep_nomina', $id_concep_nomina, $consulta);

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

            /*
             * Ejecutar SQL de consulta
             * select nvl(sum(valor_liquidado),0) as valor from no_liquida_nomina where id_periodo = :periodo - ejemplo bind
             */
            //Sql
            $sql = <<<EOD
$consulta  
EOD;
            //Ejecutar SQL
            $record = CN_TABLE::executeSQL($sql);
//            $record = CN_TABLE::executeBindSQL($sql, null, $record_liq);
            //Validar registros SQL
            if (count($record) > 0) {
                $valor_correc = $record[0]['valor'];
            } else {
                $valor_correc = 0;
            }

            $arrayParametros[$key] = $valor + $valor_correc;
            $this->logMessage("[Liquidación] Valor por caracter: " . $valor + $valor_correc);
        }

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

}
