<?php
/*
 * @author Carlos García Gómez      neorazorx@gmail.com
 * @copyright 2016-2018, Carlos García Gómez. All Rights Reserved. 
 */

/**
 * Description of recibo_factura
 *
 * @author Carlos García Gómez
 */
class recibo_factura
{

    private $asiento_model;
    private $cbc;
    private $cbp;
    private $cliente_model;
    private $core_log;
    private $divisa_model;
    private $ejercicio_model;
    private $empresa;
    public $errors;
    private $factura_cliente;
    private $factura_proveedor;
    private $forma_pago;
    private $pago_model;
    private $plazo_pago;
    private $proveedor_model;
    private $recibo_cliente;
    private $recibo_proveedor;
    private $subcuenta_model;

    public function __construct()
    {
        $this->asiento_model = new asiento();
        $this->cbc = new cuenta_banco_cliente();
        $this->cbp = new cuenta_banco_proveedor();
        $this->cliente_model = new cliente();
        $this->core_log = new fs_core_log();
        $this->divisa_model = new divisa();
        $this->ejercicio_model = new ejercicio();
        $this->empresa = new empresa();
        $this->errors = [];
        $this->factura_cliente = new factura_cliente();
        $this->factura_proveedor = new factura_proveedor();
        $this->forma_pago = new forma_pago();
        $this->pago_model = new pago();
        $this->plazo_pago = new forma_pago_plazo();
        $this->proveedor_model = new proveedor();
        $this->recibo_cliente = new recibo_cliente();
        $this->recibo_proveedor = new recibo_proveedor();
        $this->subcuenta_model = new subcuenta();
    }

    private function new_error_msg($msg)
    {
        $this->errors[] = $msg;
        $this->core_log->new_error($msg);
        $this->core_log->save($msg);
    }

    /**
     * Comprueba/genera los recibos de la factura y actualiza lo necesario.
     * Devuelve un array con los recibos de la factura.
     * @param factura_cliente $factura
     * @return recibo_cliente[]
     */
    public function sync_factura_cli(&$factura)
    {
        if (empty($factura)) {
            return [];
        }

        $this->pago_model->cron_job();

        /// calculamos el saldo de la factura
        $saldo = 0;
        $recibos = $this->comprobar_recibos_venta($saldo, $factura);
        $num_recibos = count($recibos);

        /// ¿Estamos seguros de que no hay pagos previos?
        $this->comprobar_pagos_anticipo($factura, $recibos, $saldo);

        if ($factura->pagada && $num_recibos == 0) {
            /// no hacemos nada
        } else if ($factura->anulada) {
            foreach ($recibos as $recibo) {
                if ($recibo->estado != 'Pagado') {
                    $recibo->delete();
                }
            }
        } else if (abs($saldo - $factura->total) >= 0.01 && $num_recibos == 0) {
            $formap = $this->forma_pago->get($factura->codpago);
            if ($formap && !$this->empresa->floatcmp($saldo, $factura->total)) {
                $pendiente = $factura->total - $saldo;

                $plazos = $this->plazo_pago->all_from($formap->codpago);
                if ($plazos && count($recibos) == 0) {
                    /// si hay plazos, generamos un recibo por plazo
                    $pendiente2 = $pendiente;
                    foreach ($plazos as $i => $pla) {
                        if ($i + 1 == count($plazos)) {
                            $importe = round($pendiente2, FS_NF0);
                        } else {
                            $importe = round($pendiente * $pla->aplazado / 100, FS_NF0);
                            $pendiente2 -= $importe;
                        }

                        $formap->vencimiento = $pla->vencimiento();
                        $formap->save();
                        $this->nuevo_recibo_cliente($factura, $recibos, $importe, $formap);
                    }
                } else {
                    /// si no hay plazos, generamos un único recibo
                    $this->nuevo_recibo_cliente($factura, $recibos, $pendiente, $formap);
                }
            }
        }

        /// comprobamos el vencimiento de la factura
        $factura->vencimiento = $factura->fecha;
        foreach ($recibos as $recibo) {
            if (strtotime($recibo->fechav) > strtotime($factura->vencimiento)) {
                $factura->vencimiento = $recibo->fechav;
            }
        }

        if ($recibos) {
            $this->marcar_factura_pagada($factura, $recibos);
        } elseif ($factura->total == 0) {
            $factura->pagada = true;
            $factura->save();
        }

        return $recibos;
    }

