<?php

class NominaPrestamos
{
    protected $nomina;
    public $totalCuotasConciliadas = null;
    public $recuperadoPorDefinicion = null;
    public $recuperadoPorConciliacion = null;

    public function __construct($nomina)
    {
        $this->nomina = $nomina;
    }

    protected function escenario($escenario)
    {
        switch ($escenario) {
            case 1:
                // Escenario 1: Si el monto pagado < Total nómina conciliada && monto_pagado < recuperado_conciliacion
                // cuando monto pagado no cubre "Recuperado por conciliación"
                return $this->nomina->getMontoPagado() < $this->totalCuotasConciliadas() &&
                       $this->nomina->getMontoPagado() < $this->recuperadoPorConciliacion();
            case 2:
                // Escenario 2: Si monto pagado >= recuperado_conciliacion && recuperado_definicion < monto_pagado
                // Cuando monto pagado no cubre la poción de  "Recuperado por definición".
                return $this->nomina->getMontoPagado() >= $this->recuperadoPorConciliacion() &&
                       $this->recuperadoPorDefinicion() < $this->nomina->getMontoPagado();
            case 3:
                // Escenario 3: si monto_pagado = total_nómina_conciliada
                return $this->nomina->getMontoPagado() == $this->totalCuotasConciliadas();
            case 4:
                // Escenario 3: monto_pagado > total_nómina_conciliada
                return $this->nomina->getMontoPagado() > $this->totalCuotasConciliadas();
        }
    }

    public function pagar()
    {
        switch (true) {
            case $this->escenario(4):
                $this->pagarEscenarioD();
                break;
            case $this->escenario(3):
                $this->pagarEscenarioC();
                break;
            case $this->escenario(1):
                $this->pagarEscenarioA();
                break;
            case $this->escenario(2):
                $this->pagarEscenarioB();
                break;
            default:
                throw new Exception('No se pudo determinar el escenario de pago');
        }

        $montoCuotasConciliadas = $this->totalCuotasConciliadas();

        if ($this->nomina->getMontoPagado() > $montoCuotasConciliadas) {
            $restante = $this->nomina->getMontoPagado() - $montoCuotasConciliadas;
        } else {
            $restante = 0;
        }

        //////////////////////////// Contabilización comprobante inicio ////////////////////////////
        Yii::import('application.modules.contable.models.comprobantes.*', true);
        Yii::import('application.modules.contable.models.comprobantes.retencion.*', true);
        (new PagoNominaPrestamos($this->nomina, $restante))->contabilizar();
        //////////////////////////// Contabilización comprobante fin ///////////////////////////////
    }

