<?php
class CustomerPaymentRepository extends EntityRepository
{

    private $table = 'customer_payments';
    public $flashmessenger = null;
    private $options = array(
        'date' => null,
        'customer' => null,
        'payment_method' => null,
        'store_payment_type_id' => null,
        'store_payment' => null,
        'operation_num' => null,
        'amount' => null,
        'notes' => null,
        'memo' => null,
        'status' => null,
        'suma_de_pagos' => null,
        'saldo_id' => null
    );

    private $options_aux = array(
        'formaName' => null,
        'pago' => null,
        'attachments' => null
    );

    /*Input double y que no son hide*/
    public $inputs_double = array(
        'amount',
    );

    public function __construct()
    {
        if (!$this->flashmessenger instanceof FlashMessenger) {
            $this->flashmessenger = new FlashMessenger();
        }
    }

    public function _getTranslation($text)
    {
        return $this->flashmessenger->_getTranslation($text);
    }

    public function setOptions($data)
    {
        foreach ($this->options as $option => $value) {
            if (isset($data[$option])) {
                $this->options[$option] = $data[$option];
            }
        }

        foreach ($this->options_aux as $option => $value) {
            if (isset($data[$option])) {
                $this->options_aux[$option] = $data[$option];
            }
        }
    }

    public function getOptions()
    {
        return $this->options;
    }

    public function getMonto()
    {
        return $this->options['amount'];
    }

    public function getCustomer()
    {
        return $this->options['customer'];
    }

    public function getPaymentMethod()
    {
        return $this->options['payment_method'];
    }

    public function getNumOperacion()
    {
        return $this->options['operation_num'];
    }

    public function getFecha()
    {
        return $this->options['date'];
    }

    public function getStatus()
    {
        return $this->options['status'];
    }

    public function getComentarios()
    {

        return $this->options['notes'];
    }

    public function getTable()
    {

        return $this->table;
    }

    public function getMontoLetra($amount = null)
    {
        $numLetra = new NumeroALetra();
        $numLetra->setPrefijo('');
        $numLetra->setSufijo('');
        $numLetra->setMoneda('');

        if ($amount === null) {
            $amount = $this->options['amount'];
        }

        $numLetra->setNumero($amount);

        return $numLetra->letra();
    }

    public function getDataToEdit($id)
    {
        $query = "SELECT p.*,"
            . "f.id as invoice_id,"
            . "f.invoice_num,"
            . "f.customer_po,"
            . "p.customer,"
            . "fxGetCustomerName(p.customer)as customerName,"

            . "f.id as invoice_id,"
            . "DATE_FORMAT(f.date,'%m/%d/%Y')as formatedDate,"
            . "DATE_FORMAT(f.due_date,'%m/%d/%Y')as formatedDueDate,"
            . "DATE_FORMAT(p.date,'%m/%d/%Y')as datePago,"
            . "f.total as amountFactura,"
            . "d.amount as paymentAmount,"
            . "f.total - f.payments as balance "
            . "FROM customer_payments p,customer_payment_details d,invoices f "
            . "WHERE p.id = d.payment_id "
            . "AND d.invoice_id =  f.id "
            . "AND p.id = '$id'";

        $result = $this->query($query);

        if ($result->num_rows > 0) {
            $result = $this->resultToArray($result);

            $arrayTemp = array();
            $arrayTemp['date'] = $result[0]['datePago'];
            $arrayTemp['customer'] = $result[0]['customer'];
            $arrayTemp['store_payment'] = $result[0]['store_payment'];

            $arrayTemp['payment_method'] = $result[0]['payment_method'];
            $arrayTemp['store_payment_type_id'] = $result[0]['store_payment_type_id'];
            $arrayTemp['operation_num'] = $result[0]['operation_num'];
            $arrayTemp['amount'] = $result[0]['amount'];
            $arrayTemp['notes'] = $result[0]['notes'];
            $arrayTemp['memo'] = $result[0]['memo'];
            $arrayTemp['status'] = $result[0]['status'];

            $facturasLiquidadas = array();
            foreach ($result as $pago) {
                $pagos[$pago['invoice_id']] = $pago['paymentAmount'];
                $pagosOriginales[$pago['invoice_id']] = $pago;

                if ($pago['balance'] <= 0) {
                    $pago['balance'] += $pago['paymentAmount'];
                    $facturasLiquidadas[$pago['invoice_id']] = $pago;
                }
            }

            $arrayTemp['pago'] = $pagos;

            return array(
                'data' => $arrayTemp,
                'facturasLiquidadas' => $facturasLiquidadas,
                'pagosOriginales' => $pagosOriginales
            );
        }
    }