    /**
     * Comprueba/genera los recibos de la factura y actualiza lo necesario.
     * Devuelve un array con los recibos de la factura.
     * @param factura_proveedor $factura
     * @return recibo_proveedor[]
     */
    public function sync_factura_prov(&$factura)
    {
        if (empty($factura)) {
            return [];
        }

        /// calculamos el saldo de la factura
        $saldo = 0;
        $recibos = $this->comprobar_recibos_compra($saldo, $factura->idfactura);

        if ($factura->pagada && count($recibos) == 0) {
            /// no hacemos nada
        } else if ($factura->anulada) {
            foreach ($recibos as $recibo) {
                if ($recibo->estado != 'Pagado') {
                    $recibo->delete();
                }
            }
        } else if (abs($saldo - $factura->total) >= 0.01 && count($recibos) == 0) {
            $formap = $this->forma_pago->get($factura->codpago);
            if ($formap) {
                $pendiente = $factura->total - $saldo;

                $plazos = $this->plazo_pago->all_from($formap->codpago);
                if ($plazos && count($recibos) == 0) {
                    /// si hay plazos, generamos un recibo por plazo
                    $pendiente2 = $pendiente;
                    foreach ($plazos as $i => $pla) {
                        if ($i + 1 == count($plazos)) {
                            $importe = round($pendiente2, FS_NF0);
                        } else {
                            $importe = round($pendiente * $pla->aplazado / 100, FS_NF0);
                            $pendiente2 -= $importe;
                        }

                        $formap->vencimiento = $pla->vencimiento();
                        $formap->save();
                        $this->nuevo_recibo_proveedor($factura, $recibos, $importe, $formap);
                    }
                } else {
                    /// si no hay plazos, generamos un único recibo
                    $this->nuevo_recibo_proveedor($factura, $recibos, $pendiente, $formap);
                }
            }
        }

        /// comprobamos el vencimiento de la factura
        $factura->vencimiento = $factura->fecha;
        foreach ($recibos as $recibo) {
            if (strtotime($recibo->fechav) > strtotime($factura->vencimiento)) {
                $factura->vencimiento = $recibo->fechav;
            }
        }

        if ($recibos) {
            $this->marcar_factura_pagada($factura, $recibos);
        } elseif ($factura->total == 0) {
            $factura->pagada = true;
            $factura->save();
        }

        return $recibos;
    }

    /**
     * Obtiene y comprueba los recibos de la factura.
     * @param float $saldo
     * @param factura_cliente $factura
     * @return recibo_cliente[]
     */
    private function comprobar_recibos_venta(&$saldo, &$factura)
    {
        $recibos = $this->recibo_cliente->all_from_factura($factura->idfactura);
        foreach ($recibos as $re) {
            $saldo += $re->importe;

            /// comprobamos nombre y cifnif
            if ($re->cifnif != $factura->cifnif OR $re->nombrecliente = $factura->nombrecliente) {
                $re->cifnif = $factura->cifnif;
                $re->nombrecliente = $factura->nombrecliente;
            }

            /// además comprobamos la dirección
            if ($re->direccion != $factura->direccion) {
                $re->direccion = $factura->direccion;
                $re->codpostal = $factura->codpostal;
                $re->apartado = $factura->apartado;
                $re->ciudad = $factura->ciudad;
                $re->provincia = $factura->provincia;
                $re->codpais = $factura->codpais;
                $re->save();
            }
        }

        return $recibos;
    }

    /**
     * Obtiene los recibos de la factura y calcula el saldo.
     * @param float $saldo
     * @param integer $idfactura
     * @return recibo_proveedor[]
     */
    private function comprobar_recibos_compra(&$saldo, $idfactura)
    {
        $recibos = $this->recibo_proveedor->all_from_factura($idfactura);
        foreach ($recibos as $re) {
            $saldo += $re->importe;
        }

        return $recibos;
    }

