@treeunfe/danfe 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFCEGerarDanfe/NFCEGerarDanfe.d.ts +58 -0
  2. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFCEGerarDanfe/NFCEGerarDanfe.js +495 -0
  3. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFCEGerarDanfe/NFCEGerarDanfe.js.map +1 -0
  4. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFEGerarDanfe/NFEGerarDanfe.d.ts +39 -0
  5. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFEGerarDanfe/NFEGerarDanfe.js +1097 -0
  6. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/NFEGerarDanfe/NFEGerarDanfe.js.map +1 -0
  7. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/index.d.ts +2 -0
  8. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/index.js +19 -0
  9. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/src/index.js.map +1 -0
  10. package/.rollup.cache/home/runner/work/treeunfe-dfe/treeunfe-dfe/packages/danfe/dist/tsconfig.tsbuildinfo +1 -0
  11. package/.turbo/turbo-build.log +15 -0
  12. package/.turbo/turbo-typecheck.log +4 -0
  13. package/CHANGELOG.md +27 -0
  14. package/LICENSE.txt +221 -0
  15. package/dist/index.cjs +1591 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.mjs +1587 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/src/NFCEGerarDanfe/NFCEGerarDanfe.d.ts +58 -0
  20. package/dist/src/NFEGerarDanfe/NFEGerarDanfe.d.ts +39 -0
  21. package/dist/src/index.d.ts +2 -0
  22. package/dist/tsconfig.tsbuildinfo +1 -0
  23. package/package.json +63 -0
  24. package/rollup.config.js +94 -0
  25. package/src/NFCEGerarDanfe/NFCEGerarDanfe.ts +598 -0
  26. package/src/NFEGerarDanfe/NFEGerarDanfe.ts +1223 -0
  27. package/src/bwip-js.d.ts +16 -0
  28. package/src/index.ts +19 -0
  29. package/tsconfig.json +16 -0