    public function getIdCustomer()
    {
        return $this->options['id_cliente'];
    }

    public function crearPDF()
    {
        $pdf = new PagoPDF($this->getId(), true);
        $this->pagoPDF = $pdf->getPathFileCreated();
    }

    public function crearZip()
    {
        $zipfile = new zipfile();
        $this->archivoZip = "Pago-" . $this->getNumPago() . ".zip";

        $empresa = new EmpresaEntity();
        $empresa->setOptions($empresa->getById(1));

        $zipfile->add_file(implode("", file($this->pagoPDF)), $this->getNumPago() . ".pdf");
        $zipfile->add_file(implode("", file(PATH_SAT_DOCS . "/1/Pagos/Pago-" . $this->getNumPago() . ".xml")), $this->getNumPago() . ".xml");

        $fd = fopen(PATH_SAT_DOCS . "/1/Pagos/temp-pdf/" . $this->archivoZip, "wb");
        $out = fwrite($fd, $zipfile->file());
        fclose($fd);

        return PATH_SAT_DOCS . "/1/Pagos/temp-pdf/" . $this->archivoZip;
    }

    public function descargarZip()
    {
        $file = $this->crearZip();
        $fileName = $this->getRutaArchivoZip();
        header("Content-type: application/octet-stream");
        header("Content-disposition: attachment; filename=$fileName");
        // leemos el archivo creado
        readfile($file);
    }

    public function getRutaArchivoZip()
    {

        return $this->archivoZip;
    }

    public function save(array $data, $table = null)
    {

        $attachments = $this->options_aux['attachments'];
        $facturas = $this->options_aux['pago'];

        $tools = new Tools();
        $data['status'] = '1';
        $data['date'] = $tools->setFormatDateToDB($data['date']);
        $sumaPagos = $data['suma_de_pagos']; //UG agregamos el total de pagos
       
        $monto = $data['amount']; //UG el total del pago

        $saldo_id = $data['saldo_id'];
        //var_dump($saldo_id);
        

        unset($data['suma_de_pagos']);//UG Eliminamos 

        unset($data['saldo_id']);//UG Eliminamos 

        $this->startTransaction();
        $data = parent::_rawNumber($data, $this->inputs_double);
        $result = parent::save($data, $this->table);
        if ($result) {
            $idPago = $this->getInsertId();
            $this->setLastInsertId($idPago);
            $facturaEntity = new InvoiceRepository();

            foreach ($facturas as $invoice_id => $amount) {
                if ($amount > 0 && trim($amount != '') && $amount !== null) {
                    $dataFactura = $facturaEntity->getById($invoice_id);
                    $details = array(
                        'payment_id' => $idPago,
                        'invoice_id' => $invoice_id,
                        'customer_po' => $dataFactura['customer_po'],
                        'amount' => $amount
                    );

                    $result = parent::save($details, 'customer_payment_details');

                    if ($result) {
                        if (!$this->setAmmountPaymentsOfStoreIn($invoice_id)) {
                            $this->rollback();
                            $this->flashmessenger->addMessage(array('danger' => 'Error. Intenta nuevamente o contacta a tu customer de sistemas.'));
                            return null;
                        }
                    } else {
                        $this->flashmessenger->addMessage(array('danger' => 'Error. Intenta nuevamente o contacta a tu customer de sistemas.'));
                        $this->rollback();
                        return null;
                    }
                }
            }


            #UG guardar el pago dentro de saldos_sucursal cuando sea necesario
            if ($sumaPagos < $monto && $data['payment_method'] !== '8') { //UG que el pago no sea 'ya' una nota de credito
                $data_format = date('Y-m-d H:i:s');
                #Hacer calculo de saldo a favor
                $saldo_favor = $monto - $sumaPagos;
                //var_dump($saldo_favor);exit;
                $saldo_sucursal = array(
                    'payment_id' => $idPago,
                    'customer_id' => $data['customer'],
                    'store_id' => $data['store_payment'],
                    'saldo_favor' => $saldo_favor,
                    'saldo_restante' => $saldo_favor, //Al inicio es el mismo monto
                    'creado_fecha' => $data_format,
                    'status' => '1' //Al inicio del registro
                );

                $result_saldo = parent::save($saldo_sucursal, 'saldos_sucursal');
                if ($result_saldo) {

                } else {
                    $this->flashmessenger->addMessage(array('danger' => 'Error. Intenta nuevamente error al crear el saldo a favor del cliente.'));
                    $this->rollback();

                }
            }

            //UG Descontar el saldo a favor
            if ($data['payment_method'] == '8')//si existe un saldo_id !== null quiere decir que es un pago tipo Nota de credito
            {
                #descontar sumaPagos de saldo a favor
                $nuevo_saldo = $monto - $sumaPagos;
                if($nuevo_saldo < 0){
                    $nuevo_saldo = 0; 
                }             
                parent::query("UPDATE saldos_sucursal SET saldo_restante = '$nuevo_saldo' WHERE saldo_id = '$saldo_id'");
                parent::commit();
            }

            $fileManagement = new FileManagement();
            if (isset($attachments['attachments']['name'][0]) && $attachments['attachments']['name'][0] != '') {
                $fileManagement->saveFile($attachments['attachments'], $idPago, 'customer_payment');
            }
        }
        $this->setLastInsertId($idPago);
        $this->commit();
        return true;
    }

