<?php

/**
 * @author Carlos García Gómez         neorazorx@gmail.com
 * @author Francesc Pineda Segarra     shawe.ewahs@gmail.com
 * @copyright 2015-2018, Carlos García Gómez. All Rights Reserved.
 * @copyright 2015-2016, Francesc Pineda Segarra. All Rights Reserved.
 */
use AbcAeffchen\SepaUtilities\SepaUtilities;
use AbcAeffchen\Sephpa\SephpaDirectDebit;

require_once __DIR__ . '/../lib/tesoreria_controller.php';
require_once 'plugins/tesoreria/lib/sephpa/SepaUtilities.php';
require_once 'plugins/tesoreria/lib/sephpa/SephpaDirectDebit.php';
require_once 'plugins/tesoreria/lib/sephpa/payment-collections/SepaPaymentCollection.php';
require_once 'plugins/tesoreria/lib/sephpa/payment-collections/SepaDirectDebit00800102.php';

/**
 * Description of remesas
 *
 * @author Carlos García Gómez
 */
class remesas extends tesoreria_controller
{

    public $b_desde;
    public $b_estado;
    public $b_hasta;
    public $codsubcuenta_pago;
    public $cuentab;
    public $cuentab_s;
    public $num_resultados;
    public $offset;
    private $remesa_model;
    public $remesa;
    public $resultados;
    public $url_recarga;

    public function __construct()
    {
        parent::__construct(__CLASS__, 'Remesas', 'contabilidad', FALSE, TRUE);
    }

    protected function private_core()
    {
        parent::private_core();
        $this->codsubcuenta_pago = $this->codsubcuenta_pago();
        $this->cuentab = new cuenta_banco();
        $this->cuentab_s = FALSE;
        $this->remesa_model = new remesa();
        $this->resultados = [];
        $this->url_recarga = FALSE;

        if (isset($_POST['nueva'])) {
            $this->nueva_remesa();
            $this->resultados = $this->remesa_model->all();
        } else if (isset($_REQUEST['id'])) {
            $this->cargar_remesa($_REQUEST['id']);
        } else if (isset($_GET['delete'])) {
            $this->eliminar_remesa($_GET['delete']);
        } else if (isset($_GET['gdp'])) {
            $this->generar_datos_prueba();
            $this->buscar();
        } else {
            $this->share_extensions();
            $this->liberar_recibos();
            $this->buscar();
        }
    }

    private function buscar()
    {
        $this->num_resultados = 0;
        $this->resultados = [];
        $this->b_desde = isset($_REQUEST['b_desde']) ? $_REQUEST['b_desde'] : false;
        $this->b_estado = isset($_REQUEST['b_estado']) ? $_REQUEST['b_estado'] : false;
        $this->b_hasta = isset($_REQUEST['b_hasta']) ? $_REQUEST['b_hasta'] : false;
        $this->offset = isset($_REQUEST['offset']) ? intval($_REQUEST['offset']) : 0;

        $sql = 'FROM remesas_sepa WHERE 1=1';
        if ($this->b_desde) {
            $sql .= ' AND  fecha >= ' . $this->empresa->var2str($this->b_desde);
        }

        if ($this->b_hasta) {
            $sql .= ' AND  fecha <= ' . $this->empresa->var2str($this->b_hasta);
        }

        if ($this->b_estado) {
            $sql .= ' AND  estado = ' . $this->empresa->var2str($this->b_estado);
        }

        if ($this->query) {
            $sql .= " AND lower(descripcion) LIKE '%" . $this->empresa->no_html($this->query) . "%'";
        }

        $data = $this->db->select(' SELECT COUNT(*) AS num ' . $sql);
        if ($data) {
            $this->num_resultados = intval($data[0]['num']);

            $sql .= ' ORDER BY fecha DESC';
            $data2 = $this->db->select_limit('SELECT * ' . $sql, FS_ITEM_LIMIT, $this->offset);
            if ($data2) {
                foreach ($data2 as $d) {
                    $this->resultados[] = new remesa($d);
                }
            }
        }
    }

