/**
  * Método que guarda el XML del Recibo de un intercambio
  * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
  * @version 2015-12-23
  */
 public function saveXML($Emisor, $xml)
 {
     // crear recibo
     $EnvioRecibos = new \sasco\LibreDTE\Sii\EnvioRecibos();
     $EnvioRecibos->loadXML($xml);
     if (!$EnvioRecibos->getID()) {
         return null;
     }
     $Caratula = $EnvioRecibos->toArray()['EnvioRecibos']['SetRecibos']['Caratula'];
     if (explode('-', $Caratula['RutRecibe'])[0] != $Emisor->rut) {
         return false;
     }
     // guardar recibo
     $this->db->beginTransaction();
     $this->responde = explode('-', $Caratula['RutResponde'])[0];
     $this->recibe = $Emisor->rut;
     $this->codigo = md5($xml);
     $this->contacto = !empty($Caratula['NmbContacto']) ? substr($Caratula['NmbContacto'], 0, 40) : null;
     $this->telefono = !empty($Caratula['FonoContacto']) ? substr($Caratula['FonoContacto'], 0, 40) : null;
     $this->email = !empty($Caratula['MailContacto']) ? substr($Caratula['MailContacto'], 0, 80) : null;
     $this->fecha_hora = str_replace('T', ' ', $Caratula['TmstFirmaEnv']);
     $this->xml = base64_encode($xml);
     if (!$this->save()) {
         $this->db->rollback();
         return false;
     }
     // procesar cada recibo
     foreach ($EnvioRecibos->getRecibos() as $Recibo) {
         // si el RUT del emisor no corresponde con el del contribuyente el
         // acuse no es para este
         if (explode('-', $Recibo['DocumentoRecibo']['RUTEmisor'])[0] != $Emisor->rut) {
             $this->db->rollback();
             return false;
         }
         // buscar DTE emitido en el ambiente del emisor
         $DteEmitido = new Model_DteEmitido($Emisor->rut, $Recibo['DocumentoRecibo']['TipoDoc'], $Recibo['DocumentoRecibo']['Folio'], $Emisor->certificacion);
         // si no existe o si los datos del DTE emitido no corresponden error
         if (!$DteEmitido->exists() or explode('-', $Recibo['DocumentoRecibo']['RUTRecep'])[0] != $DteEmitido->receptor or $Recibo['DocumentoRecibo']['FchEmis'] != $DteEmitido->fecha or $Recibo['DocumentoRecibo']['MntTotal'] != $DteEmitido->total) {
             $this->db->rollback();
             return false;
         }
         // guardar recibo para el DTE
         $DteIntercambioReciboDte = new Model_DteIntercambioReciboDte($DteEmitido->emisor, $DteEmitido->dte, $DteEmitido->folio, $DteEmitido->certificacion);
         $DteIntercambioReciboDte->responde = $this->responde;
         $DteIntercambioReciboDte->codigo = $this->codigo;
         $DteIntercambioReciboDte->recinto = substr($Recibo['DocumentoRecibo']['Recinto'], 0, 80);
         $DteIntercambioReciboDte->firma = substr($Recibo['DocumentoRecibo']['RutFirma'], 0, 10);
         $DteIntercambioReciboDte->fecha_hora = str_replace('T', ' ', $Recibo['DocumentoRecibo']['TmstFirmaRecibo']);
         if (!$DteIntercambioReciboDte->save()) {
             $this->db->rollback();
             return false;
         }
     }
     // aceptar transacción
     $this->db->commit();
     return true;
 }
 /**
  * Acción de la API que permite obtener la información de un DTE emitido
  * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
  * @version 2015-09-24
  */
 public function _api_info_GET($dte, $folio, $contribuyente = null)
 {
     $Emisor = $this->getContribuyente();
     if (!$Emisor) {
         if (!$contribuyente) {
             $this->Api->send('Debe indicar el emisor', 500);
         }
         $Emisor = new Model_Contribuyente($contribuyente);
         if (!$Emisor->exists()) {
             $this->Api->send('Emisor no existe', 404);
         }
     }
     $DteEmitido = new Model_DteEmitido($Emisor->rut, $dte, $folio, (int) $Emisor->certificacion);
     if (!$DteEmitido->exists()) {
         $this->Api->send('No existe el documento solicitado T.' . $dte . 'F' . $folio, 404);
     }
     $DteEmitido->xml = false;
     return $DteEmitido;
 }
 /**
  * Método que genera la el XML del DTE temporal con Folio y Firma y lo envía
  * al SII
  * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]delaf.cl)
  * @version 2016-01-02
  */
 public function generar($receptor, $dte, $codigo)
 {
     $Emisor = $this->getContribuyente();
     // obtener DTE temporal
     $DteTmp = new Model_DteTmp($Emisor->rut, $receptor, $dte, $codigo);
     if (!$DteTmp->exists()) {
         \sowerphp\core\Model_Datasource_Session::message('No existe el DTE temporal solicitado', 'error');
         $this->redirect('/dte/documentos/emitir');
     }
     // obtener firma electrónica
     $Firma = $Emisor->getFirma($this->Auth->User->id);
     if (!$Firma) {
         \sowerphp\core\Model_Datasource_Session::message('No hay firma electrónica asociada a la empresa (o bien no se pudo cargar), debe agregar su firma antes de generar DTE', 'error');
         $this->redirect('/dte/admin/firma_electronicas');
     }
     // solicitar folio
     $FolioInfo = $Emisor->getFolio($DteTmp->dte);
     if (!$FolioInfo) {
         \sowerphp\core\Model_Datasource_Session::message('No fue posible obtener un folio para el DTE de tipo ' . $DteTmp->dte, 'error');
         $this->redirect('/dte/dte_tmps');
     }
     // si quedan pocos folios y se debe alertar al usuario admnistrador de la empresa se hace
     if ($FolioInfo->DteFolio->disponibles <= $FolioInfo->DteFolio->alerta and !$FolioInfo->DteFolio->alertado) {
         $msg = 'Se ha alcanzado el límite de folios del tipo de DTE ' . $FolioInfo->DteFolio->dte . ' para el contribuyente ' . $Emisor->razon_social . ', quedan ' . $FolioInfo->DteFolio->disponibles . '. Por favor, solicite un nuevo archivo CAF y súbalo en: ' . "\n\n" . $this->request->url . '/dte/admin/dte_folios';
         if ($this->Notify->send(null, $Emisor->getUsuario()->id, $msg, 'email')) {
             $FolioInfo->DteFolio->alertado = 1;
             $FolioInfo->DteFolio->save();
         }
     }
     // armar xml a partir de json del DTE temporal
     $EnvioDte = $DteTmp->getEnvioDte($FolioInfo->folio, $FolioInfo->Caf, $Firma);
     $xml = $EnvioDte->generar();
     if (!$xml) {
         \sowerphp\core\Model_Datasource_Session::message('No fue posible generar el XML del EnvioDTE. Folio ' . $FolioInfo->folio . ' quedará sin usar.<br/>' . implode('<br/>', \sasco\LibreDTE\Log::readAll()), 'error');
         $this->redirect('/dte/documentos/emitir');
     }
     // guardar DTE
     $r = $EnvioDte->getDocumentos()[0]->getResumen();
     $DteEmitido = new Model_DteEmitido($Emisor->rut, $r['TpoDoc'], $r['NroDoc'], (int) $Emisor->certificacion);
     if ($DteEmitido->exists()) {
         \sowerphp\core\Model_Datasource_Session::message('Ya existe un DTE del tipo ' . $r['TpoDoc'] . ' y folio ' . $r['NroDoc'] . ' emitido', 'error');
         $this->redirect('/dte/dte_emitidos/ver/' . $r['TpoDoc'] . '/' . $r['NroDoc'] . '/' . (int) $Emisor->certificacion);
     }
     $cols = ['tasa' => 'TasaImp', 'fecha' => 'FchDoc', 'sucursal_sii' => 'CdgSIISucur', 'receptor' => 'RUTDoc', 'exento' => 'MntExe', 'neto' => 'MntNeto', 'iva' => 'MntIVA', 'total' => 'MntTotal'];
     foreach ($cols as $attr => $col) {
         if ($r[$col] !== false) {
             $DteEmitido->{$attr} = $r[$col];
         }
     }
     $DteEmitido->receptor = substr($DteEmitido->receptor, 0, -2);
     $DteEmitido->xml = base64_encode($xml);
     $DteEmitido->usuario = $this->Auth->User->id;
     // guardar referencias si existen
     $datos = json_decode($DteTmp->datos, true);
     if (isset($datos['Referencia'])) {
         foreach ($datos['Referencia'] as $referencia) {
             $DteReferencia = new Model_DteReferencia();
             $DteReferencia->emisor = $DteEmitido->emisor;
             $DteReferencia->dte = $DteEmitido->dte;
             $DteReferencia->folio = $DteEmitido->folio;
             $DteReferencia->certificacion = $DteEmitido->certificacion;
             $DteReferencia->referencia_dte = $referencia['TpoDocRef'];
             $DteReferencia->referencia_folio = $referencia['FolioRef'];
             $DteReferencia->codigo = !empty($referencia['CodRef']) ? $referencia['CodRef'] : null;
             $DteReferencia->razon = !empty($referencia['RazonRef']) ? $referencia['RazonRef'] : null;
             $DteReferencia->save();
         }
     }
     // eliminar DTE temporal
     $DteTmp->delete();
     // enviar DTE al SII y redireccionar a página del DTE
     $track_id = $EnvioDte->enviar();
     if ($track_id) {
         $DteEmitido->track_id = $track_id;
         \sowerphp\core\Model_Datasource_Session::message('Documento emitido y envíado al SII, ahora debe verificar estado del envío. TrackID: ' . $track_id, 'ok');
     } else {
         \sowerphp\core\Model_Datasource_Session::message('Documento emitido, pero no pudo ser envíado al SII, debe reenviar.<br/>' . implode('<br/>', \sasco\LibreDTE\Log::readAll()), 'warning');
     }
     $DteEmitido->save();
     $this->redirect('/dte/dte_emitidos/ver/' . $r['TpoDoc'] . '/' . $r['NroDoc'] . '/' . (int) $Emisor->certificacion);
 }