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
JavaScript
"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;