    public function paginas()
    {
        $url = $this->url() . '&query=' . $this->query
            . '&b_desde=' . $this->b_desde
            . '&b_estado=' . $this->b_estado
            . '&b_hasta=' . $this->b_hasta;

        return $this->fbase_paginas($url, $this->num_resultados, $this->offset);
    }

    private function nueva_remesa()
    {
        $reme = new remesa();
        $reme->descripcion = $_POST['descripcion'];
        $reme->fechacargo = $_POST['fechacargo'];

        $formap = $this->forma_pago->get($_POST['codpago']);
        if ($formap) {
            $reme->codpago = $formap->codpago;

            /// buscamos la cuenta bancaria asociada a la forma de pago
            $cuentab = $this->cuentab->get($formap->codcuenta);
            if ($cuentab) {
                $reme->codcuenta = $cuentab->codcuenta;
                $reme->iban = $cuentab->iban;
                $reme->swift = $cuentab->swift;
            }
        }

        $div0 = new divisa();
        $divisa = $div0->get($this->empresa->coddivisa);
        if ($divisa) {
            $reme->coddivisa = $divisa->coddivisa;
            $reme->tasaconv = $divisa->tasaconv;
        }

        $reme->new_creditorid();

        if (is_null($reme->codcuenta)) {
            $this->new_error_msg('La <a href="' . $this->forma_pago->url() . '">forma de pago</a>'
                . ' seleccionada no tiene una cuenta bancaria asociada.');
        } else if ($reme->save()) {
            $this->new_message('Datos guardados correctamente.');
            header('Location: ' . $reme->url());
        } else {
            $this->new_error_msg('Error al guardar los datos.');
        }
    }

    private function cargar_remesa($id)
    {
        $this->remesa = $this->remesa_model->get($id);
        if ($this->remesa) {
            $this->cuentab_s = $this->cuentab->get($this->remesa->codcuenta);
            if ($this->cuentab_s && $this->cuentab_s->codsubcuenta) {
                $this->codsubcuenta_pago = $this->cuentab_s->codsubcuenta;
            }

            if (isset($_GET['download'])) {
                $this->resultados = $this->recibo_cliente_model->all_from_remesa($this->remesa->idremesa);
                $this->download();
            } else {
                $this->template = 'editar_remesa';
                $this->modificar_remesa();

                $this->resultados = $this->recibo_cliente_model->all_from_remesa($this->remesa->idremesa);

                /// calculamos el total
                $this->remesa->total = 0;
                foreach ($this->resultados as $res) {
                    $this->remesa->total += $res->importe;
                }
                $this->remesa->save();
            }
        } else {
            $this->new_error_msg('Remesa no encontrada.');
        }
    }

    private function modificar_remesa()
    {
        if (isset($_POST['descripcion'])) {
            $this->remesa->descripcion = $_POST['descripcion'];
            $this->remesa->creditorid = $_POST['creditorid'];
            $this->remesa->fecha = $_POST['fecha'];
            $this->remesa->fechacargo = $_POST['fechacargo'];
            $this->remesa->estado = $_POST['estado'];

            if ($this->remesa->save()) {
                $this->new_message('Datos guardados correctamente.');
            } else {
                $this->new_error_msg('Error al guardar los datos.');
            }
        } else if (isset($_GET['pagar'])) {
            $this->pagar_recibos();
        } else if (!$this->remesa->editable() AND ( isset($_POST['addrecibo']) OR isset($_GET['sacar']))) {
            $this->new_error_msg('Solamente se pueden hacer cambios en remesas <b>en trámite</b>.');
        } else if (isset($_POST['addrecibo'])) {
            $this->add_recibos($_POST['addrecibo']);
        } else if (isset($_GET['sacar'])) {
            $this->sacar_recibo($_GET['sacar']);
        }
    }

    private function eliminar_remesa($id)
    {
        $remesa = $this->remesa_model->get($id);
        if ($remesa) {
            if ($remesa->delete()) {
                $this->new_message('Remesa eliminada correctamente.');
            } else {
                $this->new_error_msg('Imposible eliminar la remesa.');
            }
        }

        $this->resultados = $this->remesa_model->all();
        $this->liberar_recibos();
    }