    protected function pagarEscenarioA()
    {
        $total = Math::execute(':monto_pagado / :total_cuotas_cargadas', [
            'monto_pagado' => $this->nomina->getMontoPagado(),
            'total_cuotas_cargadas' => $this->totalCuotasCargadas(),
        ], false);
        $montoRecuperadoAnterior = (new RecuperadoPorConciliacion($this->nomina))->datos();

        $monto_pagado = 0;
        $monto_remanente = 0;
        foreach ($this->getCuotasConciliadas() as $cuota) {
            $montoPagado = Math::execute(':cuota_cargada * :total_cuotas_cargadas', [
                'cuota_cargada' => $cuota->monto_cuota_pagado,
                'total_cuotas_cargadas' => $total,
            ], false);

            if ($montoPagado > $cuota->monto_cuota) {
                $cuota->monto_pagado = $cuota->monto_cuota;
                $cuota->monto_remanente = $montoPagado - $cuota->monto_cuota;
            } elseif ($montoPagado < $cuota->monto_cuota) {
                $cuota->monto_pagado = $montoPagado;
                $cuota->monto_cobro = $cuota->monto_cuota - $montoPagado;
            }

            $cuota->monto_cuota_pagado = Yii::app()->format->number($cuota->monto_cuota_pagado);

            if (! $cuota->update()) {
                throw new Exception('No se guardo la distribución del monto pagado');
            }

            $monto_pagado += $cuota->monto_pagado;
            $monto_remanente += $cuota->monto_remanente;
        }

        $this->cleanLoss($monto_pagado);

        foreach ($this->getCuotasConciliadas() as $cuota) {
            $this->historicoCobroDiferencial($cuota);
        }

        $montoRecuperadoActual = (new RecuperadoPorConciliacion($this->nomina))->datos();
        $sobrante = $montoRecuperadoAnterior['total'] - $monto_pagado;
        $porcionA = Math::execute(':a * :b / :c', [
            'a' => $sobrante,
            'b' => $montoRecuperadoAnterior['capital'],
            'c' => $montoRecuperadoAnterior['total'],
        ]);
        $porcionB = Math::execute(':a * :b / :c', [
            'a' => $sobrante,
            'b' => $montoRecuperadoAnterior['interes'],
            'c' => $montoRecuperadoAnterior['total'],
        ]);

        $a = 0;
        $b = 0;
        foreach ($this->getCuotasConciliadasMontoCobro() as $cuota) {
            $capital_cobro = Math::execute(':a * :b / :c', [
                'a' => $cuota->capital_pagado,
                'b' => $porcionA,
                'c' => $montoRecuperadoAnterior['capital'],
            ], false);
            $interes_cobro = Math::execute(':a * :b / :c', [
                'a' => $cuota->interes_pagado,
                'b' => $porcionB,
                'c' => $montoRecuperadoAnterior['interes'],
            ], false);

            $cobro = $cuota->cobroDiferencialCuota;
            $cobro->total_cobro = $capital_cobro + $interes_cobro;
            $cobro->capital_cobro = $capital_cobro;
            $cobro->interes_cobro = $interes_cobro;

            $a += $capital_cobro;
            $b += $interes_cobro;

            if (! $cobro->save()) {
                throw new Exception('No se pudo guardar la distribución cobro del diferencial');
            }
        }

        list($total_capital, $total_interes, $victima_capital, $victima_interes) = $this->montoPendienteRegistrado();

        if ($total_capital > $total_interes) {
            $diferenca_capital = bcsub($sobrante, $total_capital, 2);
            list($id, $monto_capital) = explode(' ', $victima_capital);
            if (round($sobrante, 2) < $total_capital) {
                $monto = $monto_capital - abs($diferenca_capital);
            } else {
                $monto = $monto_capital + abs($diferenca_capital);
            }
            CobroDiferencialCuota::model()->updateAll(['capital_cobro' => $monto], 'id=:id', ['id' => $id]);
        } else {
            $diferenca_interes = bcsub($b, $total_interes, 2);
            list($id, $monto_interes) = explode(' ', $victima_interes);

            if (round($b, 2) < $total_interes) {
                $monto = $monto_interes - abs($diferenca_interes);
            } else {
                $monto = $monto_interes + abs($diferenca_interes);
            }
            CobroDiferencialCuota::model()->updateAll(['interes_cobro' => $monto], 'id=:id', ['id' => $id]);
        }

        $this->pagoParcialCuotasGestionCobro();
        $this->pagadoCuotasAjusteDeduccionHaberes();
    }

    protected function pagarEscenarioB()
    {
        $this->procesarCuotasConciliadasFormaB();

        $factor = Math::execute('(:monto_pagado - :recuperado_conciliación) / (:total_cuotas_no_definidas + :remanente_cuotas_conciliadas)', [
            'monto_pagado' => $this->nomina->getMontoPagado(),
            'recuperado_conciliación' => $this->recuperadoPorConciliacion(),
            'total_cuotas_no_definidas' => $this->totalCuotasNoDefinidas(),
            'remanente_cuotas_conciliadas' => $this->totalCuotaRemanente(),
        ], false);
        foreach ($this->getCuotasSinDefinir() as $cuota) {
            $cuota->monto_conciliado = Math::execute(':monto_cuota * :factor', [
                'monto_cuota' => $cuota->monto_cuota,
                'factor' => $factor,
            ], false);
        }

        $this->pagoParcialCuotasGestionCobro();
        $this->pagadoCuotasSinDiferencialCobro();
        $this->pagadoCuotasAjusteDeduccionHaberes();
    }

