@ocelotlstudio/cfdi-pdf
Version:
Creates a pdf based on an XML CFDI
583 lines • 24.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
exports.__esModule = true;
exports.generatePdfContent = void 0;
var catalogs_1 = require("../catalogs");
var toCurrency_1 = require("../utils/toCurrency");
var helper_1 = require("../utils/helper");
var check_1 = require("../utils/check");
var generateImpuestos = function (concepto) {
var arr = [];
if (concepto.traslados.length > 0) {
arr.push('Traslados');
var content = concepto.traslados.map(function (traslado) {
return [
catalogs_1.impuestosCatalog[traslado.impuesto]
? traslado.impuesto + " - " + catalogs_1.impuestosCatalog[traslado.impuesto]
: '',
traslado.tipoFactor == 'Exento' ? 'EXENTO' : "" + helper_1.formatCurrency(traslado.importe),
];
});
arr.push({
table: {
body: content
},
layout: 'noBorders'
});
}
if (concepto.retenciones.length > 0) {
arr.push('Retenciones');
var content = concepto.retenciones.map(function (retencion) {
return [
catalogs_1.impuestosCatalog[retencion.impuesto]
? retencion.impuesto + " - " + catalogs_1.impuestosCatalog[retencion.impuesto]
: '',
"" + helper_1.formatCurrency(retencion.importe),
];
});
arr.push({
table: {
body: content
},
layout: 'noBorders'
});
}
return arr;
};
var generateConceptsTable = function (conceptos) {
var arr = conceptos.map(function (concepto) { return [
concepto.clave,
concepto.cantidad,
concepto.claveUnidad,
catalogs_1.clavesUnidadesCatalog[concepto.claveUnidad],
concepto.descripcion,
"" + helper_1.formatCurrency(concepto.valorUnitario),
"" + helper_1.formatCurrency(concepto.descuento),
{
colSpan: 2,
stack: generateImpuestos(concepto)
},
'',
"" + helper_1.formatCurrency(concepto.importe),
]; });
arr.unshift([
'ClaveProdServ',
'Cant',
'Clave Unidad',
'Unidad',
'Descripción',
'Valor Unitario',
'Descuento',
{
colSpan: 2,
text: 'Impuesto'
},
'',
'Importe',
]);
arr.unshift([
{
text: 'PARTIDAS DEL COMPROBANTE',
style: 'tableHeader',
colSpan: 10,
alignment: 'center'
},
{},
{},
{},
{},
{},
{},
{},
{},
{},
]);
return arr;
};
var generateRelatedDocs = function (docs) {
var arr = docs.map(function (doc) { return [
doc.uuid,
doc.metodoPago,
doc.moneda,
doc.tipoCambio,
doc.numParcialidad,
"" + helper_1.formatCurrency(doc.saldoAnterior),
"" + helper_1.formatCurrency(doc.importePagado),
"" + helper_1.formatCurrency(doc.saldoInsoluto),
]; });
arr.unshift([
'UUID',
'Método de Pago',
'Moneda',
'Tipo de Cambio',
'Num. Parcialidad',
'Importe Saldo Anterior',
'Importe Pagado',
'Importe Saldo Insoluto',
]);
arr.unshift([
{
text: 'DOCUMENTOS RELACIONADOS',
style: 'tableHeader',
colSpan: 8,
alignment: 'center'
},
{},
{},
{},
{},
{},
{},
{},
]);
return arr;
};
var generatePayments = function (pagos) {
var arr = pagos.map(function (pago) { return [
{
style: 'tableContent',
table: {
widths: [95, '*', 95, '*'],
body: [
[
{
text: 'INFORMACIÓN DE PAGO',
style: 'tableHeader',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
],
[
'FECHA:',
pago.fecha,
'FORMA PAGO:',
catalogs_1.formasPagoCatalog[pago.formaPago]
? pago.formaPago + " - " + catalogs_1.formasPagoCatalog[pago.formaPago]
: '',
],
[
'MONEDA:',
catalogs_1.monedasCatalog[pago.moneda] ? pago.moneda + " - " + catalogs_1.monedasCatalog[pago.moneda] : '',
'MONTO:',
"" + helper_1.formatCurrency(pago.monto),
],
pago.tipoCambio ? ['TIPO DE CAMBIO:', pago.tipoCambio, '', ''] : ['', '', '', ''],
]
},
layout: 'lightHorizontalLines'
},
'\n',
{
style: 'tableList',
table: {
widths: ['*', 'auto', 'auto', 30, 20, 'auto', 'auto', 'auto'],
body: generateRelatedDocs(pago.doctoRelacionados)
},
layout: {
fillColor: function (i) {
return i % 2 !== 0 ? '#CCCCCC' : null;
}
}
},
'\n',
]; });
return [].concat.apply([], arr);
};
var generateQrCode = function (json) {
var template = 'https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id={id}&re={re}&rr={rr}&tt={tt}&fe={fe}';
var qrCode = template
.replace('{id}', json.timbreFiscalDigital.uuid)
.replace('{re}', json.emisor.rfc)
.replace('{rr}', json.receptor.rfc)
.replace('{tt}', json.total)
.replace('{fe}', json.timbreFiscalDigital.selloCFD.substring(json.timbreFiscalDigital.selloCFD.length - 8, json.timbreFiscalDigital.selloCFD.length));
return qrCode;
};
var generateStampTable = function (json) {
var arr = [];
if (json.timbreFiscalDigital) {
var fechaHoraCertificacion = json.timbreFiscalDigital.fechaTimbrado;
arr.push([
{
colSpan: 1,
rowSpan: 8,
qr: generateQrCode(json),
fit: 140
},
'',
'',
], ['', 'NUMERO SERIE CERTIFICADO SAT', check_1.exists(json.timbreFiscalDigital.noCertificadoSAT)], ['', 'NUMERO SERIE CERTIFICADO EMISOR', check_1.exists(json.noCertificado)], ['', 'FECHA HORA CERTIFICACION', fechaHoraCertificacion], ['', 'FOLIO FISCAL UUID', check_1.exists(json.timbreFiscalDigital.uuid)], ['', 'SELLO DIGITAL', helper_1.breakEveryNCharacters(check_1.exists(json.timbreFiscalDigital.selloCFD), 86)], ['', 'SELLO DEL SAT', helper_1.breakEveryNCharacters(check_1.exists(json.timbreFiscalDigital.selloSAT), 86)]);
}
arr.push(['', 'CADENA ORIGINAL CC:', { text: helper_1.breakEveryNCharacters(json.cadenaOriginalCC, 86) }]);
return arr;
};
var generateAddress = function (receptor, address) {
var arr = [];
var addressArray = [];
if (address) {
addressArray.push('DOMICILIO:', address);
}
addressArray.push('USO CFDI:', {
colSpan: address ? 1 : 3,
text: catalogs_1.usosCfdiCatalog[receptor.usoCFDI] ? receptor.usoCFDI + " - " + catalogs_1.usosCfdiCatalog[receptor.usoCFDI] : ''
});
arr.push(addressArray);
if (receptor.residenciaFiscal && receptor.numRegIdTrib) {
arr.push([
'RESIDENCIA FISCAL:',
check_1.exists(receptor.residenciaFiscal),
'NUMERO ID TRIB.:',
check_1.exists(receptor.numRegIdTrib),
]);
}
return arr;
};
// generate content array used in PDFMake
var generateContent = function (json, logo, text, address) { return __awaiter(void 0, void 0, void 0, function () {
var content, header, _a, _b, _c, _d;
var _e, _f, _g;
return __generator(this, function (_h) {
switch (_h.label) {
case 0:
content = [];
header = {
alignment: 'center',
style: 'tableContent',
table: {
widths: ['auto', 'auto', 'auto'],
fontSize: 9,
body: [
['', 'SERIE:', json.serie],
['', 'FOLIO:', json.folio],
['', 'FECHA:', json.fecha],
['', 'EXPEDICION:', json.lugar],
[
'',
'COMPROBANTE:',
catalogs_1.tiposComprobantesCatalog[json.tipoDeComprobante]
? json.tipoDeComprobante + " - " + catalogs_1.tiposComprobantesCatalog[json.tipoDeComprobante]
: '',
],
]
},
layout: 'lightHorizontalLines'
};
if (logo) {
header.table.body[0][0] = { rowSpan: 5, image: logo, fit: [260, 260] };
header.table.widths = ['*', 'auto', 'auto'];
}
content.push(header);
// space
content.push('\n');
// this block contains info. about "emisor" object
content.push({
style: 'tableContent',
table: {
widths: ['auto', '*', 'auto', 'auto'],
body: [
[
{
text: 'EMISOR',
style: 'tableHeader',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
],
['NOMBRE:', check_1.exists(json.emisor.nombre), 'RFC:', check_1.exists(json.emisor.rfc)],
[
'REGIMEN FISCAL:',
{
colSpan: 3,
text: catalogs_1.regimenesFiscalesCatalog[json.emisor.regimenFiscal]
? json.emisor.regimenFiscal + " - " + catalogs_1.regimenesFiscalesCatalog[json.emisor.regimenFiscal]
: ''
},
'',
],
]
},
layout: 'lightHorizontalLines'
});
// space
content.push('\n');
// this block contains info. about "receptor" object
content.push({
style: 'tableContent',
table: {
widths: ['auto', '*', 'auto', 'auto'],
body: __spreadArray([
[
{
text: 'RECEPTOR',
style: 'tableHeader',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
],
['NOMBRE:', check_1.exists(json.receptor.nombre), 'RFC:', check_1.exists(json.receptor.rfc)]
], generateAddress(json.receptor, address))
},
layout: 'lightHorizontalLines'
});
// space
content.push('\n');
// check type of invoice
if (json.tipoDeComprobante.toUpperCase() === 'I' || json.tipoDeComprobante.toUpperCase() === 'E') {
// this block contains general info. about the invoice
content.push({
style: 'tableContent',
table: {
widths: [95, '*', 95, '*'],
body: [
[
{
text: 'DATOS GENERALES DEL COMPROBANTE',
style: 'tableHeader',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
],
[
'MONEDA:',
catalogs_1.monedasCatalog[json.moneda] ? json.moneda + " - " + catalogs_1.monedasCatalog[json.moneda] : '',
'FORMA PAGO:',
catalogs_1.formasPagoCatalog[json.formaPago]
? json.formaPago + " - " + catalogs_1.formasPagoCatalog[json.formaPago]
: '',
],
['TIPO DE CAMBIO:', json.tipoCambio, 'CONDICIONES DE PAGO:', json.condicionesDePago],
[
'CLAVE CONFIRMACION:',
json.confirmacion,
'METODO DE PAGO:',
catalogs_1.metodosPagoCatalog[json.metodoPago]
? json.metodoPago + " - " + catalogs_1.metodosPagoCatalog[json.metodoPago]
: '',
],
]
},
layout: 'lightHorizontalLines'
});
// space
content.push('\n');
}
// this block contains the concepts of the invoice
content.push({
style: 'tableList',
table: {
widths: ['auto', 'auto', 'auto', 'auto', '*', 'auto', 'auto', 'auto', 'auto', 'auto'],
body: generateConceptsTable(json.conceptos)
},
layout: {
fillColor: function (i) {
return i % 2 !== 0 ? '#CCCCCC' : null;
}
}
});
// space
content.push('\n');
if (!(json.tipoDeComprobante.toUpperCase() === 'I' || json.tipoDeComprobante.toUpperCase() === 'E')) return [3 /*break*/, 2];
// this block contains currency related info.
_b = (_a = content).push;
_e = {
style: 'tableContent'
};
_f = {
widths: ['auto', '*', 'auto', '*']
};
_c = [[
{
text: 'CFDI RELACIONADO',
style: 'tableHeader',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
], [
'TIPO RELACION:',
catalogs_1.tiposRelacionesCatalog[json.cfdiRelacionado ? json.cfdiRelacionado.tipoRelacion : '']
? json.cfdiRelacionado.tipoRelacion + " - " + catalogs_1.tiposRelacionesCatalog[json.cfdiRelacionado.tipoRelacion]
: '',
'CFDI RELACIONADO:',
json.cfdiRelacionado ? check_1.exists(json.cfdiRelacionado.uuid) : '',
],
['SUBTOTAL:', "" + helper_1.formatCurrency(json.subTotal), 'TOTAL:', "" + helper_1.formatCurrency(json.total)]];
_d = ['DESCUENTO:', "" + helper_1.formatCurrency(json.descuento), { text: 'IMPORTE CON LETRA:' }];
_g = {};
return [4 /*yield*/, toCurrency_1.toCurrency(parseFloat(json.total), json.moneda)];
case 1:
// this block contains currency related info.
_b.apply(_a, [(_e.table = (_f.body = _c.concat([
_d.concat([
(_g.text = _h.sent(), _g)
]),
[
'TOTAL IMP. TRASLADADOS:',
"" + helper_1.formatCurrency(check_1.existsValue(json.totalImpuestosTrasladados)),
'TOTAL IMP. RETENIDOS:',
"" + helper_1.formatCurrency(check_1.existsValue(json.totalImpuestosRetenidos)),
]
]),
_f),
_e.layout = 'lightHorizontalLines',
_e)]);
// space
content.push('\n');
_h.label = 2;
case 2:
// check type of invoice
if (json.tipoDeComprobante.toUpperCase() === 'P') {
// this block contains info. about payment
content = content.concat(generatePayments(json.pagos));
}
if (text) {
// observations
content.push({
style: 'tableContent',
table: {
widths: ['*'],
body: [[{ text: 'OBSERVACIONES', style: 'tableHeader' }], [text]]
},
layout: 'lightHorizontalLines'
});
// space
content.push('\n');
}
// this block contains info. about the stamp
content.push({
style: 'tableSat',
table: {
widths: ['auto', 'auto', '*'],
body: generateStampTable(json)
},
layout: 'lightHorizontalLines'
});
return [2 /*return*/, content];
}
});
}); };
/**
* Receives a json and returns a pdf content object for pdfmake
* @param {Cfdi} json result json from using parseData function
*/
var generatePdfContent = function (json, options) { return __awaiter(void 0, void 0, void 0, function () {
var logo, dd;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
logo = options.image;
if (options.cadenaOriginal)
json.cadenaOriginalCC = options.cadenaOriginal;
_a = {};
return [4 /*yield*/, generateContent(json, logo, options.text, options.address)];
case 1:
dd = (_a.content = _b.sent(),
_a.styles = {
tableHeader: {
bold: true,
fontSize: 10,
color: 'black'
},
tableContent: {
fontSize: 8,
color: 'black',
alignment: 'left'
},
tableList: {
fontSize: 7,
color: 'black',
alignment: 'center'
},
tableSat: {
fontSize: 5,
color: 'black',
alignment: 'left'
}
},
_a.defaultStyle = {
// alignment: 'justify'
},
_a.footer = function () {
return {
style: 'tableContent',
table: {
widths: ['auto', '*', 'auto', 'auto'],
body: [
[
{
text: 'Este documento es una representación impresa de un CFDI',
style: 'tableList',
colSpan: 4,
alignment: 'center'
},
{},
{},
{},
],
]
},
layout: 'lightHorizontalLines'
};
},
_a);
return [2 /*return*/, dd];
}
});
}); };
exports.generatePdfContent = generatePdfContent;
//# sourceMappingURL=generateContent.js.map