    /**
     * Comprueba los pagos anticipados de la factura y genera los recibos si es necesario.
     * @param factura_cliente $factura
     * @param recibo_cliente[] $recibos
     * @param float $saldo
     */
    private function comprobar_pagos_anticipo(&$factura, &$recibos, &$saldo)
    {
        foreach ($this->pago_model->all_from_factura($factura->idfactura) as $pago) {
            if (!is_null($pago->idrecibo)) {
                continue;
            }

            $recibo = new recibo_cliente();
            $recibo->cifnif = $factura->cifnif;
            $recibo->coddivisa = $factura->coddivisa;
            $recibo->tasaconv = $factura->tasaconv;
            $recibo->codpago = $factura->codpago;
            $recibo->codserie = $factura->codserie;
            $recibo->codcliente = $factura->codcliente;
            $recibo->nombrecliente = $factura->nombrecliente;
            $recibo->estado = 'Pagado';
            $recibo->fecha = $recibo->fechav = $recibo->fechap = $pago->fecha;
            $recibo->idfactura = $factura->idfactura;
            $recibo->importe = $pago->importe;
            $recibo->numero = $recibo->new_numero($recibo->idfactura);
            $recibo->codigo = $factura->codigo . '-' . sprintf('%02s', $recibo->numero);
            $recibo->observaciones = $pago->nota;

            if ($recibo->save()) {
                $pago->idrecibo = $recibo->idrecibo;
                $pago->save();

                $sc_pago = $this->subcuenta_model->get_cuentaesp('CAJA', $factura->codejercicio);
                if ($sc_pago) {
                    $this->nuevo_pago_cli($recibo, $sc_pago->codsubcuenta);
                } else {
                    $this->new_error_msg('No se ha encontrado una subcuenta de caja para generar el asiento del pago.');
                }

                $recibos[] = $recibo;
                $saldo += $recibo->importe;
            } else {
                $this->new_error_msg('Error al generar el recibo.');
            }
        }
    }

    /**
     * Genera un nuevo recibo de cliente.
     * @param factura_cliente $factura
     * @param recibo_cliente[] $recibos
     * @param float $importe
     * @param forma_pago $formap
     */
    private function nuevo_recibo_cliente(&$factura, &$recibos, $importe, $formap)
    {
        $recibo = new recibo_cliente();
        $recibo->cifnif = $factura->cifnif;
        $recibo->coddivisa = $factura->coddivisa;
        $recibo->tasaconv = $factura->tasaconv;
        $recibo->codpago = $factura->codpago;
        $recibo->codserie = $factura->codserie;
        $recibo->codcliente = $factura->codcliente;
        $recibo->nombrecliente = $factura->nombrecliente;
        $recibo->fecha = $factura->fecha;

        /// calculamos el vencimiento
        $cliente = $this->cliente_model->get($factura->codcliente);
        if ($cliente) {
            $recibo->fechav = $formap->calcular_vencimiento($factura->fecha, $cliente->diaspago);
        } else {
            $recibo->fechav = $formap->calcular_vencimiento($factura->fecha);
        }

        $recibo->idfactura = $factura->idfactura;
        $recibo->importe = $importe;
        $recibo->numero = $recibo->new_numero($recibo->idfactura);
        $recibo->codigo = $factura->codigo . '-' . sprintf('%02s', $recibo->numero);

        foreach ($this->cbc->all_from_cliente($factura->codcliente) as $cuenta) {
            if (is_null($recibo->codcuenta) || $cuenta->principal) {
                $recibo->codcuenta = $cuenta->codcuenta;
                $recibo->iban = $cuenta->iban;
                $recibo->swift = $cuenta->swift;
                $recibo->fmandato = $cuenta->fmandato;
            }
        }

        if ($recibo->save()) {
            $recibos[] = $recibo;
        } else {
            $this->new_error_msg('Error al generar el recibo.');
        }
    }