    protected function pagarEscenarioC()
    {
        $this->procesarCuotasConciliadasFormaB();

        foreach ($this->getCuotasSinDefinir() as $cuota) {
            $cuota->monto_conciliado = $cuota->monto_cuota;
        }

        $this->pagoParcialCuotasGestionCobro();
        $this->pagadoCuotasSinDiferencialCobro();
        $this->pagadoCuotasAjusteDeduccionHaberes();
    }

    protected function pagarEscenarioD()
    {
        $this->procesarCuotasConciliadasFormaB();

        foreach ($this->getCuotasSinDefinir() as $cuota) {
            $cuota->monto_conciliado = $cuota->monto_cuota;
        }

        $this->pagarCuotasConciliadas();
        $this->pagoParcialCuotasGestionCobro();
        $this->pagadoCuotasAjusteDeduccionHaberes();

        $montoSobrante = $this->nomina->getMontoPagado() - $this->totalCuotasConciliadas();
        $montoSobranteFormateado = Yii::app()->format->number($montoSobrante);

        $proveedor = $this->nomina->getProveedor();

        OrdenPago::generar([
            'idproveedor' => $proveedor->id,
            'id_tipo_orden' => 1,
            'id_tipo_carga' => 3,
            'id_tipo_persona' => $proveedor->id_tipo_persona,
            'rif' => $proveedor->rif,
            'monto_pago' => $montoSobranteFormateado,
            'descripcion' => "Tipo: patrono {$this->nomina->getDescripcion()} Monto: {$montoSobranteFormateado}",
            'idbanco' => $proveedor->proveedorCuentaBancosPrincipal->id,
            'id_concepto' => ConceptosOrdenPago::proceso(8),
        ], 2);

        $pagoAdicional = new PagosAdicionales();
        $pagoAdicional->id_txt = $this->nomina->id;
        $pagoAdicional->tipo_aporte = 4;
        $pagoAdicional->monto_adicional = $montoSobrante;
        $pagoAdicional->fecha_transaccion = $this->nomina->getFechaOperacion();
        $pagoAdicional->usuario = Yii::app()->user->id;

        if (! $pagoAdicional->save()) {
            throw new Exception('No se pudo guardar el sobrante del pago');
        }
    }

    protected function procesarCuotasConciliadasFormaB()
    {
        $monto_pagado = 0;
        $cuotas = $this->getCuotasConciliadas();
        
        foreach ($cuotas as $cuota) {
            if ($cuota->monto_cuota_pagado <= $cuota->monto_cuota) {
                $cuota->monto_pagado = $cuota->monto_cuota_pagado;
            } else {
                $cuota->monto_pagado = $cuota->monto_cuota;
            }

            if ($cuota->monto_pagado > $cuota->monto_cuota) {
                $cuota->monto_remanente = $cuota->monto_pagado - $cuota->monto_cuota;
            } elseif ($cuota->monto_pagado < $cuota->monto_cuota) {
                $cuota->monto_cobro = $cuota->monto_cuota - $cuota->monto_pagado;
            }

            $monto_pagado += $cuota->monto_pagado;

            $afectedRecords = DatosTxtTablaAmortizacion::model()->updateAll([
                'monto_pagado' => $cuota->monto_pagado,
                'monto_remanente' => $cuota->monto_remanente,
                'monto_cobro' => $cuota->monto_cobro,
                'monto_cuota_pagado' => $cuota->monto_cuota_pagado,
            ], "id={$cuota->id}");

            if ($afectedRecords != 1) {
                throw new Exception('No se guardo la distribución del monto pagado');
            }
        }

        $this->cleanLoss($monto_pagado);

        foreach ($cuotas as $cuota) {
            $this->historicoCobroDiferencial($cuota);
        }
    }