    public function updateMultiple($id, $data)
    {
        $attachments = $this->options_aux['attachments'];
        $facturas = $this->options_aux['pago'];

        $tools = new Tools();
        $data['date'] = $tools->setFormatDateToDB($data['date']);
        unset($data['suma_de_pagos']);//UG Eliminamos 

        unset($data['saldo_id']);//UG Eliminamos 
        $this->startTransaction();
        $data = parent::_rawNumber($data, $this->inputs_double);
        $result = parent::update($id, $data, $this->table);

        if ($result) {
            $facturaEntity = new InvoiceRepository();
            $arrayIdsPagos = array();
            foreach ($facturas as $invoice_id => $amount) {
                if ($amount > 0 && trim($amount != '') && $amount !== null) {
                    $dataFactura = $facturaEntity->getById($invoice_id);
                    //$invoice_id[1] contiene el id de Pago
                    //Si existe $invoice_id[1], significa que ya existe un pago con ese id y solo debe actualizarse
                    //Sino existe, debe agregarse.
                    if ($this->existePago($id, $invoice_id)) {
                        #Se actualiza Pago
                        $result = parent::updateString(array('amount' => $amount), " payment_id = '$id' AND invoice_id = '$invoice_id' ", 'customer_payment_details');
                        if ($result) {
                            $arrayIdsPagos[] = $invoice_id;
                            $result = $this->setAmmountPaymentsOfStoreIn($invoice_id);
                        }
                    } else {
                        #Se inserta Pago
                        $details = array(
                            'payment_id' => $id,
                            'invoice_id' => $invoice_id,
                            'customer_po' => $dataFactura['customer_po'],
                            'amount' => $amount
                        );

                        $result = parent::save($details, 'customer_payment_details');
                    }

                    if ($result === null) {
                        $this->flashmessenger->addMessage(array('danger' => 'Error. Intenta nuevamente o contacta a tu customer de sistemas.'));
                        $this->rollback();
                        return null;
                    }
                }
            }

            foreach ($_SESSION['pagosOriginales'] as $pago) {
                if (!in_array($pago['invoice_id'], $arrayIdsPagos)) {
                    $this->query("DELETE FROM customer_payment_details WHERE payment_id = '$id' AND invoice_id = '{$pago['invoice_id']}'");
                    $this->setAmmountPaymentsOfStoreIn($pago['invoice_id']);
                }
            }

            $this->commit();

            $fileManagement = new FileManagement();
            if (isset($attachments['attachments']['name'][0]) && $attachments['attachments']['name'][0] != '') {
                $fileManagement->saveFile($attachments['attachments'], $id, 'customer_payment');
            }

            return true;
        }
        return null;
    }

