/** * 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; } } }
* SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO. * Consulte los detalles de la Licencia Pública General GNU para obtener * una información más detallada. * * Debería haber recibido una copia de la Licencia Pública General GNU * junto a este programa. * En caso contrario, consulte <http://www.gnu.org/licenses/gpl.html>. */ /** * @file 007-folios.php * * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-09-16 */ // respuesta en texto plano header('Content-type: text/plain'); // incluir archivos php de la biblioteca y configuraciones include 'inc.php'; // cargar folios $Folios = new \sasco\LibreDTE\Sii\Folios(file_get_contents('xml/folios.xml')); // ejemplos métodos echo 'Folios son validos?: ', $Folios->check() ? 'si' : 'no', "\n\n"; echo 'Rango de folios: ', $Folios->getDesde(), ' al ', $Folios->getHasta(), "\n\n"; echo 'CAF: ', $Folios->getCaf()->C14N(), "\n\n"; echo $Folios->getPrivateKey(), "\n"; echo $Folios->getPublicKey(); // si hubo errores mostrar foreach (\sasco\LibreDTE\Log::readAll() as $error) { echo $error, "\n"; }
/** * 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]); }
/** * Método que entrega el CAF de un folio de cierto DTE * @param dte Tipo de documento para el cual se quiere su CAF * @param folio Folio del CAF del DTE que se busca * @return \sasco\LibreDTE\Sii\Folios * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-09-22 */ private function getCaf($dte, $folio) { $caf = $this->db->getValue(' SELECT xml FROM dte_caf WHERE emisor = :rut AND dte = :dte AND certificacion = :certificacion AND :folio BETWEEN desde AND hasta ', [':rut' => $this->rut, ':dte' => $dte, ':certificacion' => (int) $this->certificacion, ':folio' => $folio]); if (!$caf) { return false; } $caf = Utility_Data::decrypt($caf); if (!$caf) { return false; } $Caf = new \sasco\LibreDTE\Sii\Folios($caf); return $Caf->getTipo() ? $Caf : false; }