    protected function historicoCobroDiferencial($cuota)
    {
        $cobro = $cuota->cobroDiferencialCuota;

        if (! $cobro) {
            return $this->crearHistorico($cuota);
        }

        return $this->actualizarHistorico($cobro, $cuota);
    }

    protected function crearHistorico($cuota)
    {
        // Calculo contra montos tabla de amortizacion
        $metodo_cobro = $this->distribucionMontoCobroCuota($cuota->monto_pagado, [
            'monto_capital' => $cuota->monto_capital,
            'monto_interes' => $cuota->monto_interes,
            'monto_cuota' => $cuota->monto_capital + $cuota->monto_interes,
        ]);

        $model = new CobroDiferencialCuota();
        $model->id_proceso = $cuota->id;
        $model->id_nombre_proceso = 1;
        $model->total_cobro = $cuota->monto_cobro;
        $model->capital_pagado = $metodo_cobro['capital_pagado'];
        $model->interes_pagado = $metodo_cobro['interes_pagado'];
        $model->capital_cobro = $metodo_cobro['capital_cobro'];
        $model->interes_cobro = $metodo_cobro['interes_cobro'];

        if (! $model->save()) {
            throw new Exception('No se pudo guardar seguimiento de monto cobro.');
        }

        $modelSeguimiento = new CobroDiferencialCuotaSeguimiento();
        $modelSeguimiento->id_cobro_diferencial_cuota = $model->id;
        $modelSeguimiento->id_estatus_cobro_cuota = $this->nomina->id_estatus_cuota_pago;
        $modelSeguimiento->save();

        return true;
    }

    protected function actualizarHistorico($cobro, $cuota)
    {
        // Calculos contra monto por cobrar anterior
        $metodo_cobro = $this->distribucionMontoCobroCuota($cuota->monto_pagado, [
            'monto_capital' => $cuota->monto_capital,
            'monto_interes' => $cuota->monto_interes,
            'monto_cuota' => $cuota->monto_capital + $cuota->monto_interes,
        ]);

        $cobro->total_cobro = $cuota->monto_cobro;
        $cobro->capital_pagado = $metodo_cobro['capital_pagado'];
        $cobro->interes_pagado = $metodo_cobro['interes_pagado'];
        $cobro->capital_cobro = $metodo_cobro['capital_cobro'];
        $cobro->interes_cobro = $metodo_cobro['interes_cobro'];

        if (! $cobro->save()) {
            throw new Exception('No se pudo guardar la distribución cobro del diferencial');
        }

        return true;
    }