    /**
     * Genera un nuevo recibo de proveedor.
     * @param factura_proveedor $factura
     * @param recibo_proveedor $recibos
     * @param float $importe
     * @param forma_pago $formap
     */
    private function nuevo_recibo_proveedor(&$factura, &$recibos, $importe, $formap)
    {
        $recibo = new recibo_proveedor();
        $recibo->cifnif = $factura->cifnif;
        $recibo->coddivisa = $factura->coddivisa;
        $recibo->tasaconv = $factura->tasaconv;
        $recibo->codproveedor = $factura->codproveedor;
        $recibo->nombreproveedor = $factura->nombre;
        $recibo->fecha = $factura->fecha;
        $recibo->fechav = $formap->calcular_vencimiento($factura->fecha);
        $recibo->idfactura = $factura->idfactura;
        $recibo->codpago = $factura->codpago;
        $recibo->codserie = $factura->codserie;
        $recibo->importe = $importe;
        $recibo->numero = $recibo->new_numero($recibo->idfactura);
        $recibo->codigo = $factura->codigo . '-' . sprintf('%02s', $recibo->numero);

        foreach ($this->cbp->all_from_proveedor($recibo->codproveedor) as $cuenta) {
            if (is_null($recibo->codcuenta) || $cuenta->principal) {
                $recibo->codcuenta = $cuenta->codcuenta;
                $recibo->iban = $cuenta->iban;
                $recibo->swift = $cuenta->swift;
            }
        }

        if ($recibo->save()) {
            $recibos[] = $recibo;
        } else {
            $this->new_error_msg('Error al generar el recibo.');
        }
    }

    /**
     * Comprueba los recibos y marca la factura como pagada
     * @param factura_cliente|factura_proveedor $factura
     * @param recibo_cliente[]|recibo_proveedor[] $recibos
     */
    private function marcar_factura_pagada(&$factura, &$recibos)
    {
        $pagado = 0;
        foreach ($recibos as $res) {
            if ($res->estado == 'Pagado') {
                $pagado += $res->importe;
            }
        }

        if ($factura->total == 0) {
            $factura->pagada = TRUE;
        } else {
            $factura->pagada = ( abs($factura->total - $pagado) <= 0.01 );
            if (!$factura->pagada && $factura->idasientop) {
                $asientop = $this->asiento_model->get($factura->idasientop);
                if ($asientop) {
                    $asientop->delete();
                }

                $factura->idasientop = NULL;
            }
        }

        $factura->save();
    }

    /**
     * Genera un nuevo pago de un recibo de cliente.
     * @param recibo_cliente $recibo
     * @param string $codsubcuenta_pago
     * @param string $tipo
     * @param string $fecha
     * @param boolean $genasiento
     * @return boolean
     */
    public function nuevo_pago_cli(&$recibo, $codsubcuenta_pago = FALSE, $tipo = 'Pago', $fecha = '', $genasiento = TRUE)
    {
        $error = FALSE;

        $pago = new pago_recibo_cliente();
        $pago->idrecibo = $recibo->idrecibo;
        $pago->tipo = $tipo;

        if ($fecha) {
            $pago->fecha = $fecha;
        }

        if ($codsubcuenta_pago === '---NO---') {
            /// nada
        } elseif ($this->empresa->contintegrada && $genasiento && $codsubcuenta_pago) {
            $cliente = $this->cliente_model->get($recibo->codcliente);

            if ($tipo == 'Pago') {
                $concepto = 'Cobro recibo ' . $recibo->codigo . ' - ' . $recibo->nombrecliente;
                $inverso = FALSE;
            } else {
                $concepto = 'Devolución recibo ' . $recibo->codigo . ' - ' . $recibo->nombrecliente;
                $inverso = TRUE;
            }

            $asientop = $this->nuevo_asiento_pago_cli(
                $recibo->importe, $recibo->coddivisa, $recibo->tasaconv, $concepto, $cliente, $codsubcuenta_pago, $inverso, $pago->fecha
            );
            if ($asientop) {
                /// enlazamos el asiento con la factura
                $fact0 = new factura_cliente();
                $factura = $fact0->get($recibo->idfactura);
                if ($factura) {
                    $asientop->tipodocumento = "Factura de cliente";
                    $asientop->documento = $factura->codigo;
                    $asientop->save();
                }

                $pago->idasiento = $asientop->idasiento;

                /// nos guardamos la subcuenta
                foreach ($asientop->get_partidas() as $lin) {
                    /**
                     * Por si acaso no se ha seleccionado una subcuenta de pago,
                     * nos guardamos alguna.
                     */
                    $pago->codsubcuenta = $lin->codsubcuenta;
                    $pago->idsubcuenta = $lin->idsubcuenta;

                    if ($lin->codsubcuenta == $codsubcuenta_pago) {
                        /// salimos del bucle, ya no se asigna ninguna otra subcuenta
                        break;
                    }
                }
            } else {
                $this->new_error_msg('Error al generar el asiento de pago.');
                $error = TRUE;
            }
        } else if ($this->empresa->contintegrada && $genasiento) {
            $this->new_error_msg('La cuenta de pago no tiene una subcuenta asociada. Asocia una desde admin -> empresa -> cuentas bancarias.');
            $error = TRUE;
        }

        return $this->fin_pago($pago, $recibo, $error);
    }

