/** * 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); }