facturacionelectronicapy-xmlgen
Version:
API Node JS para generar el archivo XML del Documento electrónico exigido por SIFEN en base a JSON
789 lines (786 loc) • 93.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const xml2js = __importStar(require("xml2js"));
const StringUtil_service_1 = __importDefault(require("./StringUtil.service"));
const FechaUtil_service_1 = __importDefault(require("./FechaUtil.service"));
const Constante_service_1 = __importDefault(require("./Constante.service"));
const jsonDteItem_service_1 = __importDefault(require("./jsonDteItem.service"));
const jsonDteAlgoritmos_service_1 = __importDefault(require("./jsonDteAlgoritmos.service"));
const jsonDteComplementario_service_1 = __importDefault(require("./jsonDteComplementario.service"));
const jsonDteTransporte_service_1 = __importDefault(require("./jsonDteTransporte.service"));
const jsonDteTotales_service_1 = __importDefault(require("./jsonDteTotales.service"));
const jsonDteComplementariosComerciales_service_1 = __importDefault(require("./jsonDteComplementariosComerciales.service"));
const jsonDteIdentificacionDocumento_service_1 = __importDefault(require("./jsonDteIdentificacionDocumento.service"));
class JSonDteMainService {
constructor() {
this.codigoSeguridad = null;
this.codigoControl = null;
this.json = {};
}
generateXML(params, data) {
return new Promise((resolve, reject) => {
try {
resolve(this.generateXMLService(params, data));
}
catch (error) {
reject(error);
}
});
}
/**
* Metodo principal de generacion de XML
* @param params
* @param data
* @returns
*/
generateXMLService(params, data) {
this.validateValues(data);
this.addDefaultValues(data);
this.json = {};
this.generateCodigoSeguridad(params, data); //Primero genera el codigo de seguridad aleatorio único
this.generateCodigoControl(params, data); //Luego genera el código de Control
this.generateRte(params);
this.json['rDE']['DE'] = this.generateDe(params, data);
//---
this.generateDatosOperacion(params, data);
this.generateDatosTimbrado(params, data);
this.generateDatosGenerales(params, data);
//---
this.generateDatosEspecificosPorTipoDE(params, data);
this.generateDatosCondicionOperacionDE(params, data);
//['gDtipDE']=E001
this.json['rDE']['DE']['gDtipDE']['gCamItem'] = jsonDteItem_service_1.default.generateDatosItemsOperacion(params, data);
this.json['rDE']['DE']['gDtipDE']['gCamEsp'] = jsonDteComplementario_service_1.default.generateDatosComplementariosComercialesDeUsoEspecificos(params, data);
if (data['tipoDocumento'] == 1 || data['tipoDocumento'] == 7) {
//1 Opcional, 7 Obligatorio
this.json['rDE']['DE']['gDtipDE']['gTransp'] = jsonDteTransporte_service_1.default.generateDatosTransporte(params, data);
}
if (data['tipoDocumento'] != 7) {
const items = this.json['rDE']['DE']['gDtipDE']['gCamItem'];
this.json['rDE']['DE']['gTotSub'] = jsonDteTotales_service_1.default.generateDatosTotales(params, data, items);
}
if (data['complementarios']) {
this.json['rDE']['DE']['gCamGen'] = jsonDteComplementariosComerciales_service_1.default.generateDatosComercialesUsoGeneral(params, data);
}
if (data['tipoDocumento'] == 1 || data['tipoDocumento'] == 4 || data['tipoDocumento'] == 5 || data['tipoDocumento'] == 6 || data['tipoDocumento'] == 7) {
//this.json['rDE']['DE']['gDtipDE']['gCamDEAsoc'] = jsonDteIdentificacionDocumento.generateDatosDocumentoAsociado(params, data);
if (data['documentoAsociado']) {
this.json['rDE']['DE']['gCamDEAsoc'] = jsonDteIdentificacionDocumento_service_1.default.generateDatosDocumentoAsociado(params, data);
}
}
var builder = new xml2js.Builder({ xmldec: {
version: '1.0',
encoding: 'UTF-8',
standalone: false
} });
var xml = builder.buildObject(this.json);
/*
validator.validateXML(xml, __dirname + '\\xsd\\siRecepDE_v150.xsd', function(err, result) {
//validator.validateXML(xml.split('\n').slice(1).join('\n'), __dirname + '\\xsd\\siRecepDE_v150.xsd', function(err, result) {
if (err) {
throw err;
}
});
*/
return this.normalizeXML(xml);
}
generateCodigoSeguridad(params, data) {
//this.codigoSeguridad = oThis.generateCodigoSeguridadAleatorio(params, data);
this.codigoSeguridad = StringUtil_service_1.default.leftZero(data.codigoSeguridadAleatorio, 9);
}
/**
* Genera el CDC para la Factura
* Corresponde al Id del DE
*
* @param params
* @param data
*/
generateCodigoControl(params, data) {
this.codigoControl = jsonDteAlgoritmos_service_1.default.generateCodigoControl(params, data, this.codigoSeguridad);
}
/**
* Valida los datos ingresados en el data del req.body
* @param data
*/
validateValues(data) {
}
/**
* Añade algunos valores por defecto al JSON de entrada, valido para
* todas las operaciones
* @param data
*/
addDefaultValues(data) {
if (Constante_service_1.default.tiposDocumentos.filter(um => um.codigo === data["tipoDocumento"]).length == 0) {
throw new Error("Tipo de Documento '" + data["tipoDocumento"]) + "' en data.tipoDocumento no válido. Valores: " + Constante_service_1.default.tiposDocumentos.map(a => a.codigo + '-' + a.descripcion);
}
data["tipoDocumentoDescripcion"] = Constante_service_1.default.tiposDocumentos.filter(td => td.codigo == data["tipoDocumento"])[0]['descripcion'];
}
generateRte(params) {
this.json = {
rDE: {
$: {
'xmlns': 'http://ekuatia.set.gov.py/sifen/xsd',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation': 'http://ekuatia.set.gov.py/sifen/xsd siRecepDE_v150.xsd'
},
'dVerFor': params.version
}
};
}
generateDe(params, data) {
if (params['ruc'].indexOf('-') == -1) {
throw new Error("RUC debe contener dígito verificador en params.ruc");
}
const rucEmisor = params['ruc'].split('-')[0];
const dvEmisor = params['ruc'].split('-')[1];
const id = this.codigoControl;
//const digitoVerificador = jsonDteAlgoritmos.calcularDigitoVerificador(rucEmisor, 11 );
if (!(params.fechaFirmaDigital && params.fechaFirmaDigital.length >= 10)) {
// throw new Error("Debe proveer la fecha de la firma digital en params.fechaFirmaDigital");
}
const fechaFirmaDigital = new Date(params.fechaFirmaDigital);
let digitoVerificadorString = this.codigoControl + "";
const jsonResult = {
$: {
'Id': id
},
dDVId: digitoVerificadorString.substring(digitoVerificadorString.length - 1, digitoVerificadorString.length),
//dFecFirma : fechaUtilService.convertToJSONFormat(fechaFirmaDigital), //Fecha de la Firma Digital
dFecFirma: FechaUtil_service_1.default.convertToJSONFormat(new Date()),
dSisFact: 1
};
return jsonResult;
}
/**
* Datos inerentes a la operacion
* <gOpeDE>
<iTipEmi>1</iTipEmi>
<dDesTipEmi>Normal</dDesTipEmi>
<dCodSeg>000000023</dCodSeg>
<dInfoEmi>1</dInfoEmi>
<dInfoFisc>Información de interés del Fisco respecto al DE</dInfoFisc>
</gOpeDE>
* @param params
* @param data
* @param options
*/
generateDatosOperacion(params, data) {
if (params['ruc'].indexOf('-') == -1) {
throw new Error("RUC debe contener dígito verificador en params.ruc");
}
const rucEmisor = params['ruc'].split('-')[0];
const dvEmisor = params['ruc'].split('-')[1];
const id = jsonDteAlgoritmos_service_1.default.generateCodigoControl(params, data, this.codigoSeguridad);
const digitoVerificador = jsonDteAlgoritmos_service_1.default.calcularDigitoVerificador(rucEmisor, 11);
const codigoSeguridadAleatorio = this.codigoSeguridad;
if (Constante_service_1.default.tiposEmisiones.filter(um => um.codigo === data["tipoEmision"]).length == 0) {
throw new Error("Tipo de Emisión '" + data["tipoEmision"] + "' en data.tipoEmision no válido. Valores: " + Constante_service_1.default.tiposEmisiones.map(a => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gOpeDE'] = {
iTipEmi: data['tipoEmision'],
dDesTipEmi: Constante_service_1.default.tiposEmisiones.filter(td => td.codigo == data["tipoEmision"])[0]['descripcion'],
dCodSeg: codigoSeguridadAleatorio,
dInfoEmi: data['observacion'],
dInfoFisc: data['descripcion'],
};
//Validar aqui "dInfoFisc"
if (data['tipoDocumento'] == 7) { //Nota de Remision
if (!(data['descripcion'] && data['descripcion'] != "")) {
throw new Error("Debe informar la Descripción para el Documento Electrónico");
}
}
}
/**
* Genera los datos del timbrado
*
* <gTimb>
<iTiDE>1</iTiDE>
<dDesTiDE>Factura electrónica</dDesTiDE>
<dNumTim>12345678</dNumTim>
<dEst>001</dEst>
<dPunExp>001</dPunExp>
<dNumDoc>1000050</dNumDoc>
<dSerieNum>AB</dSerieNum>
<dFeIniT>2019-08-13</dFeIniT>
</gTimb>
* @param params
* @param data
* @param options
*/
generateDatosTimbrado(params, data) {
this.json['rDE']['DE']['gTimb'] = {
iTiDE: data['tipoDocumento'],
dDesTiDE: data['tipoDocumentoDescripcion'],
dNumTim: params['timbradoNumero'],
dEst: StringUtil_service_1.default.leftZero(data['establecimiento'], 3),
dPunExp: StringUtil_service_1.default.leftZero(data['punto'], 3),
dNumDoc: StringUtil_service_1.default.leftZero(data['numero'], 7),
//dSerieNum : null,
dFeIniT: params['timbradoFecha'].substring(0, 10)
};
if (data['numeroSerie']) {
this.json['rDE']['DE']['gTimb']['dSerieNum'] = data['numeroSerie'];
}
}
/**
* Genera los campos generales, divide las actividades en diferentes metodos
*
* <gDatGralOpe>
<dFeEmiDE>2020-05-07T15:03:57</dFeEmiDE>
</gDatGralOpe>
*
* @param params
* @param data
* @param options
*/
generateDatosGenerales(params, data) {
this.json['rDE']['DE']['gDatGralOpe'] = {
dFeEmiDE: data['fecha']
};
this.generateDatosGeneralesInherentesOperacion(params, data);
this.generateDatosGeneralesEmisorDE(params, data);
this.generateDatosGeneralesResponsableGeneracionDE(params, data);
this.generateDatosGeneralesReceptorDE(params, data);
}
/**
* D1. Campos inherentes a la operación comercial (D010-D099)
* Pertenece al grupo de datos generales
*
* <gOpeCom>
<iTipTra>1</iTipTra>
<dDesTipTra>Venta de mercadería</dDesTipTra>
<iTImp>1</iTImp>
<dDesTImp>IVA</dDesTImp>
<cMoneOpe>PYG</cMoneOpe>
<dDesMoneOpe>Guarani</dDesMoneOpe>
</gOpeCom>
* @param params
* @param data
* @param options
*/
generateDatosGeneralesInherentesOperacion(params, data) {
if (data['tipoDocumento'] == 7) { //C002
return; //No informa si el tipo de documento es 7
}
if (Constante_service_1.default.tiposImpuestos.filter(um => um.codigo === data["tipoImpuesto"]).length == 0) {
throw new Error("Tipo de Impuesto '" + data["tipoImpuesto"]) + "' en data.tipoImpuesto no válido. Valores: " + Constante_service_1.default.tiposImpuestos.map(a => a.codigo + '-' + a.descripcion);
}
if (Constante_service_1.default.monedas.filter(um => um.codigo === data["moneda"]).length == 0) {
throw new Error("Moneda '" + data["moneda"]) + "' en data.moneda no válido. Valores: " + Constante_service_1.default.monedas.map(a => a.codigo + '-' + a.descripcion);
}
if (data["condicionAnticipo"]) {
if (Constante_service_1.default.globalPorItem.filter(um => um.codigo === data["condicionAnticipo"]).length == 0) {
throw new Error("Condición de Anticipo '" + data["condicionAnticipo"]) + "' en data.condicionAnticipo no válido. Valores: " + Constante_service_1.default.globalPorItem.map(a => a.codigo + '-Anticipo ' + a.descripcion);
}
}
if (Constante_service_1.default.tiposTransacciones.filter(um => um.codigo === data["tipoTransaccion"]).length == 0) {
throw new Error("Tipo de Transacción '" + data["tipoTransaccion"]) + "' en data.tipoTransaccion no válido. Valores: " + Constante_service_1.default.tiposTransacciones.map(a => a.codigo + '-' + a.descripcion);
}
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom'] = {
iTipTra: null,
dDesTipTra: null,
iTImp: data['tipoImpuesto'],
dDesTImp: Constante_service_1.default.tiposImpuestos.filter(ti => ti.codigo == data['tipoImpuesto'])[0]['descripcion'],
cMoneOpe: data['moneda'],
dDesMoneOpe: Constante_service_1.default.monedas.filter(m => m.codigo == data['moneda'])[0]['descripcion'],
};
if (data['tipoDocumento'] == 1 || data['tipoDocumento'] == 4) {
//Obligatorio informar iTipTra D011
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['iTipTra'] = data['tipoTransaccion'];
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['dDesTipTra'] = Constante_service_1.default.tiposTransacciones.filter(tt => tt.codigo == data['tipoTransaccion'])[0]['descripcion'];
}
if (data['moneda'] != 'PYG') {
if (!data['condicionTipoCambio']) {
throw new Error("Debe informar el tipo de Cambio en data.condicionTipoCambio");
}
//Obligatorio informar dCondTiCam D017
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['dCondTiCam'] = data['condicionTipoCambio'];
}
if (data['cambio'] == 1 && data['moneda'] != 'PYG') {
if (!(data['cambio'] && data['cambio'] > 0)) {
throw new Error("Debe informar el valor del Cambio en data.cambio");
}
//Obligatorio informar dCondTiCam D018
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['dTiCam'] = data['cambio'];
}
if (data['condicionAnticipo']) {
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['iCondAnt'] = data['condicionAnticipo'];
this.json['rDE']['DE']['gDatGralOpe']['gOpeCom']['dDesCondAnt'] = "Anticipo " + Constante_service_1.default.globalPorItem.filter(ca => ca.codigo == data['condicionAnticipo'])[0]['descripcion'];
}
}
/**
* D2. Campos que identifican al emisor del Documento Electrónico DE (D100-D129)
* Pertenece al grupo de datos generales
*
* @param params
* @param data
* @param options
*/
generateDatosGeneralesEmisorDE(params, data) {
if (!(params && params.establecimientos)) {
throw new Error("Debe proveer un Array con la información de los establecimientos en params");
}
//Validar si el establecimiento viene en params
let establecimiento = StringUtil_service_1.default.leftZero(data['establecimiento'], 3);
let punto = StringUtil_service_1.default.leftZero(data['punto'], 3);
if (params.establecimientos.filter((um) => um.codigo === establecimiento).length == 0) {
throw new Error("Establecimiento '" + establecimiento + "' no encontrado en params.establecimientos*.codigo. Valores: " + params.establecimientos.map((a) => a.codigo + '-' + a.denominacion));
}
if (params['ruc'].indexOf('-') == -1) {
throw new Error("RUC debe contener dígito verificador en params.ruc");
}
this.json['rDE']['DE']['gDatGralOpe']['gEmis'] = {
dRucEm: params['ruc'].split('-')[0],
dDVEmi: params['ruc'].split('-')[1],
iTipCont: params['tipoContribuyente'],
cTipReg: params['tipoRegimen'],
dNomEmi: params['razonSocial'],
dNomFanEmi: params['nombreFantasia'],
dDirEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['direccion'],
dNumCas: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['numeroCasa'],
dCompDir1: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['complementoDireccion1'],
dCompDir2: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['complementoDireccion2'],
cDepEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['departamento'],
dDesDepEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['departamentoDescripcion'],
cDisEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['distrito'],
dDesDisEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['distritoDescripcion'],
cCiuEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['ciudad'],
dDesCiuEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['ciudadDescripcion'],
dTelEmi: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['telefono'],
dEmailE: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['email'],
dDenSuc: params["establecimientos"].filter((e) => e.codigo === establecimiento)[0]['denominacion'],
};
if (params["actividadesEconomicas"] && params["actividadesEconomicas"].length > 0) {
this.json['rDE']['DE']['gDatGralOpe']['gEmis']['gActEco'] = [];
for (let i = 0; i < params["actividadesEconomicas"].length; i++) {
const actividadEconomica = params["actividadesEconomicas"][i];
const gActEco = {
cActEco: actividadEconomica.codigo,
dDesActEco: actividadEconomica.descripcion
};
this.json['rDE']['DE']['gDatGralOpe']['gEmis']['gActEco'].push(gActEco);
}
}
else {
throw new Error("Debe proveer el array de actividades económicas en params.actividadesEconomicas");
}
}
/**
* Datos generales del responsable de generacion del DE
*
* @param params
* @param data
* @param options
*/
generateDatosGeneralesResponsableGeneracionDE(params, data) {
this.json['rDE']['DE']['gDatGralOpe']['gEmis']['gRespDE'] = {
iTipIDRespDE: data['usuario']['documentoTipo'],
dDTipIDRespDE: Constante_service_1.default.tiposDocumentosIdentidades.filter(td => td.codigo === data['usuario']['documentoTipo'])[0]["descripcion"],
dNumIDRespDE: data['usuario']['documentoNumero'],
dNomRespDE: data['usuario']['nombre'],
dCarRespDE: data['usuario']['cargo']
};
}
/**
* Datos generales del receptor del documento electrónico
* Pertenece al grupo de datos generales
*
* <gDatRec>
<iNatRec>1</iNatRec>
<iTiOpe>1</iTiOpe>
<cPaisRec>PRY</cPaisRec>
<dDesPaisRe>Paraguay</dDesPaisRe>
<iTiContRec>2</iTiContRec>
<dRucRec>00000002</dRucRec>
<dDVRec>7</dDVRec>
<dNomRec>RECEPTOR DEL DOCUMENTO</dNomRec>
<dDirRec>CALLE 1 ENTRE CALLE 2 Y CALLE 3</dDirRec>
<dNumCasRec>123</dNumCasRec>
<cDepRec>1</cDepRec>
<dDesDepRec>CAPITAL</dDesDepRec>
<cDisRec>1</cDisRec>
<dDesDisRec>ASUNCION (DISTRITO)</dDesDisRec>
<cCiuRec>1</cCiuRec>
<dDesCiuRec>ASUNCION (DISTRITO)</dDesCiuRec>
<dTelRec>012123456</dTelRec>
<dCodCliente>AAA</dCodCliente>
</gDatRec>
*
* @param params
* @param data
* @param options
*/
generateDatosGeneralesReceptorDE(params, data) {
if (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) {
if (Constante_service_1.default.tiposDocumentosReceptor.filter((um) => um.codigo === data['cliente']['documentoTipo']).length == 0) {
throw new Error("Tipo de Documento '" + data['cliente']['documentoTipo'] + "' del Cliente en data.cliente.documentoTipo no encontrado. Valores: " + Constante_service_1.default.tiposDocumentosReceptor.map((a) => a.codigo + '-' + a.descripcion));
}
}
if (data['cliente']['ruc'].indexOf('-') == -1) {
throw new Error("RUC debe contener dígito verificador en data.cliente.ruc");
}
this.json['rDE']['DE']['gDatGralOpe']['gDatRec'] = {
iNatRec: data['cliente']['contribuyente'] ? 1 : 2,
iTiOpe: data['cliente']['tipoOperacion'],
cPaisRec: data['cliente']['pais'],
dDesPaisRe: data['cliente']['paisDescripcion'],
iTiContRec: data['cliente']['contribuyente'] ? data['cliente']['tipoContribuyente'] : null,
dRucRec: data['cliente']['contribuyente'] ? data['cliente']['ruc'].split('-')[0] : null,
dDVRec: data['cliente']['contribuyente'] ? data['cliente']['ruc'].split('-')[1] : null,
//iTipIDRec : (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['documentoTipo'] : null,
//dDTipIDRec : (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) ? constanteService.tiposDocumentosReceptor.filter(tdr => { tdr.codigo === data['cliente']['documentoTipo']})[0]["descripcion"] : null,
//dNumIDRec : null, //Sera Sobreescito D210
dNomRec: (data['cliente']['documentoTipo'] === 5) ? "Sin Nombre" : data['cliente']['razonSocial'],
dNomFanRec: (data['cliente']['documentoTipo'] === 5) ? null : data['cliente']['nombreFantasia'],
//dDirRec : (data['tipoDocumento'] === 7 || data['cliente']['tipoOperacion'] === 4) ? data['cliente']['direccion'] : null,
dNumCasRec: data['cliente']['direccion'] ? data['cliente']['numeroCasa'] : null,
cDepRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['departamento'] : null,
dDesDepRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['departamentoDescripcion'] : null,
cDisRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['distrito'] : null,
dDesDisRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['distritoDescripcion'] : null,
cCiuRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['ciudad'] : null,
dDesCiuRec: (data['cliente']['direccion'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['ciudadDescripcion'] : null,
};
if (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion']) {
//Obligatorio completar D210
if (data['cliente']['tipoOperacion'] != 4 && !data['cliente']['documentoNumero']) {
throw new Error("Debe informar el número de documento en data.cliente.documentoNumero");
}
//iTipIDRec : (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) ? data['cliente']['documentoTipo'] : null,
//dDTipIDRec : (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) ? constanteService.tiposDocumentosReceptor.filter(tdr => { tdr.codigo === data['cliente']['documentoTipo']})[0]["descripcion"] : null,
//dNumIDRec : null, //Sera Sobreescito D210
if (!data['cliente']['contribuyente'] && data['cliente']['tipoOperacion'] != 4) {
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['iTipIDRec'] = data['cliente']['documentoTipo'];
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dDTipIDRec'] = Constante_service_1.default.tiposDocumentosReceptor.filter(tdr => { tdr.codigo === data['cliente']['documentoTipo']; })[0]["descripcion"];
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dNumIDRec'] = data['cliente']['documentoNumero'];
}
if (data['cliente']['documentoTipo'] = 5) {
//Si es innominado completar con cero
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dNumIDRec'] = "0";
}
}
if (data['tipoDocumento'] === 7 || data['cliente']['tipoOperacion'] === 4) {
if (data['cliente']['direccion']) {
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dDirRec'] = data['cliente']['direccion'];
}
}
//Asignar null a departamento, distrito y ciudad si tipoOperacion = 4
if (data['cliente']['tipoOperacion'] === 4) {
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['cDepRec'] = null;
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dDesDepRec'] = null;
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['cDisRec'] = null;
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dDesDisRec'] = null;
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['cCiuRec'] = null;
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dDesCiuRec'] = null;
}
if (data['cliente']['telefono'] && data['cliente']['telefono'].lenght >= 6) {
dTelRec: data['cliente']['telefono'];
}
if (data['cliente']['celular'] && data['cliente']['telefono'].lenght >= 10) {
dCelRec: data['cliente']['celular'];
}
if (data['cliente']['email']) {
dEmailRec: data['cliente']['email'];
}
if (data['cliente']['codigo']) {
this.json['rDE']['DE']['gDatGralOpe']['gDatRec']['dCodCliente'] = data['cliente']['codigo'];
}
}
/**
* Campos que seran especificos de acuerdo a cada tipo de documento electronico
* Se dividiran en diferentes métodos por cada tipo de factura.
*
* @param params
* @param data
* @param options
*/
generateDatosEspecificosPorTipoDE(params, data) {
this.json['rDE']['DE']['gDtipDE'] = {};
if (data["tipoDocumento"] === 1) {
this.generateDatosEspecificosPorTipoDE_FacturaElectronica(params, data);
}
if (data["tipoDocumento"] === 4) {
this.generateDatosEspecificosPorTipoDE_Autofactura(params, data);
}
if (data["tipoDocumento"] === 5 || data["tipoDocumento"] === 6) {
this.generateDatosEspecificosPorTipoDE_NotaCreditoDebito(params, data);
}
if (data["tipoDocumento"] === 7) {
this.generateDatosEspecificosPorTipoDE_RemisionElectronica(params, data);
}
}
/**
* Datos especificos para la factura electronica
*
* @param params
* @param data
* @param options
*/
generateDatosEspecificosPorTipoDE_FacturaElectronica(params, data) {
if (Constante_service_1.default.indicadoresPresencias.filter((um) => um.codigo === data['factura']['presencia']).length == 0) {
throw new Error("Indicador de Presencia '" + data['factura']['presencia'] + "' en data.factura.presencia no encontrado. Valores: " + Constante_service_1.default.indicadoresPresencias.map((a) => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gDtipDE']['gCamFE'] = {
iIndPres: data['factura']['presencia'],
dDesIndPres: Constante_service_1.default.indicadoresPresencias.filter(ip => ip.codigo === data['factura']['presencia'])[0]['descripcion'],
};
if (data['factura']['fechaEnvio']) {
this.json['rDE']['DE']['gDtipDE']['gCamFE']['dFecEmNR'] = data['factura']['fechaEnvio'];
}
if (data["cliente"]["tipoOperacion"] === 3) {
this.generateDatosEspecificosPorTipoDE_ComprasPublicas(params, data);
}
}
/**
* Datos especificos cuando el tipo de operacion del receptor es B2G (Campo D202)
* Dentro de la factura electronica
*
* @param params
* @param data
* @param options
*/
generateDatosEspecificosPorTipoDE_ComprasPublicas(params, data) {
if (!(data['dncp'] && data['dncp']['modalidad'] && data['dncp']['modalidad'].lenght > 0)) {
throw new Error("Debe informar la modalidad de Contratación DNCP en data.dncp.modalidad");
}
if (!(data['dncp'] && data['dncp']['entidad'] && data['dncp']['entidad'].lenght > 0)) {
throw new Error("Debe informar la entidad de Contratación DNCP en data.dncp.entidad");
}
if (!(data['dncp'] && data['dncp']['año'] && data['dncp']['año'].lenght > 0)) {
throw new Error("Debe informar la año de Contratación DNCP en data.dncp.año");
}
if (!(data['dncp'] && data['dncp']['secuencia'] && data['dncp']['secuencia'].lenght > 0)) {
throw new Error("Debe informar la secuencia de Contratación DNCP en data.dncp.secuencia");
}
if (!(data['dncp'] && data['dncp']['fecha'] && data['dncp']['fecha'].lenght > 0)) {
throw new Error("Debe informar la fecha de emisión de código de Contratación DNCP en data.dncp.fecha");
}
this.json['rDE']['DE']['gDtipDE']['gCamFE']['gCompPub'] = {
dModCont: data['dncp']['modalidad'],
dEntCont: data['dncp']['entidad'],
dAnoCont: data['dncp']['año'],
dSecCont: data['dncp']['secuencia'],
dFeCodCont: data['dncp']['fecha']
};
}
generateDatosEspecificosPorTipoDE_Autofactura(params, data) {
if (Constante_service_1.default.naturalezaVendedorAutofactura.filter((um) => um.codigo === data['autoFactura']['tipoVendedor']).length == 0) {
throw new Error("Tipo de Vendedor '" + data['autoFactura']['tipoVendedor'] + "' en data.autoFactura.tipoVendedor no encontrado. Valores: " + Constante_service_1.default.naturalezaVendedorAutofactura.map((a) => a.codigo + '-' + a.descripcion));
}
if (Constante_service_1.default.tiposDocumentosIdentidades.filter((um) => um.codigo === data['autoFactura']['documentoTipo']).length == 0) {
throw new Error("Tipoo de Documento '" + data['autoFactura']['documentoTipo'] + "' en data.autoFactura.documentoTipo no encontrado. Valores: " + Constante_service_1.default.tiposDocumentosIdentidades.map((a) => a.codigo + '-' + a.descripcion));
}
if (!data['autoFactura']['ubicacion']) {
throw new Error("Debe especificar la ubicación de la transacción en data.autoFactura.ubicacion");
}
console.log(data['autoFactura']['ubicacion']);
this.json['rDE']['DE']['gDtipDE']['gCamAE'] = {
iNatVen: data['autoFactura']['tipoVendedor'],
dDesNatVen: Constante_service_1.default.naturalezaVendedorAutofactura.filter(nv => nv.codigo === data['autoFactura']['tipoVendedor'])[0]['descripcion'],
iTipIDVen: data['autoFactura']['documentoTipo'],
dDTipIDVen: Constante_service_1.default.tiposDocumentosIdentidades.filter(td => td.codigo === data['autoFactura']['documentoTipo'])[0]['descripcion'],
dNumIDVen: data['autoFactura']['documentoNumero'],
dNomVen: data['autoFactura']['nombre'],
dDirVen: data['autoFactura']['direccion'],
dNumCasVen: data['autoFactura']['numeroCasa'],
cDepVen: data['autoFactura']['departamento'],
dDesDepVen: data['autoFactura']['departamentoDescripcion'],
cDisVen: data['autoFactura']['distrito'],
dDesDisVen: data['autoFactura']['distritoDescripcion'],
cCiuVen: data['autoFactura']['ciudad'],
dDesCiuVen: data['autoFactura']['ciudadDescripcion'],
dDirProv: data['autoFactura']['ubicacion']['lugar'],
cDepProv: data['autoFactura']['ubicacion']['departamento'],
dDesDepProv: data['autoFactura']['ubicacion']['departamentoDescripcion'],
cDisProv: data['autoFactura']['ubicacion']['distrito'],
dDesDisProv: data['autoFactura']['ubicacion']['distritoDescripcion'],
cCiuProv: data['autoFactura']['ubicacion']['ciudad'],
dDesCiuProv: data['autoFactura']['ubicacion']['ciudadDescripcion'],
};
}
generateDatosEspecificosPorTipoDE_NotaCreditoDebito(params, data) {
if (!data['notaCreditoDebito']['motivo']) {
throw new Error("Debe completar el motivo para la nota de crédito/débito en data.notaCreditoDebito.motivo");
}
if (params.notasCreditosMotivos.filter((um) => um.codigo === data['notaCreditoDebito']['motivo']).length == 0) {
throw new Error("Motivo de la Nota de Crédito/Débito '" + data['notaCreditoDebito']['motivo'] + "' en data.notaCreditoDebito.motivo no encontrado. Valores: " + params.notasCreditosMotivos.map((a) => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gDtipDE']['gCamNCDE'] = {
iMotEmi: data['notaCreditoDebito']['motivo'],
dDesMotEmi: Constante_service_1.default.notasCreditosMotivos.filter(nv => nv.codigo === data['notaCreditoDebito']['motivo'])[0]['descripcion'],
};
}
generateDatosEspecificosPorTipoDE_RemisionElectronica(params, data) {
if (params.remisionesMotivos.filter((um) => um.codigo === data['remision']['motivo']).length == 0) {
throw new Error("Motivo de la Remisión '" + data['remision']['motivo'] + "' en data.remision.motivo no encontrado. Valores: " + params.remisionesMotivos.map((a) => a.codigo + '-' + a.descripcion));
}
if (params.remisionesResponsables.filter((um) => um.codigo === data['remision']['remisionesResponsables']).length == 0) {
throw new Error("Tipo de Documento '" + data['remision']['remisionesResponsables'] + "' en data.remision.remisionesResponsables no encontrado. Valores: " + params.remisionesResponsables.map((a) => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gDtipDE']['gCamNRE'] = {
iMotEmiNR: data['remision']['motivo'],
dDesMotEmiNR: Constante_service_1.default.remisionesMotivos.filter(nv => nv.codigo === data['remision']['motivo'])[0]['descripcion'],
iRespEmiNR: data['remision']['remisionesResponsables'],
dDesRespEmiNR: Constante_service_1.default.remisionesResponsables.filter(nv => nv.codigo === data['remision']['remisionesResponsables'])[0]['descripcion'],
dKmR: data['remision']['kms'],
dFecEm: data['remision']['fechaFactura']
};
}
/**
* E7. Campos que describen la condición de la operación (E600-E699)
* @param params
* @param data
* @param options
*/
generateDatosCondicionOperacionDE(params, data) {
if (Constante_service_1.default.condicionesOperaciones.filter((um) => um.codigo === data['condicion']['tipo']).length == 0) {
throw new Error("Condición de la Operación '" + data['condicion']['tipo'] + "' en data.condicion.tipo no encontrado. Valores: " + Constante_service_1.default.condicionesOperaciones.map((a) => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gDtipDE']['gCamCond'] = {
iCondOpe: data['condicion']['tipo'],
dDCondOpe: Constante_service_1.default.condicionesOperaciones.filter(co => co.codigo === data['condicion']['tipo'])[0]['descripcion'],
};
//if (data['condicion']['tipo'] === 1) {
this.generateDatosCondicionOperacionDE_Contado(params, data);
//}
if (data['condicion']['tipo'] === 2) {
this.generateDatosCondicionOperacionDE_Credito(params, data);
}
}
/**
* E7.1. Campos que describen la forma de pago de la operación al contado o del monto
* de la entrega inicial (E605-E619)
* @param params
* @param data
* @param options
*/
generateDatosCondicionOperacionDE_Contado(params, data) {
if (data['condicion']['entregas'] && data['condicion']['entregas'].length > 0) {
const entregas = [];
for (let i = 0; i < data['condicion']['entregas'].length; i++) {
const dataEntrega = data['condicion']['entregas'][i];
if (Constante_service_1.default.condicionesTiposPagos.filter((um) => um.codigo === dataEntrega['tipo']).length == 0) {
throw new Error("Condición de Tipo de Pago '" + dataEntrega['tipo'] + "' en data.condicion.entregas[" + i + "].tipo no encontrado. Valores: " + Constante_service_1.default.condicionesTiposPagos.map((a) => a.codigo + '-' + a.descripcion));
}
const cuotaInicialEntrega = {
iTiPago: dataEntrega['tipo'],
dDesTiPag: Constante_service_1.default.condicionesTiposPagos.filter(co => co.codigo === dataEntrega['tipo'])[0]['descripcion'],
dMonTiPag: dataEntrega['monto'],
cMoneTiPag: dataEntrega['moneda'],
dDMoneTiPag: dataEntrega['monedaDescripcion'],
};
if (dataEntrega['moneda'] != 'PYG') {
if (dataEntrega['cambio']) {
cuotaInicialEntrega['dTiCamTiPag'] = dataEntrega['cambio'];
}
}
//Verificar si el Pago es con Tarjeta de crédito
if (dataEntrega['tipo'] === 3 || dataEntrega['tipo'] === 4) {
if (Constante_service_1.default.condicionesOperaciones.filter((um) => um.codigo === dataEntrega['infoTarjeta']["tipo"]).length == 0) {
throw new Error("Tipo de Tarjeta de Crédito '" + dataEntrega['infoTarjeta']["tipo"] + "' en data.condicion.entregas[" + i + "].infoTarjeta.tipo no encontrado. Valores: " + Constante_service_1.default.condicionesOperaciones.map((a) => a.codigo + '-' + a.descripcion));
}
if (dataEntrega['infoTarjeta']["ruc"].indexOf("-") == -1) {
throw new Error("Ruc de Proveedor de Tarjeta debe contener digito verificador en data.condicion.entregas[" + i + "].infoTarjeta.ruc");
}
cuotaInicialEntrega['gPagTarCD'] = {
iDenTarj: dataEntrega['infoTarjeta']["tipo"],
dDesDenTarj: dataEntrega['infoTarjeta']["tipo"] === 99 ? dataEntrega['infoTarjeta']["tipoDescripcion"] : Constante_service_1.default.tarjetasCreditosTipos.filter(co => co.codigo === dataEntrega['infoTarjeta']['tipo'])[0]['descripcion'],
dRSProTar: dataEntrega['infoTarjeta']["razonSocial"],
dRUCProTar: dataEntrega['infoTarjeta']["ruc"].split("-")[0],
dDVProTar: dataEntrega['infoTarjeta']["ruc"].split("-")[1],
iForProPa: dataEntrega['infoTarjeta']["medioPago"],
dCodAuOpe: dataEntrega['infoTarjeta']["codigoAutorizacion"],
dNomTit: dataEntrega['infoTarjeta']["titular"],
dNumTarj: dataEntrega['infoTarjeta']["numero"]
};
}
//Verificar si el Pago es con Cheque
if (dataEntrega['tipo'] === 2) {
cuotaInicialEntrega['gPagCheq'] = {
dNumCheq: StringUtil_service_1.default.leftZero(dataEntrega['infoCheque']["numeroCheque"], 8),
dBcoEmi: dataEntrega['infoCheque']["banco"],
};
}
entregas.push(cuotaInicialEntrega);
}
this.json['rDE']['DE']['gDtipDE']['gCamCond']['gPaConEIni'] = entregas; //Array de Entregas
}
}
/**
* E7.2. Campos que describen la operación a crédito (E640-E649)
*
* @param params
* @param data
* @param options
*/
generateDatosCondicionOperacionDE_Credito(params, data) {
if (Constante_service_1.default.condicionesCreditosTipos.filter((um) => um.codigo === data['condicion']['credito']['tipo']).length == 0) {
throw new Error("Tipo de Crédito '" + data['condicion']['credito']['tipo'] + "' en data.condicion.credito.tipo no encontrado. Valores: " + Constante_service_1.default.condicionesCreditosTipos.map((a) => a.codigo + '-' + a.descripcion));
}
this.json['rDE']['DE']['gDtipDE']['gCamCond']['gPagCred'] = {
iCondCred: data['condicion']['credito']['tipo'],
dDCondCred: Constante_service_1.default.condicionesCreditosTipos.filter(co => co.codigo === data['condicion']['credito']['tipo'])[0]['descripcion'],
dPlazoCre: data['condicion']['credito']['tipo'] === 1 ? data['condicion']['credito']['plazo'] : null,
//dCuotas : data['condicion']['credito']['tipo'] === 2 ? data['condicion']['credito']['cuotas'] : null,
dMonEnt: data['condicion']['credito']['montoEntrega'],
gCuotas: []
};
if (data['condicion']['credito']['tipo'] === 2) {
if (data['condicion']['credito']['cuotas']) {
this.json['rDE']['DE']['gDtipDE']['gCamCond']['gPagCred']['dCuotas'] = data['condicion']['credito']['cuotas'];
}
}
//Recorrer array de infoCuotas e informar en el JSON
if (data['condicion']['credito']['tipo'] === 2) { //A Cuotas
if (data['condicion']['credito']['infoCuotas'] && data['condicion']['credito']['infoCuotas'].length > 0) {
for (let i = 0; i < data['condicion']['credito']['infoCuotas'].length; i++) {
const infoCuota = data['condicion']['credito']['infoCuotas'][i];
const gCuotas = {
cMoneCuo: infoCuota['moneda'],
dDMoneCuo: infoCuota['monedaDescripcion'],
dMonCuota: infoCuota['monto'],
dVencCuo: infoCuota['vencimiento'],
};
this.json['rDE']['DE']['gDtipDE']['gCamCond']['gPagCred']['gCuotas'].push(gCuotas);
}
}
else {
throw new Error("Debe proporcionar data.condicion.credito.infoCuotas[]");
}
}
}
normalizeXML(xml) {
xml = xml.split('\r\n').join('');
xml = xml.split('\n').join('');
xml = xml.split('\t').join('');
xml = xml.split(' ').join('');
xml = xml.split('> <').join('><');
xml = xml.split('> <').join('><');
xml = xml.replace(/\r?\n|\r/g, '');
return xml;
}
}
exports.default = new JSonDteMainService();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbkR0ZU1haW4uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9qc29uRHRlTWFpbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtDQUFpQztBQUVqQyw4RUFBcUQ7QUFDckQsNEVBQW1EO0FBQ25ELDRFQUFtRDtBQUNuRCxnRkFBZ0Q7QUFDaEQsNEZBQTREO0FBQzVELG9HQUFxRTtBQUNyRSw0RkFBNEQ7QUFDNUQsc0ZBQXNEO0FBQ3RELDRIQUF5RjtBQUN6RixzSEFBc0Y7QUFHdEYsTUFBTSxrQkFBa0I7SUFBeEI7UUFDSSxvQkFBZSxHQUFTLElBQUksQ0FBQztRQUM3QixrQkFBYSxHQUFTLElBQUksQ0FBQztRQUMzQixTQUFJLEdBQVMsRUFBRSxDQUFDO0lBczJCcEIsQ0FBQztJQXAyQlUsV0FBVyxDQUFDLE1BQVcsRUFBRSxJQUFTO1FBQ3JDLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDbkMsSUFBSTtnQkFDQSxPQUFPLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ2xEO1lBQUMsT0FBTyxLQUFLLEVBQUU7Z0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ2pCO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSyxrQkFBa0IsQ0FBQyxNQUFXLEVBQUUsSUFBUztRQUU3QyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU1QixJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUVmLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUMs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