    /**
     * Genera el asiento de un pago de un recibo de cliente.
     * @param float $importe
     * @param string $coddivisa
     * @param float $tasaconv
     * @param string $concepto
     * @param cliente $cliente
     * @param string $codsubcuenta_pago
     * @param boolean $inverso
     * @param string $fecha
     * @return \asiento
     */
    public function nuevo_asiento_pago_cli($importe, $coddivisa, $tasaconv, $concepto, $cliente = FALSE, $codsubcuenta_pago = FALSE, $inverso = FALSE, $fecha = '')
    {
        $tasaconv2 = $tasaconv;
        $this->set_tasasconv($tasaconv, $tasaconv2, $coddivisa);

        $nasiento = FALSE;
        $asiento = new asiento();
        $asiento->editable = FALSE;
        $asiento->importe = round($importe * $tasaconv, FS_NF0);
        $asiento->concepto = $concepto;

        if ($fecha) {
            $asiento->fecha = $fecha;
        }

        $ejercicio = $this->ejercicio_model->get_by_fecha($asiento->fecha);
        if ($ejercicio) {
            $asiento->codejercicio = $ejercicio->codejercicio;
        }

        if ($cliente) {
            $subcuenta_cli = $cliente->get_subcuenta($ejercicio->codejercicio);
        } else {
            /// buscamos la cuenta 0 de clientes
            $subcuenta_cli = $this->subcuenta_model->get_cuentaesp('CLIENT', $ejercicio->codejercicio);
        }

        $subcaja = $this->get_subcuenta_caja($ejercicio, $codsubcuenta_pago);

        if (!$ejercicio) {
            $this->new_error_msg('Ningún ejercico encontrado.');
        } else if (!$ejercicio->abierto()) {
            $this->new_error_msg('El ejercicio ' . $ejercicio->codejercicio . ' está cerrado.');
        } else if (!$subcuenta_cli) {
            $this->new_error_msg("No se ha podido generar una subcuenta para el cliente "
                . "<a href='" . $ejercicio->url() . "'>¿Has importado los datos del ejercicio?</a>");
        } else if (!$subcaja) {
            $this->new_error_msg("No se ha encontrado la subcuenta de caja "
                . "<a href='" . $ejercicio->url() . "'>¿Has importado los datos del ejercicio?</a>");
        } else if ($asiento->save()) {
            $this->new_partida($asiento, $subcuenta_cli, $importe, $tasaconv, $tasaconv2, !$inverso);
            $this->new_partida($asiento, $subcaja, $importe, $tasaconv, $tasaconv2, $inverso);
            $nasiento = $asiento;
        } else {
            $this->new_error_msg('Error al guardar el asiento.');
        }

        return $nasiento;
    }