@@ -0,0 +1,598 @@
1
+ /**
2
+ * @description :
3
+ * @author : Marco Aurélio Silva Lima
4
+ * @group :
5
+ * @created :
6
+ *
7
+ * MODIFICATION LOG
8
+ * - Version : 1.0.0
9
+ * - Date : 3/7/2025
10
+ * - Author : Cassio Seffrin
11
+ * - Modification :
12
+ **/
13
+ /*
14
+ * This file is part of Treeunfe DFe.
15
+ *
16
+ * Treeunfe DFe is free software: you can redistribute it and/or modify
17
+ * it under the terms of the GNU General Public License as published by
18
+ * the Free Software Foundation, either version 3 of the License, or
19
+ * (at your option) any later version.
20
+ *
21
+ * Treeunfe DFe is distributed in the hope that it will be useful,
22
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
+ * GNU General Public License for more details.
25
+ *
26
+ * You should have received a copy of the GNU General Public License
27
+ * along with Treeunfe DFe. If not, see <https://www.gnu.org/licenses/>.
28
+ */
29
+ import { ValidaCPFCNPJ } from '@treeunfe/shared';
30
+ import { getDesTipoPag } from '@treeunfe/shared';
31
+ import bwipjs from 'bwip-js';
32
+ import { format, parseISO } from 'date-fns';
33
+ import fs from 'fs';
34
+ import path from 'path';
35
+ import PDFDocument from 'pdfkit';
36
+ import QRCode from 'qrcode';
37
+ import { Dest, DetProd, Emit, Ide, InfAdic, InfNFeSupl, NFEGerarDanfeProps, Pag, ProtNFe, Total, Transp } from '@treeunfe/types';
38
+ import { fileURLToPath } from 'url';
39
+
40
+ const baseDir = path.dirname(fileURLToPath(import.meta.url))
41
+ const fontDir = process.env.NODE_ENV === 'production' ? '../resources/fonts/ARIAL.TTF' : '../../../../resources/fonts/ARIAL.TTF';
42
+ const fontDirBold = process.env.NODE_ENV === 'production' ? '../resources/fonts/ARIALBD.TTF' : '../../../../resources/fonts/ARIALBD.TTF';
43
+
44
+ class NFCEGerarDanfe {
45
+ data: NFEGerarDanfeProps['data'];
46
+ chave: string;
47
+ enviada: boolean;
48
+ outputPath: string
49
+ qrcodePath: string;
50
+ documento: InstanceType<typeof ValidaCPFCNPJ>;
51
+ protNFe: ProtNFe | undefined;
52
+ det: DetProd | DetProd[];
53
+ ide: Ide;
54
+ dest: Dest | undefined;
55
+ emit: Emit;
56
+ total: Total;
57
+ transp: Transp;
58
+ pag: Pag;
59
+ infAdic: InfAdic | undefined;
60
+ infNFeSupl: InfNFeSupl | undefined
61
+ exibirMarcaDaguaDanfe?: boolean;
62
+ fontSize: number;
63
+ larguraPadrao: number;
64
+ documentWidth: number;
65
+ itemHeight: number;
66
+ doc: InstanceType<typeof PDFDocument>;
67
+
68
+ constructor(props: NFEGerarDanfeProps) {
69
+ const { data, chave, outputPath, pageWidth } = props;
70
+
71
+ this.data = data;
72
+ this.chave = chave.trim();
73
+ this.outputPath = outputPath;
74
+ this.enviada = false; // Valor padrão
75
+ this.qrcodePath = outputPath; // Caminho padrão
76
+ this.documento = new ValidaCPFCNPJ(); // Inicialização correta
77
+ this.protNFe = data.protNFe;
78
+
79
+ const nfeData = Array.isArray(data.NFe) ? data.NFe[0] : data.NFe;
80
+ const { det, ide, emit, dest, total, transp, pag, infAdic } = nfeData.infNFe;
81
+ const infNFeSupl = nfeData.infNFeSupl;
82
+
83
+ this.det = det;
84
+ this.ide = ide;
85
+ this.emit = emit;
86
+ this.total = total;
87
+ this.transp = transp;
88
+ this.pag = pag;
89
+ this.infAdic = infAdic;
90
+ this.infNFeSupl = infNFeSupl;
91
+ if (dest) this.dest = dest;
92
+
93
+ if (this.protNFe?.infProt.nProt) {
94
+ this.enviada = true;
95
+ }
96
+
97
+ function calculateHeight(itemsLength: number, itemHeight: number) {
98
+ const headerHeight = 34.22975675056; // Altura do cabeçalho
99
+ const footerHeight = 170; // Altura do rodapé -> 34.22975675056
100
+
101
+ // Altura total é a soma das alturas dos itens + cabeçalho + rodapé
102
+ return headerHeight + footerHeight + (itemsLength * itemHeight) + 5;
103
+ }
104
+
105
+ function calculateFontSize(width: number) {
106
+ // Aqui você pode ajustar a fórmula para atender às suas necessidades
107
+ return Math.min(width) * 0.02646;
108
+ }
109
+
110
+ this.larguraPadrao = 226.772;
111
+ this.documentWidth = pageWidth || 226.772; // 158.74
112
+ // const pageHeight = 300;
113
+ let itensLength = 1;
114
+ if (this.det instanceof Array) {
115
+ itensLength = this.det.length;
116
+ }
117
+
118
+ const fontSize = calculateFontSize(this.documentWidth);
119
+ this.fontSize = fontSize;
120
+
121
+ this.itemHeight = fontSize * 1.116;
122
+ const pageHeight = calculateHeight(itensLength, this.itemHeight);
123
+
124
+ const fontPath = path.resolve(baseDir, fontDir);
125
+ const fontPathBold = path.resolve(baseDir, fontDirBold);
126
+
127
+ this.doc = new PDFDocument({
128
+ margins: { top: 5.67, right: 5.67, bottom: 5.67, left: 5.67 },
129
+ size: [this.documentWidth, pageHeight],
130
+ bufferPages: true,
131
+ layout: 'portrait',
132
+ });
133
+ this.doc.registerFont('Arial', fontPath)
134
+ this.doc.registerFont('Arial-bold', fontPathBold)
135
+ }
136
+
137
+ saveQRCode = async (text: string) => {
138
+ const filePath = path.resolve(baseDir, this.qrcodePath);
139
+
140
+ try {
141
+ await QRCode.toFile(`${filePath}/qrcode.png`, text, {
142
+ color: {
143
+ dark: '#000000', // Cor do código
144
+ light: '#FFFFFF', // Cor de fundo
145
+ },
146
+ width: 300, // Largura da imagem
147
+ });
148
+ } catch (error: any) {
149
+ console.error('Erro ao gerar o QR code:', error);
150
+ console.error(error.stack);
151
+ }
152
+ };
153
+
154
+ getQRCodeBuffer = async (text: string) => {
155
+ try {
156
+ const buffer = await QRCode.toBuffer(text, {
157
+ color: {
158
+ dark: '#000000', // Cor do código
159
+ light: '#FFFFFF', // Cor de fundo
160
+ },
161
+ width: 300, // Largura da imagem
162
+ });
163
+ return buffer;
164
+ } catch (error: any) {
165
+ console.error('Erro ao gerar o QR code:', error);
166
+ console.error(error.stack);
167
+ throw new Error(`Erro ao gerar o QR code: ${error.message}`);
168
+ }
169
+ };
170
+
171
+ createDir(path: string) {
172
+ if (!fs.existsSync(path)) {
173
+ fs.mkdirSync(path, { recursive: true });
174
+ }
175
+ }
176
+
177
+ async generateBarcode(data: string): Promise<Buffer | null> {
178
+ try {
179
+ const png = await bwipjs.toBuffer({
180
+ bcid: 'code128', // Tipo de código de barras
181
+ text: data, // Dado a ser codificado
182
+ scaleX: 4, // Fator de escala
183
+ height: 14, // Altura da barra
184
+ includetext: false, // Incluir texto
185
+ });
186
+ const barcode = png.toString('base64');
187
+ const buffer: any = Buffer.from(barcode, 'base64')
188
+ const barcodeDir = this.qrcodePath;
189
+ const barcodeFilePath = path.join(barcodeDir, 'barcode.png');
190
+ // this.createDir(barcodeDir);
191
+ fs.writeFileSync(barcodeFilePath, buffer);
192
+ return buffer;
193
+ } catch (err) {
194
+ console.error('Erro ao gerar código de barras:', err);
195
+ return null;
196
+ }
197
+ }
198
+
199
+ centeredPos(texto: string) {
200
+ const larguraPagina = this.doc.page.width;
201
+ const larguraTexto = this.doc.fontSize(this.fontSize).widthOfString(texto);
202
+ const posicaoX = (larguraPagina - larguraTexto) / 2;
203
+ return posicaoX;
204
+ }
205
+
206
+ ajustarPosicao(posicaoOriginal: number, novaLargura: number) {
207
+ return posicaoOriginal * (novaLargura / this.larguraPadrao);
208
+ }
209
+
210
+ calculaPosicao(text: string) {
211
+ const { right, left } = this.doc.page.margins;
212
+ const [pageWidth] = this.doc.page.size;
213
+
214
+ const textWidth = this.doc.widthOfString(text);
215
+ return Number(pageWidth) - textWidth - right - left;
216
+ }
217
+
218
+ drawHeader(_isFirstPage: boolean) {
219
+ this._buildHeader();
220
+ }
221
+
222
+ drawFooter(qrCodeBuffer: Buffer) {
223
+ this._buildFooter(qrCodeBuffer);
224
+ }
225
+
226
+ _buildHeader() {
227
+ const CNPJCPF = this.emit.CNPJCPF?.toString()
228
+ const CNPJ = this.emit.CNPJ?.toString()
229
+ const CPF = this.emit.CPF?.toString()
230
+ const documento = this.documento.mascaraCnpjCpf(CNPJCPF || CNPJ || CPF || '')
231
+
232
+ const identificationJoined = `${this.emit.enderEmit.xLgr}, ${this.emit.enderEmit.nro}, ${this.emit.enderEmit.xBairro}, ${this.emit.enderEmit.UF}`
233
+
234
+ /** IDENTIFICACAO EMITENTE */
235
+ const _buildIdentificacaoEmit = () => {
236
+ const centeredPosEmit = this.centeredPos(`CNPJ: ${documento} ${this.emit.xNome}`)
237
+ const centeredPosEnd = this.centeredPos(identificationJoined)
238
+ const centeredPosText = this.centeredPos('Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica')
239
+
240
+ this.doc.font('Arial').fontSize(this.fontSize).text(`CNPJ: ${documento} `, centeredPosEmit, 2, {
241
+ lineBreak: false,
242
+ })
243
+ .font('Arial-bold').text(this.emit.xNome)
244
+ .fontSize(this.fontSize)
245
+ .font('Arial')
246
+ .text(identificationJoined, centeredPosEnd)
247
+ .text('Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica', centeredPosText)
248
+ }
249
+
250
+ _buildIdentificacaoEmit();
251
+ }
252
+
253
+ _buildProdutos() {
254
+ const { right, left, top } = this.doc.page.margins;
255
+ const tableWidth = this.documentWidth - left - right;
256
+ const startX = left;
257
+ const tableTop = this.doc.y + top;
258
+ const columnRatios = {
259
+ codigo: 0.15,
260
+ descricao: 0.40,
261
+ qtdeUn: 0.15,
262
+ unit: 0.15,
263
+ total: 0.15
264
+ };
265
+ const columnSpacing = 0;
266
+ const columnWidths = {
267
+ codigo: tableWidth * columnRatios.codigo,
268
+ descricao: tableWidth * columnRatios.descricao,
269
+ qtdeUn: tableWidth * columnRatios.qtdeUn,
270
+ unit: tableWidth * columnRatios.unit,
271
+ total: tableWidth * columnRatios.total
272
+ };
273
+ const header = (top: number) => {
274
+ let x = startX;
275
+ this.doc.font('Arial-bold').fontSize(this.fontSize).text('Código', x, top, { width: columnWidths.codigo });
276
+ x += columnWidths.codigo + columnSpacing;
277
+ this.doc.text('Descrição', x, top, { width: columnWidths.descricao });
278
+ x += columnWidths.descricao + columnSpacing;
279
+ this.doc.text('Qtde', x, top, { width: columnWidths.qtdeUn, align: 'right' });
280
+ x += columnWidths.qtdeUn + columnSpacing;
281
+ this.doc.text('Unit', x, top, { width: columnWidths.unit, align: 'right' });
282
+ x += columnWidths.unit + columnSpacing;
283
+ this.doc.text('Total', x, top, { width: columnWidths.total, align: 'right' });
284
+ };
285
+
286
+ const row = (top: number, item: DetProd) => {
287
+ const quant = parseFloat(String(item.prod.qCom || item.prod.qTrib)).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
288
+ const valUnit = parseFloat(String(item.prod.vUnCom || item.prod.vUnTrib || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
289
+ const valLiq = parseFloat(String(item.prod.vProd || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
290
+
291
+ let x = startX;
292
+ this.doc.font('Arial').fontSize(this.fontSize).text(item.prod.cProd, x, top, {
293
+ width: columnWidths.codigo,
294
+ align: 'left' as const
295
+ });
296
+
297
+ x += columnWidths.codigo + columnSpacing;
298
+
299
+
300
+ const descricao = item.prod.xProd.slice(0, 120); // Limite de 120 caracteres
301
+ const textWidth = this.doc.widthOfString(descricao);
302
+ const lineCount = Math.ceil(textWidth / columnWidths.descricao);
303
+
304
+ const descricaoOptions = {
305
+ width: columnWidths.descricao,
306
+ align: 'left' as const,
307
+ height: this.itemHeight * lineCount
308
+ };
309
+
310
+ this.doc.text(descricao, x, top, descricaoOptions);
311
+ x += columnWidths.descricao + columnSpacing;
312
+
313
+ this.doc.text(`${quant} ${item.prod.uCom}`, x, top, {
314
+ width: columnWidths.qtdeUn,
315
+ align: 'right'
316
+ });
317
+ x += columnWidths.qtdeUn + columnSpacing;
318
+
319
+ this.doc.text(valUnit, x, top, {
320
+ width: columnWidths.unit,
321
+ align: 'right'
322
+ });
323
+ x += columnWidths.unit + columnSpacing;
324
+
325
+ this.doc.text(valLiq, x, top, {
326
+ width: columnWidths.total,
327
+ align: 'right'
328
+ });
329
+
330
+
331
+ return descricaoOptions.height;
332
+ };
333
+ header(tableTop);
334
+ let y = tableTop + this.itemHeight;
335
+ if (this.det instanceof Array) {
336
+ this.det.forEach((prod) => {
337
+ row(y, prod);
338
+ y += this.itemHeight;
339
+ });
340
+ } else {
341
+ row(y, this.det);
342
+ }
343
+ }
344
+ _buildTotais() {
345
+
346
+ let tableTop = this.doc.y + 5;
347
+
348
+ const quantidadeTotalDeItens = Array.isArray(this.det) ? this.det.length : 1;
349
+
350
+ let valTotal = 0;
351
+ let acrescimo = 0;
352
+ let desconto = 0;
353
+
354
+ if (Array.isArray(this.det)) {
355
+ // Calcula o valor total dos produtos
356
+ valTotal = this.det.reduce((sum, item) => sum + parseFloat(item.prod.vProd), 0);
357
+
358
+ // Calcula o total dos acréscimos
359
+ acrescimo = this.det.reduce((sum, item) =>
360
+ sum + (parseFloat(item.prod.vFrete || '0') + parseFloat(item.prod.vSeg || '0') + parseFloat(item.prod.vOutro || '0')), 0
361
+ );
362
+
363
+ // Calcula o total dos descontos
364
+ desconto = this.det.reduce((sum, item) => sum + parseFloat(item.prod.vDesc || '0'), 0);
365
+ } else {
366
+ // Calcula o valor total do produto, os acréscimos, e desconto caso não seja um array
367
+ valTotal = parseFloat(this.det.prod.vProd);
368
+ acrescimo = parseFloat(this.det.prod.vFrete || '0') + parseFloat(this.det.prod.vSeg || '0') + parseFloat(this.det.prod.vOutro || '0');
369
+ desconto = parseFloat(this.det.prod.vDesc || '0')
370
+ }
371
+ const valorTotal = valTotal.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
372
+ const acrescimoTotal = acrescimo.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
373
+ const descontoTotal = desconto.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
374
+
375
+ this.doc.text('Qtd. total de itens', 2, tableTop);
376
+ this.doc.text(String(quantidadeTotalDeItens), this.calculaPosicao(String(quantidadeTotalDeItens)), tableTop, {
377
+ align: 'right',
378
+ });
379
+ tableTop += this.itemHeight;
380
+
381
+ this.doc.text('Valor total R$', 2, tableTop);
382
+ this.doc.text(valorTotal, this.calculaPosicao(valorTotal), tableTop, {
383
+ align: 'right',
384
+ });
385
+
386
+ tableTop += this.itemHeight;
387
+
388
+ if (desconto > 0) {
389
+ this.doc.text('Desconto R$', 2, tableTop);
390
+ this.doc.text(descontoTotal, this.calculaPosicao(descontoTotal), tableTop, {
391
+ align: 'right',
392
+ });
393
+ tableTop += this.itemHeight;
394
+ }
395
+ if (acrescimo > 0) {
396
+ this.doc.text('Acréscimo R$', 2, tableTop);
397
+ this.doc.text(acrescimoTotal, this.calculaPosicao(acrescimoTotal), tableTop, {
398
+ align: 'right',
399
+ });
400
+ tableTop += this.itemHeight;
401
+ }
402
+
403
+ if (desconto > 0 || acrescimo > 0) {
404
+ const totalPagar = parseFloat(String(valTotal + acrescimo - desconto)).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
405
+
406
+ this.doc.font('Arial-bold').text('Valor a Pagar R$', 2, tableTop);
407
+ this.doc.text(totalPagar, this.calculaPosicao(totalPagar), tableTop, {
408
+ align: 'right',
409
+ });
410
+ }
411
+
412
+ tableTop += this.itemHeight + 2;
413
+
414
+ this.doc.font('Arial').text('FORMA PAGAMENTO', 2, tableTop);
415
+
416
+ // Tipos
417
+
418
+ let topTiposPag = tableTop;
419
+ if (Array.isArray(this.pag.detPag)) {
420
+ for (let pagto of this.pag.detPag) {
421
+ if (!pagto.xPag) pagto.xPag = getDesTipoPag(pagto.tPag);
422
+ this.doc.text(pagto.xPag || 'Não informado', 2, topTiposPag + this.itemHeight);
423
+ topTiposPag += this.itemHeight;
424
+ }
425
+ } else {
426
+ if (!this.pag.detPag.xPag) this.pag.detPag.xPag = getDesTipoPag(this.pag.detPag.tPag);
427
+ this.doc.text(this.pag.detPag.xPag || 'Não informado', 2, topTiposPag + this.itemHeight);
428
+ }
429
+
430
+ this.doc.text('VALOR PAGO R$', this.calculaPosicao('VALOR PAGO R$'), tableTop, {
431
+ align: 'right',
432
+ });
433
+
434
+ // Valores
435
+ let topValPags = tableTop;
436
+ if (Array.isArray(this.pag.detPag)) {
437
+ for (let pagto of this.pag.detPag) {
438
+ const val = parseFloat(pagto.vPag).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
439
+ this.doc.text(val, this.calculaPosicao(val), topValPags + this.itemHeight, {
440
+ align: 'right',
441
+ });
442
+ topValPags += this.itemHeight;
443
+ }
444
+ } else {
445
+ const val = parseFloat(this.pag.detPag.vPag).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
446
+ this.doc.text(val, this.calculaPosicao(val), topValPags + this.itemHeight, {
447
+ align: 'right',
448
+ });
449
+ }
450
+
451
+ tableTop = topValPags;
452
+ tableTop += 2 * this.itemHeight;
453
+
454
+ let valTroco = 0;
455
+ if (Array.isArray(this.pag.detPag)) {
456
+ valTroco = this.pag.detPag.reduce((sum, item) => sum + parseFloat(item.vTroco || '0'), 0);
457
+ } else {
458
+ valTroco = parseFloat(this.pag.detPag.vTroco || '0');
459
+ }
460
+
461
+ const troco = valTroco.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 })
462
+
463
+ this.doc.text('Troco R$', 2, tableTop);
464
+ this.doc.text(troco, this.calculaPosicao(troco), tableTop, {
465
+ align: 'right',
466
+ });
467
+
468
+ }
469
+
470
+ _buildFooter(qrCodeBuffer: Buffer) {
471
+ let tableTop = this.doc.y + 5;
472
+
473
+ this.doc.font('Arial-bold').text('Consulte pela Chave de Acesso em', 0, tableTop, {
474
+ align: 'center'
475
+ });
476
+ tableTop += this.itemHeight;
477
+
478
+ this.doc.font('Arial').text(this.infNFeSupl?.urlChave || '', 0, tableTop, {
479
+ align: 'center'
480
+ });
481
+ tableTop += this.itemHeight;
482
+
483
+ this.doc.text(this.protNFe?.infProt.chNFe || '', 0, tableTop, {
484
+ align: 'center'
485
+ });
486
+
487
+ tableTop += this.itemHeight;
488
+ // const filePath = path.resolve(baseDir, this.qrcodePath);
489
+ // this.doc.image(`${filePath}/qrcode.png`, 2, tableTop, { width: 70.87, height: 70.87 });
490
+ this.doc.image(qrCodeBuffer, 2, tableTop, { width: 70.87, height: 70.87 });
491
+
492
+
493
+ tableTop += 4;
494
+ let topBeforeQrCode = tableTop;
495
+
496
+ const CNPJCPF = this.documento.mascaraCnpjCpf(
497
+ this.dest?.CNPJCPF || this.dest?.CNPJ || this.dest?.CPF || this.dest?.idEstrangeiro || ''
498
+ );
499
+ const xNome = this.dest?.xNome ?? 'Sem cliente identificado';
500
+ const xLgr = this.dest?.enderDest?.xLgr ?? '';
501
+ const nro = this.dest?.enderDest?.nro ?? '';
502
+ const xBairro = this.dest?.enderDest?.xBairro ?? null;
503
+ const xMun = this.dest?.enderDest?.xMun ?? '';
504
+ const UF = this.dest?.enderDest?.UF ?? '';
505
+ const enderecoPartes = [
506
+ xLgr && `${xLgr}`,
507
+ nro && `${nro}`,
508
+ xBairro && `bairro: ${xBairro}`,
509
+ xMun && `${xMun}`,
510
+ UF && `${UF}`
511
+ ].filter(Boolean);
512
+ const enderecoStr = enderecoPartes.join(', ');
513
+ if (CNPJCPF && CNPJCPF !== '') {
514
+ this.doc.font('Arial-bold')
515
+ .text(`CONSUMIDOR - DOC ${CNPJCPF}`, 75, tableTop, {
516
+ align: 'left',
517
+ lineGap: 1
518
+ })
519
+ .font('Arial')
520
+ .text(` - ${xNome}`, {
521
+ lineGap: 1
522
+ });
523
+ tableTop = this.doc.y + 4;
524
+ this.doc.text(enderecoStr, 75, tableTop);
525
+ tableTop = this.doc.y + 8;
526
+ } else {
527
+ this.doc.text('CONSUMIDOR NÃO IDENTIFICADO', 75, tableTop, {
528
+ align: 'left',
529
+ });
530
+ tableTop = this.doc.y + 8;
531
+ }
532
+
533
+
534
+ const data = parseISO(this.ide.dhEmi);
535
+ const dtaEmi = format(data, 'dd/MM/yyyy HH:mm:ss');
536
+
537
+ let dtaAut = format(new Date(), 'dd/MM/yyyy HH:mm:ss');
538
+ if (this.protNFe?.infProt.dhRecbto) {
539
+ const dataAut = parseISO(this.protNFe?.infProt.dhRecbto);
540
+ dtaAut = format(dataAut, 'dd/MM/yyyy HH:mm:ss');
541
+ }
542
+
543
+ this.doc.font('Arial-bold')
544
+ .text(`NFC-e nº ${this.ide.nNF} Série ${this.ide.serie} ${dtaEmi}`, 75, tableTop, {
545
+ align: 'left',
546
+ lineGap: 1
547
+ })
548
+ .text('Protocolo de autorização: ', {
549
+ continued: true,
550
+ lineGap: 1,
551
+ })
552
+ .font('Arial')
553
+ .text(this.protNFe?.infProt.nProt || '123')
554
+ .font('Arial-bold')
555
+ .text('Data de autorização ', {
556
+ continued: true,
557
+ lineGap: 1,
558
+ })
559
+ .font('Arial')
560
+ .text(dtaAut);
561
+
562
+ tableTop = this.doc.y + 20;
563
+ topBeforeQrCode += 70.87
564
+ this.doc.text(`Tributos Totais Incidentes (Lei Federal 12.741/2012): R$ ${parseFloat(this.total.ICMSTot.vTotTrib || '0').toFixed(2)}`, 0, topBeforeQrCode, {
565
+ align: 'center'
566
+ });
567
+ }
568
+
569
+ async generatePDF(exibirMarcaDaguaDanfe?: boolean) {
570
+ try {
571
+ this.exibirMarcaDaguaDanfe = exibirMarcaDaguaDanfe || true;
572
+
573
+ // await this.saveQRCode(this.infNFeSupl?.qrCode || '')
574
+ const qrCodeBuffer = await this.getQRCodeBuffer(this.infNFeSupl?.qrCode || '');
575
+
576
+ this.doc.pipe(fs.createWriteStream(this.outputPath));
577
+
578
+ this.drawHeader(true);
579
+
580
+ this._buildProdutos();
581
+
582
+ this._buildTotais();
583
+
584
+ this.drawFooter(qrCodeBuffer);
585
+
586
+ this.doc.end();
587
+
588
+ return {
589
+ message: ` DANFE Gerada em '${this.outputPath}'`,
590
+ success: true,
591
+ };
592
+ } catch (error: any) {
593
+ throw new Error(`Erro ao gerar DANFE: ${error.message}`);
594
+ }
595
+ }
596
+ }
597
+
598
+ export default NFCEGerarDanfe;