<?php
class PagoRepository extends EntityRepository {   

    private $table = 'pagos';
    public $flashmessenger = null;       
     private $options = array(      
        'fecha' => null,
        'proveedor' => null,
        'forma_de_pago' => null,
        'num_operacion' => null,
        'monto' => null,
        'notas' => null,
        'status' => null
    );
     
    private $options_aux = array(
        'formaName' => null,
    );
    
    
    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['monto'];   
    }

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

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

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

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

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

    public function getComentarios() {

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

    public function getTable() {

        return $this->table;
    }

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

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

        $numLetra->setNumero($monto);

        return $numLetra->letra();
    }

    public function getDataToEdit($id) {
        $query = "SELECT p.*,"
                . "f.purchase_number,"
                . "p.proveedor,"
                . "fxGetVendorName(p.proveedor)as proveedorName,"
                . "f.id as idFactura,"
                . "DATE_FORMAT(f.purchase_date,'%d/%m/%Y')as fecha,"
                . "DATE_FORMAT(p.fecha,'%d/%m/%Y')as fechaPago,"
                . "f.total as montoFactura,"
                . "d.monto as montoPago,"
                . "f.total - f.payments as saldoPendiente "
                . "FROM pagos p,pagos_detalle d,purchases f "
                . "WHERE p.id = d.id_pago "
                . "AND d.id_factura =  f.id "
                . "AND p.id = '$id'";

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

            $arrayTemp = array();
            $arrayTemp['fecha'] = $result[0]['fechaPago'];
            $arrayTemp['proveedor'] = $result[0]['proveedor'];
            $arrayTemp['forma_de_pago'] = $result[0]['forma_de_pago'];
            $arrayTemp['num_operacion'] = $result[0]['num_operacion'];
            $arrayTemp['monto'] = $result[0]['monto'];
            $arrayTemp['notas'] = $result[0]['notas'];
            $arrayTemp['status'] = $result[0]['status'];

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

                if ($pago['saldoPendiente'] <= 0) {
                    $pago['saldoPendiente'] += $pago['montoPago'];
                    $facturasLiquidadas[$pago['idFactura']] = $pago;
                }
            }

            $arrayTemp['pago'] = $pagos;

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

    public function getIdCliente() {
        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){ 
      $facturas = $data['pago'];      
      unset($data['pago']);
      
      $tools = new Tools();
      $data['status'] = '1';
      $data['fecha'] = $tools->setFormatDateToDB($data['fecha']);      
      
      $this->startTransaction();
      $result = parent::save($data, $this->table);
      if($result){
          $idPago = $this->getInsertId();
          $this->setLastInsertId($idPago);
          $facturaEntity = new PurchaseRepository();
          
          foreach ($facturas as $idFactura => $monto){           
            if($monto > 0 && trim($monto!= '') && $monto !== null){                
                $dataFactura = $facturaEntity->getById($idFactura);
                $details = array(
                        'id_pago'=>$idPago,
                        'id_factura'=>$idFactura,
                        'reference'=>$dataFactura['purchase_number'],
                        'monto'=>$monto);                

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

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

  public function updateMultiple($id,$data){
        $facturas = $data['pago'];      
        unset($data['pago']);

        $tools = new Tools();
        $data['fecha'] = $tools->setFormatDateToDB($data['fecha']);      

        $this->startTransaction();   
        $result = parent::update($id, $data,$this->table);      

        if($result){
            $facturaEntity = new PurchaseRepository();
            $arrayIdsPagos = array();
            foreach ($facturas as $idFactura => $monto){
                if($monto > 0 && trim($monto!= '') && $monto !== null){ 
                    $dataFactura = $facturaEntity->getById($idFactura);
                    //$idFactura[1] contiene el id de Pago
                    //Si existe $idFactura[1], significa que ya existe un pago con ese id y solo debe actualizarse
                    //Sino existe, debe agregarse.
                    if($this->existePago($id, $idFactura)){
                        #Se actualiza Pago
                        $result = parent::updateString(array('monto'=>$monto), " id_pago = '$id' AND id_factura = '$idFactura' ", 'pagos_detalle');
                        if($result){
                            $arrayIdsPagos[] = $idFactura; 
                            $result = $this->setAmmountPaymentsOfStoreIn($idFactura);
                        }                        
                    }else{
                        #Se inserta Pago
                        $details = array(
                                'id_pago'=>$id,
                                'id_factura'=>$idFactura,
                                'reference'=>$dataFactura['purchase_number'],
                                'monto'=>$monto);                
                          
                        $result = parent::save($details,'pagos_detalle');
                    }    
                    
                    if($result === null){
                        $this->flashmessenger->addMessage(array('danger'=>'Error. Intenta nuevamente o contacta a tu proveedor de sistemas.'));
                        $this->rollback();
                        return null;
                    }
                }
            }            
            
            foreach($_SESSION['pagosOriginales'] as $pago){
                if(!in_array($pago['idFactura'], $arrayIdsPagos)){
                    $this->query("DELETE FROM pagos_detalle WHERE id_pago = '$id' AND id_factura = '{$pago['idFactura']}'");
                    $this->setAmmountPaymentsOfStoreIn($pago['idFactura']);
                }
            }
            
            $this->commit();
            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['id_factura'])){
                        $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();
            $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.fecha,1,10),date),'%d/%m/%Y')as fecha,"
                . "fxGetVendorName(p.proveedor)as proveedorName, "
                . "fxGetPaymentMethodName(p.forma_de_pago)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,$idFactura){
        $query = "SELECT * "
                . "FROM pagos p, pagos_detalle d "
                . "WHERE p.id = d.id_pago "
                . "AND p.status != 3 "
                . "AND id_pago = $idPago "
                . "AND id_factura = $idFactura";

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

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

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

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

    public function getListPagos($options){        
        $limit = null;
        $date = null;
        $vendor_id = null;
        $forma_de_pago = null;
        $num_operacion = null;
        $status = null;
        
        $date = $this->createFilterFecha($options, 'p.fecha');
        if($options){
            if(isset($options['vendor_id'])){
                if(is_array($options['vendor_id']) && count($options['vendor_id']) > 0){
                    $vendorIds = implode(',', $options['vendor_id']);
                    $vendor_id = " AND find_in_set(f.vendor_id,'{$vendorIds}')";
                }else{
                     $vendor_id = " AND find_in_set(f.vendor_id,'{$options['vendor_id']}')";
                }           
            } 
            if(isset($options['forma_de_pago']) && trim($options['forma_de_pago']) != ''){$forma_de_pago = " AND  find_in_set(p.forma_de_pago,'{$options['forma_de_pago']}')";}
            if(isset($options['num_operacion']) && trim($options['num_operacion']) != ''){$num_operacion = " AND  find_in_set(p.num_operacion,'{$options['num_operacion']}')";}
            if(isset($options['purchase_number']) && trim($options['purchase_number']) != ''){$num_operacion = " AND  find_in_set(d.reference,'{$options['purchase_number']}')";}
            if(isset($options['status']) && trim($options['status']) != ''){$status = " AND p.status = '{$options['status']}'";}
            
        }else{
            $limit = " LIMIT 300";
        }       
        $query = "SELECT 
                    p.id,
                    GROUP_CONCAT(f.purchase_number)as purchase_number,
                    DATE_FORMAT(p.fecha,'%d/%m/%Y')as fecha,
                    fxGetVendorName(p.proveedor) as proveedorName,
                    p.num_operacion,
                    SUM(d.monto) as total,
                    IF(p.forma_de_pago !='',fxGetPaymentMethodName(p.forma_de_pago),'')as formaPago,
                    fxGetStatusName(p.status,'Payment')as statusName,
                    p.status
                FROM pagos p, pagos_detalle d, purchases f
                WHERE 1=1 
                AND p.id = d.id_pago
                AND d.id_factura = f.id
                $date
                $vendor_id 
                $forma_de_pago
                $num_operacion
                $status
                GROUP BY p.id
                ORDER BY p.fecha DESC $limit";

        # var_dump($options);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 createFilterFecha($options,$campoFecha = null ){
        $fechaInicio = $options['fechaInicio'];
        $fechaFin = $options['fechaFin'];
        $fecha = null;
        $tools = new Tools();

        if($fechaInicio!=null){
            $fechaInicio = $tools->setFormatDateToDB($fechaInicio);
            if($fechaFin!=null){
                $fechaFin = $tools->setFormatDateToDB($fechaFin);
                $fecha .=" AND $campoFecha BETWEEN '{$fechaInicio}' AND '{$fechaFin}' ";
            }else{
                $fecha .=" AND $campoFecha BETWEEN '{$fechaInicio}' AND '{$fechaInicio}' ";
            }

        }elseif($fechaFin!=null){
            $fecha .=" AND $campoFecha BETWEEN '{$fechaFin}' AND '{$fechaFin}' ";
        }       
        return $fecha;
    }
    
    public function setAmmountPaymentsOfStoreIn($idFactura){
        $query = "SELECT d.id_factura,"
                . "IFNULL(SUM(d.monto),0)as monto "
                . "FROM pagos p,pagos_detalle d "
                . "WHERE p.id = d.id_pago "
                . "AND d.id_factura = '$idFactura' "
                . "AND p.status = 1 ";
        
        $result = $this->query($query);
        
        if($result){
            $result = $result->fetch_object();
            if(parent::update($idFactura, array('payments'=>$result->monto), 'purchases')){
                $repo = new PurchaseRepository();
                $data = $repo->getById($idFactura);
                $balance = $data['total'] - $result->monto;
                if($balance > 0){$status = '1';}else{$status = '2';}
                
                if(parent::update($idFactura, array('status'=>$status), 'purchases')){
                    return true;
                }            
                return true;
            }           
        }        
        return null;
    }    
    
    public function getPagosByIdFactura($id_factura) {
        $select = "SELECT p.*,d.monto, "
                . "fxGetClienteName(cliente)as clienteName,"
                . "IF(status = 2,DATE_FORMAT(convert(substring(fecha_timbrado,1,10),date),'%d/%m/%Y'),DATE_FORMAT(fecha,'%d/%m/%Y'))as fecha,"                
                . "fxGetTipoDeComprobanteName(tipo_documento)as comprobanteName, "             
                . "fxGetFormaDePagoName(forma_de_pago)as formaName, "
                . "fxGetMetodoDePagoName(metodo_de_pago)as metodoName, "
                . "fxGetMonedaName(moneda)as monedaName, "
                . "fxGetUsoCFDIName(uso_cfdi)as usoCFDIName, "
                . "fxGetStatusName(status,'Pago')as statusName, "
                . "fxGetUserName(p.creado_por) as userName "
                . "FROM $this->table p, pagos_detalle d "             
                . "WHERE p.id = d.id_pago and d.id_factura = '$id_factura'";

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

        if ($result->num_rows>0) {
            return $this->resultToArray($result);
        }
        return false;
    }
    
     public function getListStatus($options = null){        
        $query = "SELECT * FROM status_code WHERE operation = 'Payment'";
        $result = $this->query($query);
        
        if($result->num_rows > 0){
            $array = array();
            foreach($result as $status){
                $array[$status['code']] = $status['description'];
            }
            return $array;
        }
        return null;
    }
}