    /**
     * Genera un nuevo pago de un recibo de proveedor.
     * @param recibo_proveedor $recibo
     * @param string $codsubcuenta_pago
     * @param string $tipo
     * @param string $fecha
     * @param boolean $genasiento
     * @return boolean
     */
    public function nuevo_pago_prov(&$recibo, $codsubcuenta_pago = FALSE, $tipo = 'Pago', $fecha = '', $genasiento = TRUE)
    {
        $error = FALSE;

        $pago = new pago_recibo_proveedor();
        $pago->idrecibo = $recibo->idrecibo;
        $pago->tipo = $tipo;

        if ($fecha) {
            $pago->fecha = $fecha;
        }

        if ($codsubcuenta_pago === '---NO---') {
            /// nada
        } elseif ($this->empresa->contintegrada && $genasiento && $codsubcuenta_pago) {
            $proveedor = $this->proveedor_model->get($recibo->codproveedor);

            if ($tipo == 'Pago') {
                $concepto = 'Pago recibo de compra ' . $recibo->codigo . ' - ' . $recibo->nombreproveedor;
                $inverso = FALSE;
            } else {
                $concepto = 'Devolución recibo de compra ' . $recibo->codigo . ' - ' . $recibo->nombreproveedor;
                $inverso = TRUE;
            }

            $asientop = $this->nuevo_asiento_pago_prov(
                $recibo->importe, $recibo->coddivisa, $recibo->tasaconv, $concepto, $proveedor, $codsubcuenta_pago, $inverso, $pago->fecha
            );
            if ($asientop) {
                /// enlazamos el asiento con la factura
                $fact0 = new factura_proveedor();
                $factura = $fact0->get($recibo->idfactura);
                if ($factura) {
                    $asientop->tipodocumento = "Factura de proveedor";
                    $asientop->documento = $factura->codigo;
                    $asientop->save();
                }

                $pago->idasiento = $asientop->idasiento;

                /// nos guardamos la subcuenta
                foreach ($asientop->get_partidas() as $lin) {
                    /**
                     * Por si acaso no se ha seleccionado una subcuenta de pago,
                     * nos guardamos alguna.
                     */
                    $pago->codsubcuenta = $lin->codsubcuenta;
                    $pago->idsubcuenta = $lin->idsubcuenta;

                    if ($lin->codsubcuenta == $codsubcuenta_pago) {
                        /// salimos del bucle, ya no se asigna ninguna otra subcuenta
                        break;
                    }
                }
            } else {
                $this->new_error_msg('Error al generar el asiento de pago.');
                $error = TRUE;
            }
        } else if ($this->empresa->contintegrada && $genasiento) {
            $this->new_error_msg('La cuenta de pago no tiene una subcuenta asociada. Asocia una desde admin -> empresa -> cuentas bancarias.');
            $error = TRUE;
        }

        return $this->fin_pago($pago, $recibo, $error);
    }

    /**
     * Genera el asiento de un pago de un recibo de proveedor.
     * @param float $importe
     * @param string $coddivisa
     * @param float $tasaconv
     * @param string $concepto
     * @param proveedor $proveedor
     * @param string $codsubcuenta_pago
     * @param boolean $inverso
     * @param string $fecha
     * @return \asiento
     */
    public function nuevo_asiento_pago_prov($importe, $coddivisa, $tasaconv, $concepto, $proveedor = FALSE, $codsubcuenta_pago = FALSE, $inverso = FALSE, $fecha = '')
    {
        $tasaconv2 = $tasaconv;
        $this->set_tasasconv($tasaconv, $tasaconv2, $coddivisa, TRUE);

        $nasiento = FALSE;
        $asiento = new asiento();
        $asiento->editable = FALSE;
        $asiento->importe = round($importe * $tasaconv, FS_NF0);
        $asiento->concepto = $concepto;

        if ($fecha) {
            $asiento->fecha = $fecha;
        }

        $ejercicio = $this->ejercicio_model->get_by_fecha($asiento->fecha);
        if ($ejercicio) {
            $asiento->codejercicio = $ejercicio->codejercicio;
        }

        if ($proveedor) {
            $subcuenta_pro = $proveedor->get_subcuenta($ejercicio->codejercicio);
        } else {
            /// buscamos la cuenta 0 de proveedores
            $subcuenta_pro = $this->subcuenta_model->get_cuentaesp('PROVEE', $ejercicio->codejercicio);
        }

        $subcaja = $this->get_subcuenta_caja($ejercicio, $codsubcuenta_pago);

        if (!$ejercicio) {
            $this->new_error_msg('Ningún ejercico encontrado.');
        } else if (!$ejercicio->abierto()) {
            $this->new_error_msg('El ejercicio ' . $ejercicio->codejercicio . ' está cerrado.');
        } else if (!$subcuenta_pro) {
            $this->new_error_msg("No se ha podido generar una subcuenta para el proveedor "
                . "<a href='" . $ejercicio->url() . "'>¿Has importado los datos del ejercicio?</a>");
        } else if (!$subcaja) {
            $this->new_error_msg("No se ha encontrado la subcuenta de caja "
                . "<a href='" . $ejercicio->url() . "'>¿Has importado los datos del ejercicio?</a>");
        } else if ($asiento->save()) {
            $this->new_partida($asiento, $subcuenta_pro, $importe, $tasaconv, $tasaconv2, $inverso);
            $this->new_partida($asiento, $subcaja, $importe, $tasaconv, $tasaconv2, !$inverso);
            $nasiento = $asiento;
        } else {
            $this->new_error_msg('Error al guardar el asiento.');
        }

        return $nasiento;
    }