    protected function pagarCuotasConciliadas()
    {
        return Yii::app()->getDb()->createCommand('
            update prestamos.credito_tabla_amortizacion set id_estatus_cuota=2
            from (
                select dtta.id_tabla_amortizacion
                from prestamos.datos_txt_tabla_amortizacion dtta
                where dtta.id_txt=:nomina
                    and dtta.monto_cobro is null
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
            ) as t
            where id=id_tabla_amortizacion
        ')->execute([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function pagoParcialCuotasGestionCobro()
    {
        return Yii::app()->getDb()->createCommand('
            update prestamos.credito_tabla_amortizacion set id_estatus_cuota=12
            from (
                select dtta.id_tabla_amortizacion
                from prestamos.datos_txt_tabla_amortizacion dtta
                inner join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                    and cdc.id_nombre_proceso=1
                    and cdc.blnborrado is false
                inner join prestamos.cobro_diferencial_cuota_seguimiento cdcs on cdcs.id_cobro_diferencial_cuota=cdc.id
                    and cdcs.actual is true
                where dtta.id_txt=:nomina
                    and cdcs.id_estatus_cobro_cuota=3
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
            ) as t
            where id=id_tabla_amortizacion
        ')->execute([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function pagadoCuotasAjusteDeduccionHaberes()
    {
        return Yii::app()->getDb()->createCommand('
            update prestamos.credito_tabla_amortizacion set id_estatus_cuota=2
            from (
                select dtta.id_tabla_amortizacion
                from prestamos.datos_txt_tabla_amortizacion dtta
                inner join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                    and cdc.id_nombre_proceso=1
                    and cdc.blnborrado is false
                inner join prestamos.cobro_diferencial_cuota_seguimiento cdcs on cdcs.id_cobro_diferencial_cuota=cdc.id
                    and cdcs.actual is true
                where dtta.id_txt=:nomina
                    and cdcs.id_estatus_cobro_cuota=6
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
            ) as t
            where id=id_tabla_amortizacion
        ')->execute([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function pagadoCuotasSinDiferencialCobro()
    {
        return Yii::app()->getDb()->createCommand('
           update prestamos.credito_tabla_amortizacion set id_estatus_cuota=2 -- pagado
            from (
                select dtta.id_tabla_amortizacion
                from prestamos.datos_txt_tabla_amortizacion dtta
                where dtta.id_txt=:nomina
                    and dtta.monto_cobro is null
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
            ) as t
            where id=id_tabla_amortizacion
        ')->execute([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function distribucionMontoCobroCuota($monto, $cuota)
    {
        $model = ConfPreNomina::model()->find();

        if (! $model) {
            throw new Exception('No existe el metodo de distribución para las cuotas diferidas, por favor defina el método y vuelva a intentarlo');
        }

        return $model->distribucionCuota($monto, (object) $cuota);
    }

    protected function recuperadoPorConciliacion()
    {
        if ($this->recuperadoPorConciliacion === null) {
            $this->recuperadoPorConciliacion = (new RecuperadoPorConciliacion($this->nomina))->datos('total');
        }

        return $this->recuperadoPorConciliacion;
    }

    protected function recuperadoPorDefinicion()
    {
        if ($this->recuperadoPorDefinicion === null) {
            $this->recuperadoPorDefinicion = (new RecuperadoPorDefinicion($this->nomina))->datos('total');
        }

        return $this->recuperadoPorDefinicion;
    }

    protected function totalCuotasConciliadas()
    {
        if ($this->totalCuotasConciliadas === null) {
            $this->totalCuotasConciliadas = (new TotalRecuperado($this->nomina))->total();
        }

        return $this->totalCuotasConciliadas;
    }

    protected function totalCuotasCargadas()
    {
        return Yii::app()->getDb()->createCommand('
            select coalesce(sum(dtta.monto_cuota_pagado),0)
            from prestamos.datos_txt_tabla_amortizacion dtta
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
        ')->queryScalar([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function totalCuotasNoDefinidas()
    {
        return Yii::app()->getDb()->createCommand('
            select coalesce(sum(dtta.monto_remanente),0)
            from prestamos.datos_txt_tabla_amortizacion dtta
            where dtta.id_txt=:nomina
                and dtta.monto_remanente is not null
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
        ')->queryScalar([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function totalCuotaRemanente()
    {
        return Yii::app()->getDb()->createCommand('
            select coalesce(sum(monto_cuota),0)
            from prestamos.datos_txt_tabla_amortizacion_diferido
            where id_txt=:nomina
                and blnborrado is false
        ')->queryScalar([
            'nomina' => $this->nomina->id,
        ]);
    }

    protected function getCuotasConciliadas()
    {
        return DatosTxtTablaAmortizacion::model()->findAllBySql('
            select dtta.*,
                   cta.monto_capital,
                   cta.monto_interes,
                   cta.monto_cuota,
                   coalesce(cdc.capital_pagado,0) as capital_pagado,
                   coalesce(cdc.interes_pagado,0) as interes_pagado,
                   coalesce(cdc.capital_cobro,0) as capital_cobro,
                   coalesce(cdc.interes_cobro,0) as interes_cobro
            from prestamos.datos_txt_tabla_amortizacion dtta
            inner join prestamos.credito_tabla_amortizacion cta on cta.id=dtta.id_tabla_amortizacion
            left join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                and cdc.blnborrado is false
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
            order by dtta.id
        ', [
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function getCuotasConciliadasMontoCobro()
    {
        return DatosTxtTablaAmortizacion::model()->findAllBySql('
            select dtta.*,
                   cta.monto_capital,
                   cta.monto_interes,
                   cta.monto_cuota,
                   coalesce(cdc.capital_pagado,0) as capital_pagado,
                   coalesce(cdc.interes_pagado,0) as interes_pagado,
                   coalesce(cdc.capital_cobro,0) as capital_cobro,
                   coalesce(cdc.interes_cobro,0) as interes_cobro
            from prestamos.datos_txt_tabla_amortizacion dtta
            inner join prestamos.credito_tabla_amortizacion cta on cta.id=dtta.id_tabla_amortizacion
            left join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                and cdc.blnborrado is false
            where dtta.id_txt=:nomina
                and dtta.monto_cobro is not null
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
            order by dtta.id
        ', [
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ]);
    }

    protected function montoPendienteRegistrado()
    {
        return Yii::app()->getDb()->createCommand('
            select sum(cdc.capital_cobro) as capital
                  ,sum(cdc.interes_cobro) as interes
                  ,(select concat(cdc.id, \' \', cdc.capital_cobro)
                    from prestamos.datos_txt_tabla_amortizacion dtta
                    inner join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                        and cdc.blnborrado is false
                    where dtta.id_txt=:nomina
                        -- remueve cuotas afectadas por subprocesos
                        and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                        )
                    order by cdc.capital_cobro DESC
                    limit 1) as capital_victima

                  ,(select concat(cdc.id, \' \', cdc.interes_cobro)
                    from prestamos.datos_txt_tabla_amortizacion dtta
                    inner join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                        and cdc.blnborrado is false
                    where dtta.id_txt=:nomina
                        -- remueve cuotas afectadas por subprocesos
                        and dtta.id_tabla_amortizacion not in (
                            select id_tabla_amortizacion
                            from prestamos.pre_nomina_tabla_amortizacion
                            where id_pre_nomina_credito=:prenomina
                                and blnborrado is true
                        )
                    order by cdc.interes_cobro DESC
                    limit 1) as interes_victima
            from prestamos.datos_txt_tabla_amortizacion dtta
            inner join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                and cdc.blnborrado is false
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
        ')->bindValues([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ])->queryRow(false);
    }

    protected function getCuotasSinDefinir()
    {
        return DatosTxtTablaAmortizacionDiferido::model()->findAllByAttributes([
            'id_txt' => $this->nomina->id,
            'blnborrado' => false,
        ]);
    }

    public function getVictima()
    {
        return Yii::app()->getDb()->createCommand('
            select (select concat(dtta.id, \' \', dtta.monto_remanente)
                    from prestamos.datos_txt_tabla_amortizacion dtta
                    where dtta.id_txt=:nomina
                        -- remueve cuotas afectadas por subprocesos
                        and dtta.id_tabla_amortizacion not in (
                            select id_tabla_amortizacion
                            from prestamos.pre_nomina_tabla_amortizacion
                            where id_pre_nomina_credito=:prenomina
                                and blnborrado is true
                        )
                    order by coalesce(monto_remanente,0) DESC
                    limit 1) as remanente

                ,(select concat(dtta.id, \' \', dtta.monto_cobro)
                  from prestamos.datos_txt_tabla_amortizacion dtta
                  where dtta.id_txt=:nomina
                      -- remueve cuotas afectadas por subprocesos
                      and dtta.id_tabla_amortizacion not in (
                          select id_tabla_amortizacion
                          from prestamos.pre_nomina_tabla_amortizacion
                          where id_pre_nomina_credito=:prenomina
                              and blnborrado is true
                      )
                  order by coalesce(monto_cobro,0) DESC
                  limit 1) cobro

                ,(select concat(dtta.id, \' \', dtta.monto_pagado)
                  from prestamos.datos_txt_tabla_amortizacion dtta
                  where dtta.id_txt=:nomina
                      -- remueve cuotas afectadas por subprocesos
                      and dtta.id_tabla_amortizacion not in (
                          select id_tabla_amortizacion
                          from prestamos.pre_nomina_tabla_amortizacion
                          where id_pre_nomina_credito=:prenomina
                              and blnborrado is true
                      )
                  order by monto_pagado DESC
                  limit 1) pagado
            from prestamos.datos_txt_tabla_amortizacion dtta
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
            limit 1
        ')->bindValues([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ])->queryRow();
    }

    public function getTotales()
    {
        return Yii::app()->getDb()->createCommand('
            select tmp.monto_cobro as cobro,
                   tmp.monto_remanente as remanente,
                   tmp.monto_pagado as pagado
            from prestamos.datos_txt_tabla_amortizacion dtta
            left join (
                select dtta.id_txt
                    ,sum(dtta.monto_cobro) as monto_cobro
                    ,sum(dtta.monto_remanente) as monto_remanente
                    ,sum(monto_pagado) as monto_pagado
                from prestamos.datos_txt_tabla_amortizacion dtta
                where dtta.id_txt=:nomina
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
                group by dtta.id_txt
            ) as tmp on tmp.id_txt=dtta.id_txt
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
            order by dtta.monto_pagado DESC
            limit 1
        ')->bindValues([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ])->queryRow();
    }

    public function getDatosLimpiezaCobroDiferencialCuota()
    {
        return Yii::app()->getDb()->createCommand('
            select cdc.id as id_cdc
                  ,cdc.capital_pagado
                  ,cdc.interes_pagado
                  ,coalesce(dtta.monto_remanente,0) as monto_remanente
                  ,coalesce(tmp.monto,0) + coalesce(dtta.monto_remanente,0) as total
            from prestamos.datos_txt_tabla_amortizacion dtta
            Left join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                and blnborrado is false
                and id_nombre_proceso=1
            left join (
                select dtta.id_txt
                    ,coalesce(sum(cdc.capital_pagado),0) + coalesce(sum(cdc.interes_pagado),0) as monto
                from prestamos.datos_txt_tabla_amortizacion dtta
                Left join prestamos.cobro_diferencial_cuota cdc on cdc.id_proceso=dtta.id
                    and blnborrado is false
                    and id_nombre_proceso=1
                where dtta.id_txt=:nomina
                    -- remueve cuotas afectadas por subprocesos
                    and dtta.id_tabla_amortizacion not in (
                        select id_tabla_amortizacion
                        from prestamos.pre_nomina_tabla_amortizacion
                        where id_pre_nomina_credito=:prenomina
                            and blnborrado is true
                    )
                group by dtta.id_txt
            ) as tmp on tmp.id_txt=dtta.id_txt
            where dtta.id_txt=:nomina
                -- remueve cuotas afectadas por subprocesos
                and dtta.id_tabla_amortizacion not in (
                    select id_tabla_amortizacion
                    from prestamos.pre_nomina_tabla_amortizacion
                    where id_pre_nomina_credito=:prenomina
                        and blnborrado is true
                )
            order by coalesce(cdc.capital_pagado,0) DESC, coalesce(cdc.interes_pagado,0) desc
            limit 1
        ')->bindValues([
            'nomina' => $this->nomina->id,
            'prenomina' => $this->nomina->id_prenomina_credito,
        ])->queryRow();
    }

    /**
     * Aplica diferencia decimal a un asociado para cuadrar monto distribuido
     *
     * @param float $real sumatoria del monto distribuido
     * @return boolean donde se haya aplicado la diferencia aun asociado
     */
    public function cleanLoss($real)
    {
        $totales = $this->getTotales();
        $victimas = $this->getVictima();

        if (!$victimas) {
            return false;
        }

        $diferencia_monto_pagado = bcsub($this->nomina->getMontoPagado(), ($totales['pagado'] + $totales['remanente']), 2);

        list($id, $monto_pagado) = explode(' ', $victimas['pagado']);

        if ($real < $totales['pagado']) {
            $monto = $monto_pagado - abs($diferencia_monto_pagado);
        } else {
            $monto = $monto_pagado + abs($diferencia_monto_pagado);
        }

        DatosTxtTablaAmortizacion::model()->updateAll(['monto_pagado' => $monto], 'id=:id', ['id' => $id]);
    }
}
