/** * Acción que permite subir un caf para un tipo de folio * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-09-22 */ public function subir_caf() { $Emisor = $this->getContribuyente(); $this->set(['Emisor' => $Emisor]); // procesar solo si se envió el formulario if (isset($_POST['submit'])) { // verificar que se haya podido subir CAF if (!isset($_FILES['caf']) or $_FILES['caf']['error']) { \sowerphp\core\Model_Datasource_Session::message('Ocurrió un error al subir el CAF', 'error'); return; } if (\sowerphp\general\Utility_File::mimetype($_FILES['caf']['tmp_name']) != 'application/xml') { \sowerphp\core\Model_Datasource_Session::message('Formato del archivo ' . $_FILES['caf']['name'] . ' es incorrecto', 'error'); return; } // cargar caf $caf = file_get_contents($_FILES['caf']['tmp_name']); $Folios = new \sasco\LibreDTE\Sii\Folios($caf); // si no se pudo validar el caf error if (!$Folios->getTipo()) { \sowerphp\core\Model_Datasource_Session::message('No fue posible cargar el CAF ' . $_FILES['caf']['name'] . ':<br/>' . implode('<br/>', \sasco\LibreDTE\Log::readAll()), 'error'); return; } // verificar que el caf tenga previamente cargado un mantenedor de folio $DteFolio = new Model_DteFolio($Emisor->rut, $Folios->getTipo(), (int) $Folios->getCertificacion()); if (!$DteFolio->exists()) { \sowerphp\core\Model_Datasource_Session::message('Primero debe crear el mantenedor de los folios de tipo ' . $Folios->getTipo(), 'error'); return; } // verificar que el caf sea del emisor if ($Folios->getEmisor() != $Emisor->rut . '-' . $Emisor->dv) { \sowerphp\core\Model_Datasource_Session::message('RUT del CAF ' . $Folios->getEmisor() . ' no corresponde con el RUT de la empresa ' . $Emisor->razon_social . ' ' . $Emisor->rut . '-' . $Emisor->dv, 'error'); return; } // verificar que el folio que se está subiendo sea para el ambiente actual de la empresa $ambiente_empresa = $Emisor->certificacion ? 'certificación' : 'producción'; $ambiente_caf = $Folios->getCertificacion() ? 'certificación' : 'producción'; if ($ambiente_empresa != $ambiente_caf) { \sowerphp\core\Model_Datasource_Session::message('Empresa está en ambiente de ' . $ambiente_empresa . ' pero folios son de ' . $ambiente_caf, 'error'); return; } // crear caf para el folio $DteCaf = new Model_DteCaf($DteFolio->emisor, $DteFolio->dte, (int) $Folios->getCertificacion(), $Folios->getDesde()); if ($DteCaf->exists()) { \sowerphp\core\Model_Datasource_Session::message('El CAF para el documento de tipo ' . $DteCaf->dte . ' que inicia en ' . $Folios->getDesde() . ' en ambiente de ' . $ambiente_caf . ' ya estaba cargado', 'warning'); return; } $DteCaf->hasta = $Folios->getHasta(); $DteCaf->xml = \website\Dte\Utility_Data::encrypt($caf); try { $DteCaf->save(); } catch (\sowerphp\core\Exception_Model_Datasource_Database $e) { \sowerphp\core\Model_Datasource_Session::message('No fue posible guardar el CAF: ' . $e->getMessage(), 'error'); return; } // actualizar mantenedor de folios if (!$DteFolio->disponibles) { $DteFolio->siguiente = $Folios->getDesde(); $DteFolio->disponibles = $Folios->getHasta() - $Folios->getDesde() + 1; } else { $DteFolio->disponibles += $Folios->getHasta() - $Folios->getDesde() + 1; } $DteFolio->alertado = 'f'; try { $DteFolio->save(); \sowerphp\core\Model_Datasource_Session::message('El CAF para el documento de tipo ' . $DteCaf->dte . ' que inicia en ' . $Folios->getDesde() . ' en ambiente de ' . $ambiente_caf . ' fue cargado, el siguiente folio disponible es ' . $DteFolio->siguiente, 'ok'); $this->redirect('/dte/admin/dte_folios'); } catch (\sowerphp\core\Exception_Model_Datasource_Database $e) { \sowerphp\core\Model_Datasource_Session::message('El CAF se guardó, pero no fue posible actualizar el mantenedor de folios, deberá actualizar manualmente. ' . $e->getMessage(), 'error'); return; } } }
/** * Recurso de la API que genera el XML de los DTEs solicitados * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-11-21 */ public function _api_generar_xml_POST() { // verificar si se pasaron credenciales de un usuario $User = $this->Api->getAuthUser(); if (is_string($User)) { $this->Api->send($User, 401); } // verificar que se hayan pasado los índices básicos foreach (['Emisor', 'Receptor', 'documentos', 'folios', 'firma'] as $key) { if (!isset($this->Api->data[$key])) { $this->Api->send('Falta índice/variable ' . $key . ' por POST', 500); } } // recuperar folios y definir ambiente $folios = []; $certificacion = false; foreach ($this->Api->data['folios'] as $folio) { $Folios = new \sasco\LibreDTE\Sii\Folios(base64_decode($folio)); $folios[$Folios->getTipo()] = $Folios; if ($Folios->getCertificacion()) { $certificacion = true; } } // normalizar datos emisor $this->Api->data['Emisor']['RUTEmisor'] = str_replace('.', '', $this->Api->data['Emisor']['RUTEmisor']); // normalizar datos receptor $this->Api->data['Receptor']['RUTRecep'] = str_replace('.', '', $this->Api->data['Receptor']['RUTRecep']); // objeto de la firma try { $Firma = new \sasco\LibreDTE\FirmaElectronica(['data' => base64_decode($this->Api->data['firma']['data']), 'pass' => $this->Api->data['firma']['pass']]); } catch (\Exception $e) { $this->Api->send('No fue posible abrir la firma digital, quizás contraseña incorrecta', 500); } // normalizar dte? $normalizar_dte = isset($this->Api->data['normalizar_dte']) ? $this->Api->data['normalizar_dte'] : true; // armar documentos y guardar en un arreglo $Documentos = []; foreach ($this->Api->data['documentos'] as $d) { // crear documento $d['Encabezado']['Emisor'] = $this->Api->data['Emisor']; $d['Encabezado']['Receptor'] = $this->Api->data['Receptor']; $DTE = new \sasco\LibreDTE\Sii\Dte($d, $normalizar_dte); // timbrar, firmar y validar el documento if (!isset($folios[$DTE->getTipo()])) { return $this->Api->send('Falta el CAF para el tipo de DTE ' . $DTE->getTipo(), 500); } if (!$DTE->timbrar($folios[$DTE->getTipo()]) or !$DTE->firmar($Firma) or !$DTE->schemaValidate()) { return $this->Api->send(implode("\n", \sasco\LibreDTE\Log::readAll()), 500); } // agregar el DTE al listado $Documentos[] = $DTE; } // armar EnvioDTE si se pasó fecha de resolución y número de resolución if (isset($this->Api->data['resolucion']) and !empty($this->Api->data['resolucion']['FchResol']) and isset($this->Api->data['resolucion']['NroResol'])) { $EnvioDte = new \sasco\LibreDTE\Sii\EnvioDte(); foreach ($Documentos as $DTE) { $EnvioDte->agregar($DTE); } $EnvioDte->setCaratula(['RutEnvia' => $Firma->getID(), 'RutReceptor' => $certificacion ? '60803000-K' : $this->Api->data['Receptor']['RUTRecep'], 'FchResol' => $this->Api->data['resolucion']['FchResol'], 'NroResol' => (int) $this->Api->data['resolucion']['NroResol']]); $EnvioDte->setFirma($Firma); // generar $xml = $EnvioDte->generar(); // validar schema del DTE if (!$EnvioDte->schemaValidate()) { return $this->Api->send(implode("\n", \sasco\LibreDTE\Log::readAll()), 500); } $dir = sys_get_temp_dir() . '/EnvioDTE_' . $this->Api->data['Emisor']['RUTEmisor'] . '_' . $this->Api->data['Receptor']['RUTRecep'] . '_' . date('U') . '.xml'; file_put_contents($dir, $xml); } else { // directorio temporal para guardar los XML $dir = sys_get_temp_dir() . '/DTE_' . $this->Api->data['Emisor']['RUTEmisor'] . '_' . $this->Api->data['Receptor']['RUTRecep'] . '_' . date('U'); if (is_dir($dir)) { \sasco\LibreDTE\File::rmdir($dir); } if (!mkdir($dir)) { $this->Api->send('No fue posible crear directorio temporal para DTEs', 500); } // procesar cada DTEs e ir agregándolo al directorio que se comprimirá foreach ($Documentos as $DTE) { // guardar XML file_put_contents($dir . '/dte_' . $this->Api->data['Emisor']['RUTEmisor'] . '_' . $DTE->getID() . '.xml', $DTE->saveXML()); } } // guardar datos de emisor, receptor y estadísticas if (isset($this->Api->data['resolucion'])) { $resolucion = []; if (!empty($this->Api->data['resolucion']['FchResol'])) { $resolucion['FchResol'] = $this->Api->data['resolucion']['FchResol']; } if (isset($this->Api->data['resolucion']['NroResol'])) { $resolucion['NroResol'] = $this->Api->data['resolucion']['NroResol']; } $this->guardarEmisor($this->Api->data['Emisor'], $resolucion); } else { $this->guardarEmisor($this->Api->data['Emisor']); } $this->guardarReceptor($this->Api->data['Receptor']); list($emisor, $dv) = explode('-', $this->Api->data['Emisor']['RUTEmisor']); list($receptor, $dv) = explode('-', $this->Api->data['Receptor']['RUTRecep']); // entregar archivo comprimido que incluirá cada uno de los DTEs \sasco\LibreDTE\File::compress($dir, ['format' => 'zip', 'delete' => true]); }