    public function delete($id, $table = null)
    {
        $data = $this->getById($id);
        if ($data['status'] == '2') {
            return true;
        }

        $this->startTransaction();
        if (parent::update($id, array('status' => '2'), $this->table)) {
            $detalles = $this->getDetallesByIdPago($id);

            if ($detalles && count($detalles) > 0) {
                foreach ($detalles as $detalle) {
                    if (!$this->setAmmountPaymentsOfStoreIn($detalle['invoice_id'])) {
                        $this->flashmessenger->addMessage(array('danger' => $this->_getTranslation('Opps !!. Algo salio mal al intentar cancelar el Pago.<br/>Intente nuevamente.')));
                        $this->rollback(); 
                        return null;
                    }
                }
            }
            

           
            $this->commit();

             #Buscar si existen saldos sobre ese payment_id
             $resultPagoSucursal = $this->getSaldosSucursales(null,null,$id);

             #UG Validar si el pago es tipo nota de credito = 8
             if (isset($resultPagoSucursal)) {
                //var_dump($resultPagoSucursal[0]);exit;
                #Es necesario cambiar el status del saldo_sucursal a 2 = cancelado              
                $_paymentId =$resultPagoSucursal[0]['payment_id'];
                parent::query("UPDATE saldos_sucursal SET status = '2' WHERE payment_id = '$_paymentId'");
                parent::commit();
            }

            $this->flashmessenger->addMessage(array('success' => $this->_getTranslation('Genial !!. El pago fue cancelado correctamente.')));
            return true;
        }

        $this->flashmessenger->addMessage(array('danger' => $this->_getTranslation('Opps !!. Algo salio mal al intentar cancelar el Pago.<br/>Intente nuevamente.')));
        return null;
    }

    public function getById($id, $table = null, $selectAux = null)
    {
        $select = "SELECT p.*,"
            . "DATE_FORMAT(convert(substring(p.date,1,10),date),'%d/%m/%Y')as date,"
            . "fxGetCustomerName(p.customer)as customerName, "
            . "fxGetPaymentMethodName(p.payment_method)as formaName, "
            . " fxGetStatusName(p.status,'Payment')as statusName, "
            . "fxGetUserName(p.creado_por) as userName "
            . "FROM $this->table p  "
            . "WHERE p.id = '$id' ";

        $result = $this->query($select);

        if ($result->num_rows > 0) {
            $set = $this->resultToArray($result);
            return $set[0];
        }
        return false;
    }

    public function isUsedInRecord($id, array $buscarEn = null, $andWhere = null)
    {
        return true;
        #return parent::isUsedInRecord($id, array('facturas'=>'shipFrom'),"AND tipo = 'Inbound'");   
    }

    public function updateString($fields, $where, $table = null)
    {
        return parent::updateString($fields, $where, $this->table);
    }

    public function existePago($idPago, $invoice_id)
    {
        $query = "SELECT * "
            . "FROM customer_payments p, customer_payment_details d "
            . "WHERE p.id = d.payment_id "
            . "AND p.status != 3 "
            . "AND payment_id = $idPago "
            . "AND invoice_id = $invoice_id";

        $result = $this->query($query);

        if ($result->num_rows > 0) {
            return true;
        }
        return null;
    }
    public function getSaldosSucursales($customer_id, $store_id,$idPago = null)
    {

        $filter_customer = "";
        $filter_store = "";
        $filter_idPago = "";
        #obtener un registro en especifico
        if($idPago){
            $filter_idPago = " AND payment_id = $idPago";
        }else{
            $filter_customer = " AND customer_id = $customer_id ";
            $filter_store = " AND store_id = $store_id ";
        }
        $query = "SELECT *, "
            . "DATE_FORMAT(creado_fecha,'%m/%d/%Y')as formatedDate "
            . "FROM saldos_sucursal ss "
            . "WHERE ss.saldo_restante > 0 AND ss.status = 1"
            . "$filter_customer "
            . "$filter_store "
            . "$filter_idPago ";

        $result = $this->query($query);

        if ($result->num_rows > 0) {
            return $this->resultToArray($result);
        }
        return null;
    }