    private function add_recibos($ids)
    {
        $nuevos = 0;
        foreach ($ids as $id) {
            $recibo = $this->recibo_cliente_model->get($id);
            if ($recibo) {
                $recibo->idremesa = $this->remesa->idremesa;
                if ($recibo->save()) {
                    $nuevos++;
                }
            }
        }

        $this->new_message($nuevos . ' recibos añadidos a la remesa.');
    }

    private function sacar_recibo($id)
    {
        $recibo = $this->recibo_cliente_model->get($id);
        if ($recibo) {
            $recibo->idremesa = NULL;

            if ($recibo->save()) {
                $this->new_message('Recibo ' . $recibo->codigo . ' excluido.');
            } else {
                $this->new_error_msg('Error al excluir el recibo ' . $recibo->codigo);
            }
        }
    }

    private function codsubcuenta_pago()
    {
        $codsubcuenta = FALSE;
        foreach ($this->get_subcuentas_caja() as $subcuenta) {
            $codsubcuenta = $subcuenta->codsubcuenta;
            break;
        }

        return $codsubcuenta;
    }

    public function formas_pago_domiciliadas()
    {
        $lista = [];
        foreach ($this->forma_pago->all() as $fp) {
            if ($fp->domiciliado) {
                $lista[] = $fp;
            }
        }

        return $lista;
    }

    public function recibos_disponibles()
    {
        $lista = [];

        $sql = "SELECT * FROM reciboscli WHERE idremesa IS NULL AND estado != 'Pagado'"
            . " AND fechav <= " . $this->remesa->var2str($this->remesa->fechacargo)
            . " AND coddivisa = " . $this->remesa->var2str($this->empresa->coddivisa)
            . " AND (codpago = " . $this->remesa->var2str($this->remesa->codpago)
            . " OR codpago IN (SELECT codpago FROM formaspago WHERE domiciliado"
            . " AND codcuenta = " . $this->remesa->var2str($this->remesa->codcuenta) . "))"
            . " ORDER BY fechav ASC;";
        $data = $this->db->select($sql);
        if ($data) {
            foreach ($data as $d) {
                $lista[] = new recibo_cliente($d);
            }
        }

        return $lista;
    }

    private function download()
    {
        // ID único de la remesa: id de remesa + fecha de generación
        $paymentInfoId = $this->empresa->cifnif . '-' . date('dmy-H:i', strtotime($this->remesa->fecha . ' ' . $this->hour()));

        // Formato de documento a utilizar
        $sepaPAIN = SephpaDirectDebit::SEPA_PAIN_008_001_02;

        // Comprobar y sanear valores, permite evitar validación de IBAN, útil para pruebas con IBANs falsos
        $checkAndSanitize = FALSE;

        /**
         * normal direct debit : LOCAL_INSTRUMENT_CORE_DIRECT_DEBIT = 'CORE';
         * urgent direct debit : LOCAL_INSTRUMENT_CORE_DIRECT_DEBIT_D_1 = 'COR1';
         * business direct debit : LOCAL_INSTRUMENT_BUSINESS_2_BUSINESS = 'B2B';
         */
        $localInstrument = SepaUtilities::LOCAL_INSTRUMENT_CORE_DIRECT_DEBIT;

        /**
         * first direct debit : SEQUENCE_TYPE_FIRST = 'FRST';
         * recurring direct debit : SEQUENCE_TYPE_RECURRING = 'RCUR';
         * one time direct debit : SEQUENCE_TYPE_ONCE = 'OOFF';
         * final direct debit : SEQUENCE_TYPE_FINAL = 'FNAL';
         */
        $sequenceType = SepaUtilities::SEQUENCE_TYPE_RECURRING;

        $directDebitFile = new SephpaDirectDebit($this->empresa->nombre, $paymentInfoId, $sepaPAIN, $checkAndSanitize);

        $creationDateTime = date('Y-m-d\TH:i:s', strtotime($this->remesa->fecha . ' ' . $this->hour()));

        // at least one in every SEPA file. No limit.
        $directDebitCollection = $directDebitFile->addCollection(
            array(
                'pmtInfId' => $paymentInfoId,
                'lclInstrm' => $localInstrument,
                'seqTp' => $sequenceType,
                'cdtr' => $this->sanitize_name($this->empresa->nombre),
                'iban' => $this->remesa->iban(),
                'bic' => $this->remesa->swift,
                'ci' => $this->remesa->creditorid,
                'ccy' => $this->remesa->coddivisa,
                'reqdColltnDt' => date('Y-m-d', strtotime($this->remesa->fechacargo)),
        ));

        // at least one in every DirectDebitCollection. No limit.
        foreach ($this->resultados as $recibo) {
            $payment = [
                'pmtId' => $recibo->codigo,
                'instdAmt' => $recibo->importe,
                'mndtId' => $recibo->codigo,
                'dtOfSgntr' => date('Y-m-d', strtotime($recibo->fecha)),
                'dbtr' => $this->sanitize_name($recibo->nombrecliente),
                'bic' => $recibo->swift,
                'iban' => $recibo->iban(),
                'rmtInf' => $recibo->codigo,
            ];

            if (!empty($recibo->fmandato)) {
                $payment['dtOfSgntr'] = date('Y-m-d', strtotime($recibo->fmandato));
            }

            $directDebitCollection->addPayment($payment);
        }

        $this->remesa->estado = "En trámite";
        if ($this->remesa->save()) {
            $this->template = FALSE;
            $directDebitFile->downloadSepaFile('Remesa_' . $this->remesa->idremesa . '_' . $this->remesa->fecha
                . '_SEPA_' . $localInstrument . '' . '.xml', $creationDateTime, $this->remesa->creditorid);
        } else {
            $this->new_error_msg("¡Imposible modificar la remesa!");
        }
    }