    /**
     * Establece las tasas de conversión.
     * @param float $tasaconv
     * @param float $tasaconv2
     * @param string $coddivisa
     * @param boolean $compra
     */
    private function set_tasasconv(&$tasaconv, &$tasaconv2, $coddivisa, $compra = false)
    {
        $tasaconv = 1;
        if ($coddivisa != $this->empresa->coddivisa) {
            $divisa = $this->divisa_model->get($this->empresa->coddivisa);
            if ($divisa && $compra) {
                $tasaconv = $divisa->tasaconv_compra / $tasaconv2;
                $tasaconv2 = $divisa->tasaconv_compra;
            } else if ($divisa) {
                $tasaconv = $divisa->tasaconv / $tasaconv2;
                $tasaconv2 = $divisa->tasaconv;
            }
        }
    }

    /**
     * Devuelve la subcuenta de caja del ejercicio seleccionado.
     * @param ejercicio $ejercicio
     * @param string $codsubcuenta_pago
     * @return subcuenta
     */
    private function get_subcuenta_caja(&$ejercicio, $codsubcuenta_pago)
    {
        if ($codsubcuenta_pago) {
            return $this->subcuenta_model->get_by_codigo($codsubcuenta_pago, $ejercicio->codejercicio);
        }

        return $this->subcuenta_model->get_cuentaesp('CAJA', $ejercicio->codejercicio);
    }

    /**
     * Termina el pago generado.
     * @param pago_recibo_cliente|pago_recibo_proveedor $pago
     * @param recibo_cliente|recibo_proveedor $recibo
     * @param boolean $error
     * @return boolean
     */
    private function fin_pago(&$pago, &$recibo, &$error)
    {
        if (!$error && $pago->save()) {
            if ($pago->tipo == 'Pago') {
                $recibo->estado = 'Pagado';
                $recibo->fechap = $pago->fecha;
            } else {
                $recibo->estado = 'Devuelto';
            }

            if (!$recibo->save()) {
                $this->new_error_msg('Error al guardar el pago.');
                $error = TRUE;
            }
        }

        return !$error;
    }

    /**
     * Genera una nueva partida para el asiento
     * @param asiento $asiento
     * @param subcuenta $subcuenta
     * @param float $importe
     * @param float $tasaconv
     * @param float $tasaconv2
     * @param boolean $inverso
     */
    private function new_partida($asiento, $subcuenta, $importe, $tasaconv, $tasaconv2, $inverso)
    {
        $partida2 = new partida();
        $partida2->idasiento = $asiento->idasiento;
        $partida2->concepto = $asiento->concepto;
        $partida2->idsubcuenta = $subcuenta->idsubcuenta;
        $partida2->codsubcuenta = $subcuenta->codsubcuenta;

        if ($inverso) {
            $partida2->haber = round($importe * $tasaconv, FS_NF0);
        } else {
            $partida2->debe = round($importe * $tasaconv, FS_NF0);
        }

        $partida2->coddivisa = $this->empresa->coddivisa;
        $partida2->tasaconv = $tasaconv2;
        $partida2->save();
    }
}