    public function getDetallesByIdPago($idPago)
    {
        $query = "SELECT * "
            . "FROM customer_payment_details "
            . "WHERE payment_id = '$idPago' ";

        $result = $this->query($query);
        if ($result->num_rows > 0) {
            return $this->resultToArray($result);
        }
        return null;
    }



    public function getListTypePaymentByStore($type = null)
    {
        $orderBy = " ORDER BY description ASC ";
        // if($type == 'Parts of the cake'){$orderBy = " ORDER BY FIELD (description,'Pan','Relleno','Decorado')";}
        if ($type) {
            $type = " AND module = '$type'";
        }

        $query = "SELECT id,description "
            . "FROM store_payment_type "
            . "WHERE 1 = 1 "
            . "$type "
            . "$orderBy";

        $result = $this->query($query);

        if ($result->num_rows > 0) {
            $array = array();
            while ($row = $result->fetch_object()) {
                $array[$row->id] = $row->description;
            }
            return $array;
        }

        return null;
    }

    public function getListPagos($options)
    {
        $date = null;
        $paymentNumber = null;
        $paymentMethod = null;
        $invoiceNumber = null;
        $operationNumber = null;
        $customer = null;
        $customer_po = null;
        $monto = null;
        $status = null;
        $user_id = null;
        $limit = null;

        if ($options) {
            $date = $this->createFilterFecha($options, 'p.date');
            if (trim($options['payment_number']) !== '') {
                $paymentNumber = " AND find_in_set(p.id,'{$options['payment_number']}')";
            }
            if (trim($options['operation_num']) !== '') {
                $operationNumber = " AND find_in_set(p.operation_num,'{$options['operation_num']}')";
            }
            if (trim($options['invoice_num']) !== '') {
                $invoiceNumber = " AND find_in_set(f.invoice_num,'{$options['invoice_num']}')";
            }
            if (trim($options['customer_po']) !== '') {
                $customer_po = " AND find_in_set(d.customer_po,'{$options['customer_po']}')";
            }
            if (trim($options['amount']) !== '') {
                $monto = " AND find_in_set(p.amount,'{$options['amount']}')";
            }

            if (isset($options['payment_method'])) {
                if (is_array($options['payment_method']) && count($options['payment_method']) > 0) {
                    $paymentMethodIds = implode(',', $options['payment_method']);
                    $paymentMethod = " AND find_in_set(p.payment_method,'{$paymentMethodIds}')";
                } else {
                    if (trim($options['payment_method']) != '') {
                        $paymentMethod = " AND find_in_set(p.payment_method,'{$options['payment_method']}')";
                    }
                }
            }

            if (isset($options['customer_id'])) {
                if (is_array($options['customer_id']) && count($options['customer_id']) > 0) {
                    $customerIds = implode(',', $options['customer_id']);
                    $customer = " AND find_in_set(f.id_customer,'{$customerIds}')";
                } else {
                    if (trim($options['customer_id']) != '') {
                        $customer = " AND find_in_set(f.id_customer,'{$options['customer_id']}')";
                    }
                }
            }

            if (isset($options['user_id'])) {
                if (is_array($options['user_id']) && count($options['user_id']) > 0) {
                    $userIds = implode(',', $options['user_id']);
                    $user_id = " AND find_in_set(p.creado_por,'{$userIds}')";
                } else {
                    if (trim($options['user_id']) != '') {
                        $user_id = " AND find_in_set(p.creado_por,'{$options['user_id']}')";
                    }
                }
            }

            if (isset($options['status']) && is_array($options['status']) && count($options['status']) > 0) {
                $idsStatus = implode(',', $options['status']);
                $status = " AND find_in_set(p.status,'$idsStatus')";
            }

            if (
                is_null($date)
                && is_null($customer)
                && is_null($invoiceNumber)
                && is_null($paymentNumber)
                && is_null($paymentMethod)
                && is_null($operationNumber)
                && is_null($monto)
                && is_null($customer_po)
                && is_null($status)
                && is_null($user_id)
            ) {
                $limit = " LIMIT 300";
            }


        } else {
            $limit = " LIMIT 300";
        }

        $query = "SELECT 
                    p.id,
                    GROUP_CONCAT(f.invoice_num)as invoice_num,
                    DATE_FORMAT(p.date,'%d/%m/%Y')as date,
                    fxGetCustomerName(p.customer) as customerName,
                    p.operation_num,
                    p.amount as total,
                    IF(p.payment_method !='',fxGetPaymentMethodName(p.payment_method),'')as paymentMethod,
                    (total - payments)as balance,
                    fxGetStatusName(p.status,'Payment')as statusName,
                    p.status,
                    fxGetStoreName(GROUP_CONCAT(f.billed_to_store))as store_name,
                    fxGetUserName(p.creado_por)as createdByName,
                    DATE_FORMAT(p.creado_fecha,'%m/%d/%Y')as formatedCreatedDate 
                FROM customer_payments p, customer_payment_details d, invoices f
                WHERE 1=1 
                AND p.id = d.payment_id
                AND d.invoice_id = f.id
                $date
                $paymentNumber
                $paymentMethod
                $invoiceNumber
                $operationNumber
                $customer
                $customer_po
                $monto
                $status
                $user_id
                GROUP BY p.id
                ORDER BY p.date DESC, p.id DESC $limit";

        #var_dump($query);exit;
        $result = $this->query($query);

        if ($result->num_rows > 0) {
            return $this->resultToArray($result);
        }
        return null;
    }