    private function sanitize_name($name)
    {
        $from = ['&', 'ñ', 'Ñ', 'ç', 'Ç'];
        $to = ['&amp;', 'n', 'N', 'c', 'C'];
        return substr(str_replace($from, $to, $name), 0, 70);
    }

    private function liberar_recibos()
    {
        $sql = "UPDATE reciboscli SET idremesa = NULL WHERE idremesa NOT IN (SELECT idremesa FROM remesas_sepa);";
        $this->db->exec($sql);
    }

    private function pagar_recibos()
    {
        $pagados = 0;

        $cuentab = $this->cuentab->get($this->remesa->codcuenta);
        if ($cuentab) {
            foreach ($this->recibo_cliente_model->all_from_remesa($this->remesa->idremesa) as $recibo) {
                if ($recibo->estado == 'Pagado') {
                    /// Recibo ya pagado
                } else if ($this->recibo_factura_tools->nuevo_pago_cli($recibo, $this->codsubcuenta_pago, 'Pago', $this->remesa->fechacargo)) {
                    $pagados++;
                } else {
                    $this->new_error_msg('Imposible guardar el pago del recibo ' . $recibo->codigo);
                }
            }

            $this->new_message($pagados . ' recibos marcados como pagados.');
        } else {
            $this->new_error_msg('Cuenta bancaria no encontrada.');
        }
    }

    private function share_extensions()
    {
        /// botón para generar remesas en el FSDK
        $fsext = new fs_extension();
        $fsext->name = 'gen_remesas';
        $fsext->from = __CLASS__;
        $fsext->to = 'fsdk_home';
        $fsext->type = 'generate';
        $fsext->text = '<i class="fa fa-bank" aria-hidden="true"></i> Remesas';
        $fsext->params = '&gdp=remesas';
        $fsext->save();
    }

    private function generar_datos_prueba()
    {
        require_once __DIR__ . '/../lib/generar_datos_prueba.php';
        $gdp = new generar_datos_prueba_crm($this->db, $this->empresa);

        switch ($_GET['gdp']) {
            case 'remesas':
                $num = $gdp->remesas();
                $this->new_message('Generadas ' . $num . ' remesas.');
                $this->new_message('Recargando... &nbsp; <i class="fa fa-refresh fa-spin"></i><br/>'
                    . '<a href="index.php?page=fsdk_home">Detener</a>');

                $this->url_recarga = $this->url() . '&gdp=remesas';
                break;
        }
    }

    public function estados()
    {
        return $this->remesa_model->estados();
    }

    public function pagada()
    {
        foreach ($this->resultados as $recibo) {
            if ($recibo->estado == 'Pagado') {
                return TRUE;
            }
        }

        return false;
    }
}
