UNPKG

envio-comprobantes-sri

Version:

Envia comprobantes electronicos al SRI (Ecuador). Recibe un objeto JSON. Lo convierte a XML, lo firma, lo envía al servicio web del SRI y devuelve la respuesta.

204 lines (203 loc) 11.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TablaImpuesto = exports.TablaTipoIdentificacion = exports.TablaPorcentajeIVA = exports.TablaFormasPago = exports.TablaCodigoDocumento = exports.InfoNotaCredito = exports.InfoFactura = exports.EnvioComprobantesSRI = exports.WebServiceSRIError = exports.DocumentContentError = exports.CertificateRelatedError = exports.EnvioComprobantesSRIError = void 0; require("reflect-metadata"); const Comprobante_to_XML_1 = require("./Comprobante-to-XML"); Object.defineProperty(exports, "DocumentContentError", { enumerable: true, get: function () { return Comprobante_to_XML_1.DocumentContentError; } }); const Factura_1 = require("./Structures/Factura"); Object.defineProperty(exports, "InfoFactura", { enumerable: true, get: function () { return Factura_1.InfoFactura; } }); const NotaCredito_1 = require("./Structures/NotaCredito"); Object.defineProperty(exports, "InfoNotaCredito", { enumerable: true, get: function () { return NotaCredito_1.InfoNotaCredito; } }); const Firmar_Comprobante_XML_1 = require("./Firmar-Comprobante-XML"); const EnvioAKARecepcion_SRI_1 = require("./EnvioAKARecepcion-SRI"); const AutorizacionXMLEnviado_SRI_1 = require("./AutorizacionXMLEnviado-SRI"); const TablasSRI_1 = require("./Structures/Utils/TablasSRI"); Object.defineProperty(exports, "TablaCodigoDocumento", { enumerable: true, get: function () { return TablasSRI_1.TablaCodigoDocumento; } }); Object.defineProperty(exports, "TablaFormasPago", { enumerable: true, get: function () { return TablasSRI_1.TablaFormasPago; } }); Object.defineProperty(exports, "TablaPorcentajeIVA", { enumerable: true, get: function () { return TablasSRI_1.TablaPorcentajeIVA; } }); Object.defineProperty(exports, "TablaTipoIdentificacion", { enumerable: true, get: function () { return TablasSRI_1.TablaTipoIdentificacion; } }); Object.defineProperty(exports, "TablaImpuesto", { enumerable: true, get: function () { return TablasSRI_1.TablaImpuesto; } }); const Cert2p12_1 = __importDefault(require("./Utils/Cert2p12")); const Certp12Info_1 = __importDefault(require("./Utils/Certp12Info")); const CertificateRelatedError_1 = __importDefault(require("./Utils/CertificateRelatedError")); exports.CertificateRelatedError = CertificateRelatedError_1.default; const EnvioComprobantesSRIError_1 = __importDefault(require("./Utils/EnvioComprobantesSRIError")); exports.EnvioComprobantesSRIError = EnvioComprobantesSRIError_1.default; const class_transformer_1 = require("class-transformer"); const ComprobanteBase_1 = require("./Structures/ComprobanteBase"); const parseWebServiceResponse_1 = require("./Utils/parseWebServiceResponse"); Object.defineProperty(exports, "WebServiceSRIError", { enumerable: true, get: function () { return parseWebServiceResponse_1.WebServiceSRIError; } }); const fs_1 = require("fs"); const path_1 = require("path"); class EnvioComprobantesSRI { contribuyente_data; p12Cert; _certInfo; CertInfo() { return { ...this._certInfo // , esPersonaJuridica: this._certInfo.organizationSerialNumber !== `${this._certInfo.subjectSerialNumber}001` , razonSocialDiferente: this._certInfo.organizationName !== this.contribuyente_data.razonSocial }; } ContribuyenteData() { return { ...this.contribuyente_data }; } constructor(cert, contribuyente_data) { this.contribuyente_data = contribuyente_data; this.p12Cert = (0, Cert2p12_1.default)(cert); this._certInfo = (0, Certp12Info_1.default)(this.p12Cert); var now = new Date().valueOf(); const c = this._certInfo; if (c.validFrom.valueOf() > now) throw new CertificateRelatedError_1.default("cert_not_valid_yet", c.validFrom); if (c.validTo.valueOf() < now) throw new CertificateRelatedError_1.default("cert_expired", c.validTo); if (!/^\d{12}1$/g.test(contribuyente_data.ruc)) { throw new CertificateRelatedError_1.default("ruc_mismatch", [contribuyente_data.ruc, contribuyente_data.ruc]); } // hay casos en que el RUC no coincide totalmente, por alguna razon. En estos casos igual se puede generar. // en algunos casos de Security Data a veces no se utiliza `organizationSerialNumber` if (c.organizationSerialNumber && !c.organizationSerialNumber.includes(contribuyente_data.ruc)) throw new CertificateRelatedError_1.default("ruc_mismatch", [`${c.organizationSerialNumber} ${c.organizationName}`, contribuyente_data.ruc]); } add_contribuyente_data(data) { /** * Convierto a la clase InfoTributaria (para depurar solo las propiedades de `infoTributaria`) * Luego convierto a JSON nuevamente (para solo tener las propiedades que no estan en `undefined`) * Actualizo `data` */ Object.assign(data.infoTributaria, (0, class_transformer_1.instanceToPlain)((0, class_transformer_1.plainToClass)(ComprobanteBase_1.InfoTributaria, this.contribuyente_data, { excludeExtraneousValues: true }), { exposeUnsetFields: false })); var prop = ""; if ("infoFactura" in data) prop = "infoFactura"; if ("infoGuiaRemision" in data) prop = "infoGuiaRemision"; if ("infoNotaCredito" in data) prop = "infoNotaCredito"; if ("infoCompRetencion" in data) prop = "infoCompRetencion"; if ("infoLiquidacionCompra" in data) prop = "infoLiquidacionCompra"; /** * Los mismos pasos de arriba, pero para los datos en `infoFactura`, `infoNotaCredito`, ...etc */ if (data[prop]) Object.assign(data[prop], (0, class_transformer_1.instanceToPlain)((0, class_transformer_1.plainToClass)(ComprobanteBase_1.InfoComprobanteBase, this.contribuyente_data, { excludeExtraneousValues: true }), { exposeUnsetFields: false })); return data; } /** * Cuando un comprobante ya ha sido subido, solicita al SRI que dicho comprobante sea autorizado. * Este proceso se debe realizar si en "AutorizacionComprobanteSRI" ocurre un error y el proceso se detiente * despues del estado RECIBIDA. * @param clave_acceso * @param ambiente * @param signal */ async SolicitarAutorizacionEnComprobanteSubido(clave_acceso, ambiente, signal) { const autorizacion_response = await (0, AutorizacionXMLEnviado_SRI_1.AutorizacionXMLEnviado_SRI)(clave_acceso, signal, ambiente); return { fechaAutorizacion: new Date(autorizacion_response.fechaAutorizacion), ambiente: autorizacion_response.ambiente, document_status: autorizacion_response.estado, xml_approved_document: autorizacion_response.xml_received }; } async AutorizarComprobanteSRI(document_type, data, reportProgress, signal, time_between_sri_requests) { const resultSet = []; try { if (!time_between_sri_requests) time_between_sri_requests = 5000; const startup_time = new Date().valueOf(); let codDoc = null; if (document_type === "factura") codDoc = TablasSRI_1.TablaCodigoDocumento.FACTURA; if (document_type === "notaCredito") codDoc = TablasSRI_1.TablaCodigoDocumento.NOTA_CREDITO; if (codDoc === null) throw new RangeError(`Parametro 'document_type' deber puede ser 'factura', 'notaCredito', 'comprobanteRetencion' o 'guiaRemision'`); const input_raw_data = JSON.parse(JSON.stringify({ ...data })); input_raw_data.infoTributaria.codDoc = codDoc; const input = this.add_contribuyente_data(input_raw_data); switch (document_type) { case "factura": var xml = (0, Comprobante_to_XML_1.Factura_to_XML)(input); break; case "notaCredito": xml = (0, Comprobante_to_XML_1.NotaCredito_to_XML)(input); break; default: throw new RangeError(`Parametro 'document_type' deber puede ser 'factura', 'notaCredito', 'comprobanteRetencion' o 'guiaRemision'`); } reportProgress && reportProgress({ message: "Archivo XML generado", percentage: 0.25, document_status: "XML_CREADO", result: xml }); resultSet.push(xml); if (signal?.aborted) throw new Error("Process aborted"); (0, fs_1.writeFileSync)((0, path_1.join)(process.cwd(), "1.xml"), xml); const { comprobante_firmado } = await (0, Firmar_Comprobante_XML_1.FirmarComprobanteXML)(this.p12Cert, xml); reportProgress && reportProgress({ message: "Archivo XML firmado.", percentage: 0.5, document_status: "XML_FIRMADO", result: comprobante_firmado }); resultSet.push(comprobante_firmado); if (signal?.aborted) throw new Error("Process aborted"); (0, fs_1.writeFileSync)((0, path_1.join)(process.cwd(), "2.xml"), xml); const recepcion_response = await (0, EnvioAKARecepcion_SRI_1.EnvioAKARecepcion_SRI)(comprobante_firmado, signal, input.infoTributaria.ambiente); reportProgress && reportProgress({ message: "Envio/Recepción de documento al SRI completado.", percentage: 0.75, document_status: recepcion_response.estado, result: recepcion_response.xml_sent }); resultSet.push(recepcion_response.xml_sent); if (signal?.aborted) throw new Error("Process aborted"); (0, fs_1.writeFileSync)((0, path_1.join)(process.cwd(), "3.xml"), xml); if (parseInt(time_between_sri_requests.toString()) > 1) await new Promise(resolve => setTimeout(resolve, time_between_sri_requests)); const autorizacion_response = await (0, AutorizacionXMLEnviado_SRI_1.AutorizacionXMLEnviado_SRI)(data.infoTributaria.claveAcceso, signal, input.infoTributaria.ambiente); reportProgress && reportProgress({ message: "Documento autorizado correctamente.", percentage: 1, document_status: autorizacion_response.estado, result: autorizacion_response.xml_received }); (0, fs_1.writeFileSync)((0, path_1.join)(process.cwd(), "4.xml"), xml); resultSet.push(recepcion_response.xml_received); return { document: input, spent_time_ms: new Date().valueOf() - startup_time, fechaAutorizacion: new Date(autorizacion_response.fechaAutorizacion), ambiente: autorizacion_response.ambiente, document_status: autorizacion_response.estado, xml_approved_document: autorizacion_response.xml_received, xml_signed_document: comprobante_firmado }; } catch (ex) { const err = new EnvioComprobantesSRIError_1.default(document_type, ex, resultSet); throw err; } } } exports.EnvioComprobantesSRI = EnvioComprobantesSRI;