    public function getListFormaPago()
    {
        $query = "SELECT id,description FROM payment_methods WHERE tipo = 'Forma pago'";
        $result = $this->query($query);

        if ($result) {
            $array = array();
            while ($row = $result->fetch_object()) {
                $array[$row->id] = $row->description;
            }

            return $array;
        }
    }
    public function getListStorePaymentType()
    {
        $query = "SELECT id,description FROM store_payment_type WHERE module = 'Pago de sucursal'";
        $result = $this->query($query);

        if ($result) {
            $array = array();
            while ($row = $result->fetch_object()) {
                $array[$row->id] = $row->description;
            }

            return $array;
        }
    }

    public function createFilterFecha($options, $campoFecha = null)
    {
        $dateInicio = $options['startDate'];
        $dateFin = $options['endDate'];
        $date = null;
        $tools = new Tools();

        if ($dateInicio != null) {
            $dateInicio = $tools->setFormatDateToDB($dateInicio);
            if ($dateFin != null) {
                $dateFin = $tools->setFormatDateToDB($dateFin);
                $date .= " AND $campoFecha BETWEEN '{$dateInicio}' AND '{$dateFin}' ";
            } else {
                $date .= " AND $campoFecha BETWEEN '{$dateInicio}' AND '{$dateInicio}' ";
            }

        } elseif ($dateFin != null) {
            $date .= " AND $campoFecha BETWEEN '{$dateFin}' AND '{$dateFin}' ";
        }
        return $date;
    }

    public function setAmmountPaymentsOfStoreIn($invoice_id)
    {
        $query = "SELECT d.invoice_id,"
            . "IFNULL(SUM(d.amount),0)as amount "
            . "FROM customer_payments p,customer_payment_details d "
            . "WHERE p.id = d.payment_id "
            . "AND d.invoice_id = '$invoice_id' "
            . "AND p.status = 1 ";

        $result = $this->query($query);

        if ($result) {
            $result = $result->fetch_object();
            if (parent::update($invoice_id, array('payments' => $result->amount), 'invoices')) {
                $repo = new InvoiceRepository();
                $data = $repo->getById($invoice_id);
                $balance = $data['total'] - $result->amount;
                if ($balance > 0) {
                    $status = '1';
                } else {
                    $status = '2';
                }

                if (parent::update($invoice_id, array('status' => $status), 'invoices')) {
                    return true;
                }
                return true;
            }
        }
        return null;
    }

    public function getListFiles($id)
    {
        $fileManagement = new FileManagement();
        return $fileManagement->getStringListFilesByOperationAndPrefix('customer_payment', $id);
    }
}