@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
package/dist/index.cjs ADDED
@@ -0,0 +1,1591 @@
1
+ 'use strict';
2
+
3
+ var shared = require('@treeunfe/shared');
4
+ var bwipjs = require('bwip-js');
5
+ var dateFns = require('date-fns');
6
+ var fs = require('fs');
7
+ var PDFDocument = require('pdfkit');
8
+ var path = require('path');
9
+ var QRCode = require('qrcode');
10
+ var url = require('url');
11
+
12
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
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
+ class NFEGerarDanfe {
30
+ constructor(props) {
31
+ this.barcodeBuffer = null;
32
+ const { data, chave, outputPath } = props;
33
+ this.data = data;
34
+ this.chave = chave.trim();
35
+ this.outputPath = outputPath;
36
+ this.enviada = false;
37
+ this.documento = new shared.ValidaCPFCNPJ();
38
+ this.protNFe = data.protNFe;
39
+ const nfeData = Array.isArray(data.NFe) ? data.NFe[0] : data.NFe;
40
+ const { det, ide, emit, dest, total, transp, infAdic } = nfeData.infNFe;
41
+ this.det = det;
42
+ this.ide = ide;
43
+ this.emit = emit;
44
+ this.total = total;
45
+ this.transp = transp;
46
+ this.infAdic = infAdic;
47
+ if (dest)
48
+ this.dest = dest;
49
+ if (this.protNFe?.infProt.nProt) {
50
+ this.enviada = true;
51
+ }
52
+ // Área útil ignorando margem à direita (22.68) e esquerda (5.67) = 566.93
53
+ this.doc = new PDFDocument({
54
+ margins: { top: 22, right: 22.68, bottom: 12, left: 5.67 },
55
+ size: 'a4', // 595.28 * 841.89
56
+ bufferPages: true,
57
+ layout: 'portrait',
58
+ font: 'Times-Roman',
59
+ });
60
+ }
61
+ async generateBarcode(data) {
62
+ try {
63
+ const pngBuffer = await bwipjs.toBuffer({
64
+ bcid: 'code128',
65
+ text: data,
66
+ scaleX: 4,
67
+ height: 14,
68
+ includetext: false,
69
+ });
70
+ this.barcodeBuffer = pngBuffer; // Armazena o buffer na instância
71
+ return pngBuffer; // Retorna o buffer
72
+ }
73
+ catch (err) {
74
+ console.error('Erro ao gerar código de barras:', err);
75
+ this.barcodeBuffer = null;
76
+ return null;
77
+ }
78
+ }
79
+ setLineStyle(lineWidth, strokeColor) {
80
+ this.doc.lineWidth(lineWidth).strokeColor(strokeColor).fill('black');
81
+ }
82
+ drawHeader(isFirstPage) {
83
+ if (isFirstPage) {
84
+ this._buildGuia();
85
+ this._buildSeparator();
86
+ this._buildHeader(52);
87
+ }
88
+ else {
89
+ this._buildHeader(0);
90
+ }
91
+ // this.doc.moveDown();
92
+ }
93
+ drawFooter() {
94
+ this._buildFooter();
95
+ }
96
+ _buildGuia() {
97
+ const { top, left } = this.doc.page.margins;
98
+ this.setLineStyle(0.75, '#1c1c1c');
99
+ /** TOP LEFT */
100
+ this.doc.rect(left, top, 470, 21).stroke();
101
+ this.doc.fontSize(5).text(`RECEBEMOS DE ${this.emit.xNome} OS PRODUTOS / SERVIÇOS CONSTANTES DA NOTA FISCAL INDICADO AO LADO`, 10, 26, {
102
+ characterSpacing: 0.5
103
+ });
104
+ this.doc.fontSize(6).text(`EMISSÃO: ${dateFns.format(new Date(this.ide.dhEmi), 'dd-MM-yyyy')} - DEST. / REM.: ${this.dest?.xNome || ''} - VALOR TOTAL: R$ ${parseFloat(String(this.total.ICMSTot.vNF)).toFixed(2)}`, 10, 33.5, {
105
+ characterSpacing: 0.5
106
+ });
107
+ /** RIGHT */
108
+ this.doc.rect(left + 470, top, 96.93, 42).stroke();
109
+ this.doc.fontSize(11).text(`NF-e`, 480, 27, {
110
+ characterSpacing: 1.5,
111
+ align: 'center'
112
+ });
113
+ this.doc.fontSize(8.8).font('Times-Bold').text(`Nº ${String(this.ide.nNF).padStart(2, '0')}`, 480, 40.5, {
114
+ characterSpacing: 1.5,
115
+ align: 'center',
116
+ });
117
+ this.doc.fontSize(8.5).font('Times-Roman').text(`SÉRIE ${this.ide.serie.padStart(3, '0')}`, 480, 53, {
118
+ characterSpacing: 1.5,
119
+ align: 'center',
120
+ });
121
+ /** BOTTON LEFT */
122
+ this.doc.rect(left, top + 21, 75, 21).stroke();
123
+ this.doc.fontSize(5).text(`DATA DE RECEBIMENTO`, 10, 46.5, {
124
+ characterSpacing: 0.5,
125
+ });
126
+ /** BOTTON RIGHT */
127
+ this.doc.rect(left + 75, top + 21, 395, 21).stroke();
128
+ this.doc.fontSize(5).text(`IDENTIFICAÇÃO E ASSINATURA DO RECEBEDOR`, 75 + 10, 46.5, {
129
+ characterSpacing: 0.5
130
+ });
131
+ }
132
+ _buildSeparator() {
133
+ const { left, right } = this.doc.page.margins;
134
+ const pageWidth = 595.28; // Largura da página A4 em pontos
135
+ // Calcule a largura da linha, considerando as margens esquerda e direita
136
+ const lineWidth = pageWidth - left - right;
137
+ // Desenhe a linha
138
+ this.doc.moveTo(left, 69) // Início da linha
139
+ .lineTo(left + lineWidth, 69) // Fim da linha
140
+ .lineWidth(1) // Espessura da linha
141
+ .dash(1.5, { space: 1.5 }) // Estilo pontilhado
142
+ .strokeColor('black') // Cor da linha
143
+ .stroke(); // Desenhar a linha
144
+ this.doc.undash();
145
+ }
146
+ _buildHeader(pos) {
147
+ const { top, left } = this.doc.page.margins;
148
+ const page = this.doc.bufferedPageRange();
149
+ const CNPJCPF = this.emit.CNPJCPF?.toString();
150
+ const CNPJ = this.emit.CNPJ?.toString();
151
+ const CPF = this.emit.CPF?.toString();
152
+ const documento = this.documento.mascaraCnpjCpf(CNPJCPF || CNPJ || CPF || '');
153
+ this.setLineStyle(0.75, '#1c1c1c');
154
+ const topIdentificacao_1 = top + pos;
155
+ const identificationJoined = `\nCEP: ${this.emit.enderEmit.CEP} - ${this.emit.enderEmit.xBairro} - ${this.emit.enderEmit.UF}\nTEL: ${this.emit.enderEmit.fone} - FAX: ${this.emit.enderEmit.fone}`;
156
+ /** IDENTIFICACAO EMITENTE */
157
+ const _buildIdentificacaoEmit = () => {
158
+ this.doc.rect(left, topIdentificacao_1, 197.5, 98).stroke();
159
+ this.doc.fontSize(5).text(`IDENTIFICAÇÃO DO EMITENTE`, 10, topIdentificacao_1 + 3.5, {
160
+ characterSpacing: 0.5,
161
+ });
162
+ this.doc.fontSize(8).font('Times-Bold').text(this.emit.xNome, 35, topIdentificacao_1 + 14, {
163
+ characterSpacing: 1,
164
+ width: 170,
165
+ lineBreak: true,
166
+ lineGap: 4
167
+ });
168
+ this.doc.fontSize(7).font('Times-Roman').text(`${this.emit.enderEmit.xLgr}, ${this.emit.enderEmit.nro} ${this.emit.xFant ? `- ${this.emit.xFant}` : ''}`, 10, topIdentificacao_1 + 44, {
169
+ characterSpacing: 1,
170
+ width: 181,
171
+ lineBreak: true,
172
+ lineGap: 2,
173
+ continued: true
174
+ }).text(identificationJoined);
175
+ };
176
+ /** IDENTIFICACAO NFe */
177
+ const _buildIdentificacaoDanfe = () => {
178
+ this.doc.rect(left + 197.5, topIdentificacao_1, 112.7, 98).stroke();
179
+ this.doc.fontSize(12).font('Times-Bold').text(`DANFE`, 203, topIdentificacao_1 + 8, {
180
+ characterSpacing: 1.5,
181
+ width: 112.7,
182
+ align: 'center'
183
+ });
184
+ this.doc.fontSize(6).text(`DOCUMENTO AUXILIAR DA NOTA FISCAL ELETRÔNICA`, 215, topIdentificacao_1 + 20, {
185
+ characterSpacing: 0.5,
186
+ width: 95,
187
+ align: 'left',
188
+ lineGap: 2,
189
+ });
190
+ this.doc.fontSize(8).font('Times-Roman').text(`0 - ENTRADA`, 217, topIdentificacao_1 + 40, {
191
+ characterSpacing: 0.5,
192
+ align: 'left',
193
+ });
194
+ this.doc.fontSize(8).text(`1 - SAÍDA`, 217, topIdentificacao_1 + 50, {
195
+ characterSpacing: 0.5,
196
+ align: 'left',
197
+ });
198
+ this.doc.rect(left + 275, topIdentificacao_1 + 38, 18, 18).stroke();
199
+ this.doc.fontSize(14).font('Times-Bold').text(String(this.ide.tpNF), left + 280, topIdentificacao_1 + 42.5);
200
+ this.doc.fontSize(8.8).text(`Nº ${String(this.ide.nNF).padStart(2, '0')}`, 208, topIdentificacao_1 + 65, {
201
+ characterSpacing: 1,
202
+ });
203
+ this.doc.fontSize(10).font('Times-Roman').text(`fl. ${page.start + 1}/${page.count}`, 240, topIdentificacao_1 + 65, {
204
+ characterSpacing: 1.5,
205
+ width: 112.7,
206
+ align: 'center'
207
+ });
208
+ this.doc.fontSize(8.8).text(`SÉRIE ${this.ide.serie.padStart(3, '0')}`, 208, topIdentificacao_1 + 78, {
209
+ characterSpacing: 1.5,
210
+ width: 112.7,
211
+ align: 'center'
212
+ });
213
+ };
214
+ /** IDENTIFICACAO NFe (Barcode e Chave) */
215
+ const _buildIdentificacaoNFe = () => {
216
+ this.doc.rect(left + 310.2, topIdentificacao_1, 256.73, 35).stroke();
217
+ if (this.barcodeBuffer) { // Verifica se o buffer do barcode existe
218
+ this.doc.image(this.barcodeBuffer, left + 323.5, topIdentificacao_1 + 3, { width: 230, height: 30 });
219
+ }
220
+ else {
221
+ this.doc.fontSize(8).fillColor('red').text('Erro ao carregar barcode', left + 316, topIdentificacao_1 + 12, {
222
+ width: 256.73, align: 'center'
223
+ });
224
+ }
225
+ if (Number(this.ide.tpAmb) !== 2 && !this.enviada && !this.data.forceTransmitida) {
226
+ this.doc.fontSize(14).font('Times-Bold').fillColor('red').text('NF-E NÃO ENVIADA PARA SEFAZ', left + 316, topIdentificacao_1 + 12, {
227
+ characterSpacing: 1,
228
+ width: 256.73,
229
+ });
230
+ }
231
+ this.setLineStyle(0.75, '#1c1c1c');
232
+ this.doc.rect(left + 310.2, topIdentificacao_1 + 35, 256.73, 23).stroke();
233
+ this.doc.fontSize(5).font('Times-Roman').text(`CHAVE DE ACESSO`, left + 314, topIdentificacao_1 + 38, {
234
+ characterSpacing: 0.5,
235
+ });
236
+ this.doc.fontSize(6).text(this.chave, left + 310.2, topIdentificacao_1 + 47, {
237
+ characterSpacing: 1,
238
+ width: 256.73,
239
+ align: 'center'
240
+ });
241
+ this.doc.rect(left + 310.2, topIdentificacao_1 + 58, 256.73, 40).stroke();
242
+ if (Number(this.ide.tpAmb) === 2 || this.enviada) {
243
+ this.doc.fontSize(6.5).text('Consulta de autenticidade no portal nacional da NF-e', left + 310.2, topIdentificacao_1 + 65, {
244
+ characterSpacing: 0.5,
245
+ width: 256.73,
246
+ align: 'center'
247
+ });
248
+ this.doc.fontSize(6.5).text('www.nfe.fazenda.gov.br/portal', left + 310.2, topIdentificacao_1 + 75, {
249
+ characterSpacing: 0.5,
250
+ width: 256.73,
251
+ align: 'center'
252
+ });
253
+ this.doc.fontSize(6.5).text('ou no site da Sefaz Autorizadora', left + 310.2, topIdentificacao_1 + 85, {
254
+ characterSpacing: 0.5,
255
+ width: 256.73,
256
+ align: 'center'
257
+ });
258
+ }
259
+ this.doc.rect(left, topIdentificacao_1 + 98, 310.2, 23).stroke();
260
+ this.doc.fontSize(5).text('NATUREZA DE OPERAÇÃO', left + 4, topIdentificacao_1 + 102, {
261
+ characterSpacing: 0.5,
262
+ });
263
+ this.doc.fontSize(8).text(this.ide.natOp, left + 4, topIdentificacao_1 + 112, {
264
+ characterSpacing: 1,
265
+ });
266
+ this.doc.rect(left + 310.2, topIdentificacao_1 + 98, 256.73, 23).stroke();
267
+ if (Number(this.ide.tpAmb) === 2 || this.enviada) {
268
+ let dhRecbto = '';
269
+ if (this.protNFe?.infProt.dhRecbto) {
270
+ dhRecbto = dateFns.format(new Date(this.protNFe?.infProt.dhRecbto), 'dd/MM/yyyy HH:mm:ss');
271
+ }
272
+ const xProtNfe = `${String(this.protNFe?.infProt.nProt || '')} ${dhRecbto}`;
273
+ this.doc.fontSize(5).text('PROTOCOLO DE AUTORIZAÇÃO DE USO', left + 314.2, topIdentificacao_1 + 102, {
274
+ characterSpacing: 0.5,
275
+ });
276
+ this.doc.fontSize(8).text(xProtNfe, left + 314.2, topIdentificacao_1 + 112, {
277
+ characterSpacing: 1,
278
+ });
279
+ }
280
+ };
281
+ /** IDENTIFICACAO PESSOA */
282
+ const _buildIdentificacaoPessoa = () => {
283
+ this.doc.rect(left, topIdentificacao_1 + 121, 189.5, 23).stroke();
284
+ this.doc.fontSize(5).text('INSCRIÇÃO ESTADUAL', left + 4, topIdentificacao_1 + 125, {
285
+ characterSpacing: 0.5,
286
+ });
287
+ this.doc.fontSize(8).text(this.emit.IE, left + 5, topIdentificacao_1 + 135, {
288
+ characterSpacing: 1,
289
+ });
290
+ this.doc.rect(left + 189.5, topIdentificacao_1 + 121, 187.93, 23).stroke();
291
+ this.doc.fontSize(5).text('INSCRIÇÃO ESTADUAL DO SUBST. TRIB.', left + 193.5, topIdentificacao_1 + 125, {
292
+ characterSpacing: 0.5,
293
+ });
294
+ this.doc.fontSize(8).text(String(this.emit.IEST || ''), left + 194.5, topIdentificacao_1 + 135, {
295
+ characterSpacing: 1,
296
+ });
297
+ this.doc.rect(left + 377.43, topIdentificacao_1 + 121, 189.5, 23).stroke();
298
+ this.doc.fontSize(5).text('CNPJ / CPF', left + 381.43, topIdentificacao_1 + 125, {
299
+ characterSpacing: 0.5,
300
+ });
301
+ this.doc.fontSize(8).text(documento, left + 386.43, topIdentificacao_1 + 135, {
302
+ characterSpacing: 1,
303
+ });
304
+ };
305
+ _buildIdentificacaoEmit();
306
+ _buildIdentificacaoDanfe();
307
+ _buildIdentificacaoNFe();
308
+ _buildIdentificacaoPessoa();
309
+ }
310
+ _buildDestinatario() {
311
+ const { top, left } = this.doc.page.margins;
312
+ const docDest = this.documento.mascaraCnpjCpf(this.dest?.CNPJCPF || this.dest?.CNPJ || this.dest?.CPF || '');
313
+ this.setLineStyle(0.75, '#1c1c1c');
314
+ const topDestinatario = top + 90;
315
+ const _buildDestPessoa = () => {
316
+ this.doc.rect(left, topDestinatario + 120, 398, 23).stroke();
317
+ let xNome = 'NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
318
+ if (Number(this.ide.tpAmb) !== 2) {
319
+ xNome = String(this.dest?.xNome || '');
320
+ }
321
+ this.doc.fontSize(5).font('Times-Roman').text('NOME / RAZÃO SOCIAL', left + 4, topDestinatario + 125, {
322
+ characterSpacing: 0.5,
323
+ });
324
+ this.doc.fontSize(8).text(xNome, left + 5, topDestinatario + 135, {
325
+ characterSpacing: 1,
326
+ });
327
+ this.doc.rect(left + 398, topDestinatario + 120, 94, 23).stroke();
328
+ this.doc.fontSize(5).text('CNPJ / CPF', left + 402, topDestinatario + 125, {
329
+ characterSpacing: 0.5,
330
+ });
331
+ this.doc.fontSize(8).text(docDest, left + 403, topDestinatario + 135, {
332
+ characterSpacing: 1,
333
+ });
334
+ this.doc.rect(left + 492, topDestinatario + 120, 74.3, 23).stroke();
335
+ this.doc.fontSize(5).text('DATA DA EMISSÃO', left + 496, topDestinatario + 125, {
336
+ characterSpacing: 0.5,
337
+ });
338
+ this.doc.fontSize(8).text(dateFns.format(new Date(this.ide.dhEmi), 'dd-MM-yyyy'), left + 497, topDestinatario + 135, {
339
+ characterSpacing: 1,
340
+ });
341
+ };
342
+ const _buildDestLogradouro = () => {
343
+ this.doc.rect(left, topDestinatario + 143, 320, 23).stroke();
344
+ this.doc.fontSize(5).text('ENDEREÇO', left + 4, topDestinatario + 148, {
345
+ characterSpacing: 0.5,
346
+ });
347
+ this.doc.fontSize(8).text(`${this.dest?.enderDest?.xLgr || ''}, ${this.dest?.enderDest?.nro || ''}`, left + 5, topDestinatario + 158, {
348
+ characterSpacing: 1,
349
+ });
350
+ this.doc.rect(left + 320, topDestinatario + 143, 118.5, 23).stroke();
351
+ this.doc.fontSize(5).text('BAIRRO / DISTRITO', left + 324, topDestinatario + 148, {
352
+ characterSpacing: 0.5,
353
+ });
354
+ const bairroText = String(this.dest?.enderDest?.xBairro || '');
355
+ const bairroCharLimit = 22;
356
+ const bairroMaxWidthForText = 110; // Largura útil para o texto dentro da célula
357
+ const defaultBairroFontSize = 8;
358
+ const reducedBairroFontSize = 5.5;
359
+ const defaultBairroCharSpacing = 1;
360
+ const reducedBairroCharSpacing = 0.25;
361
+ let fontSizeToUse = defaultBairroFontSize;
362
+ let charSpacingToUse = defaultBairroCharSpacing;
363
+ if (bairroText.length > bairroCharLimit) {
364
+ fontSizeToUse = reducedBairroFontSize;
365
+ charSpacingToUse = reducedBairroCharSpacing;
366
+ }
367
+ // Cálculo de Y para tentar alinhar (pode precisar de ajuste fino)
368
+ const textLineHeight = this.doc.currentLineHeight(); // Altura da linha com fontSizeToUse
369
+ const cellContentYBase = topDestinatario + 158; // Linha de base original
370
+ const cellHeightForText = 23 - 5 - 5; // Altura da célula - padding label - padding inferior
371
+ let yPosForBairro = cellContentYBase;
372
+ // Ajuste simples para tentar centralizar um pouco se a linha for mais baixa que o espaço
373
+ if (textLineHeight < cellHeightForText) {
374
+ yPosForBairro = cellContentYBase - ((cellHeightForText - textLineHeight) / 2) + (textLineHeight * 0.3); // ajuste
375
+ }
376
+ // Ajuste fino para alinhar com os outros campos na mesma linha Y
377
+ yPosForBairro = topDestinatario + 158; // Reset para a mesma linha Y dos outros campos
378
+ this.doc.font('Times-Roman').fontSize(fontSizeToUse);
379
+ this.doc.text(bairroText, left + 320 + 3, yPosForBairro, {
380
+ characterSpacing: charSpacingToUse,
381
+ width: bairroMaxWidthForText,
382
+ lineBreak: false,
383
+ ellipsis: true,
384
+ });
385
+ this.doc.font('Times-Roman').fontSize(8);
386
+ this.doc.rect(left + 438.5, topDestinatario + 143, 53.5, 23).stroke();
387
+ this.doc.fontSize(5).text('CEP', left + 442.5, topDestinatario + 148, {
388
+ characterSpacing: 0.5,
389
+ });
390
+ this.doc.fontSize(8).text(String(this.dest?.enderDest?.CEP || ''), left + 443.5, topDestinatario + 158, {
391
+ characterSpacing: 1,
392
+ });
393
+ this.doc.rect(left + 492, topDestinatario + 143, 74.3, 23).stroke();
394
+ this.doc.fontSize(5).text('DATA SAÍDA / ENTRADA', left + 496, topDestinatario + 148, {
395
+ characterSpacing: 0.5,
396
+ });
397
+ this.doc.fontSize(8).text(dateFns.format(new Date(), 'dd-MM-yyyy'), left + 497, topDestinatario + 158, {
398
+ characterSpacing: 1,
399
+ });
400
+ };
401
+ const _buildDestEndereco = () => {
402
+ this.doc.rect(left, topDestinatario + 166, 246.5, 23).stroke();
403
+ this.doc.fontSize(5).text('MUNICÍPIO', left + 4, topDestinatario + 171, {
404
+ characterSpacing: 0.5,
405
+ });
406
+ this.doc.fontSize(8).text(String(this.dest?.enderDest?.xMun || ''), left + 5, topDestinatario + 181, {
407
+ characterSpacing: 1,
408
+ });
409
+ this.doc.rect(left + 246.5, topDestinatario + 166, 113, 23).stroke();
410
+ this.doc.fontSize(5).text('FONE / FAX', left + 250.5, topDestinatario + 171, {
411
+ characterSpacing: 0.5,
412
+ });
413
+ this.doc.fontSize(8).text(this.dest?.enderDest?.fone || '', left + 250.5, topDestinatario + 181, {
414
+ characterSpacing: 1,
415
+ });
416
+ this.doc.rect(left + 359.5, topDestinatario + 166, 40, 23).stroke();
417
+ this.doc.fontSize(5).text('UF', left + 363.5, topDestinatario + 171, {
418
+ characterSpacing: 0.5,
419
+ });
420
+ this.doc.fontSize(8).text(String(this.dest?.enderDest?.UF || ''), left + 363.5, topDestinatario + 181, {
421
+ characterSpacing: 1,
422
+ });
423
+ this.doc.rect(left + 399.5, topDestinatario + 166, 92.5, 23).stroke();
424
+ this.doc.fontSize(5).text('INSCRIÇÃO ESTADUAL', left + 403.5, topDestinatario + 171, {
425
+ characterSpacing: 0.5,
426
+ });
427
+ this.doc.fontSize(8).text(String(this.dest?.indIEDest || ''), left + 403.5, topDestinatario + 181, {
428
+ characterSpacing: 1,
429
+ });
430
+ this.doc.rect(left + 492, topDestinatario + 166, 74.3, 23).stroke();
431
+ this.doc.fontSize(5).text('HORA DA SAÍDA', left + 496, topDestinatario + 171, {
432
+ characterSpacing: 0.5,
433
+ });
434
+ this.doc.fontSize(8).text(dateFns.format(new Date(), 'HH:mm'), left + 497, topDestinatario + 181, {
435
+ characterSpacing: 1,
436
+ });
437
+ };
438
+ this.doc.fontSize(6).font('Times-Bold').text('DESTINATÁRIO / REMETENTE', left, topDestinatario + 114, {
439
+ characterSpacing: 0.5,
440
+ });
441
+ _buildDestPessoa();
442
+ _buildDestLogradouro();
443
+ _buildDestEndereco();
444
+ }
445
+ _builCalculoImposto() {
446
+ const { top, left } = this.doc.page.margins;
447
+ this.setLineStyle(0.75, '#1c1c1c');
448
+ const topDestinatario = top + 173;
449
+ const _buildCalcImposto = () => {
450
+ /** LINHA 1 */
451
+ this.doc.rect(left, topDestinatario + 120, 86, 23).stroke();
452
+ this.doc.fontSize(5).font('Times-Roman').text('BASE DE CÁLCULO DO ICMS', left + 4, topDestinatario + 125, {
453
+ characterSpacing: 0.5,
454
+ });
455
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vBC)).toFixed(2), left - 8, topDestinatario + 135, {
456
+ characterSpacing: 1,
457
+ align: 'right',
458
+ width: 86
459
+ });
460
+ this.doc.rect(left + 86, topDestinatario + 120, 79, 23).stroke();
461
+ this.doc.fontSize(5).text('VALOR DO ICMS', left + 90, topDestinatario + 125, {
462
+ characterSpacing: 0.5,
463
+ });
464
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vICMS)).toFixed(2), left + 86 - 16, topDestinatario + 135, {
465
+ characterSpacing: 1,
466
+ align: 'right',
467
+ width: 86
468
+ });
469
+ this.doc.rect(left + 165, topDestinatario + 120, 79, 23).stroke();
470
+ this.doc.fontSize(5).text('BASE CÁLC. ICMS SUBST', left + 169, topDestinatario + 125, {
471
+ characterSpacing: 0.5,
472
+ });
473
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vBCST)).toFixed(2), left + 165 - 16, topDestinatario + 135, {
474
+ characterSpacing: 1,
475
+ align: 'right',
476
+ width: 86
477
+ });
478
+ this.doc.rect(left + 244, topDestinatario + 120, 79, 23).stroke();
479
+ this.doc.fontSize(5).text('VALOR DO ICMS SUBST.', left + 248, topDestinatario + 125, {
480
+ characterSpacing: 0.5,
481
+ });
482
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vST)).toFixed(2), left + 244 - 16, topDestinatario + 135, {
483
+ characterSpacing: 1,
484
+ align: 'right',
485
+ width: 86
486
+ });
487
+ this.doc.rect(left + 323, topDestinatario + 120, 91, 23).stroke();
488
+ this.doc.fontSize(5).text('VALOR APROX. DOS TRIBUTOS', left + 327, topDestinatario + 125, {
489
+ characterSpacing: 0.5,
490
+ });
491
+ this.doc.fontSize(8).text(parseFloat(this.total.ICMSTot.vTotTrib || '0').toFixed(2), left + 323 - 6, topDestinatario + 135, {
492
+ characterSpacing: 1,
493
+ align: 'right',
494
+ width: 86
495
+ });
496
+ this.doc.rect(left + 414, topDestinatario + 120, 152.93, 23).fillAndStroke('#DDDDDD', '#1c1c1c');
497
+ this.setLineStyle(0.75, '#1c1c1c');
498
+ this.doc.fontSize(5).text('VALOR TOTAL DOS PRODUTOS', left + 418, topDestinatario + 125, {
499
+ characterSpacing: 0.5,
500
+ });
501
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vProd)).toFixed(2), left + 480 - 8, topDestinatario + 135, {
502
+ characterSpacing: 1,
503
+ align: 'right',
504
+ width: 86
505
+ });
506
+ /** LINHA 2 */
507
+ this.doc.rect(left, topDestinatario + 143, 86, 23).stroke();
508
+ this.doc.fontSize(5).text('VALOR DO FRETE', left + 4, topDestinatario + 148, {
509
+ characterSpacing: 0.5,
510
+ });
511
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vFrete)).toFixed(2), left - 8, topDestinatario + 158, {
512
+ characterSpacing: 1,
513
+ align: 'right',
514
+ width: 86
515
+ });
516
+ this.doc.rect(left + 86, topDestinatario + 143, 79, 23).stroke();
517
+ this.doc.fontSize(5).text('VALOR DO SEGURO', left + 90, topDestinatario + 148, {
518
+ characterSpacing: 0.5,
519
+ });
520
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vSeg)).toFixed(2), left + 86 - 16, topDestinatario + 158, {
521
+ characterSpacing: 1,
522
+ align: 'right',
523
+ width: 86
524
+ });
525
+ this.doc.rect(left + 165, topDestinatario + 143, 79, 23).stroke();
526
+ this.doc.fontSize(5).text('DESCONTO', left + 169, topDestinatario + 148, {
527
+ characterSpacing: 0.5,
528
+ });
529
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vDesc)).toFixed(2), left + 165 - 16, topDestinatario + 158, {
530
+ characterSpacing: 1,
531
+ align: 'right',
532
+ width: 86
533
+ });
534
+ this.doc.rect(left + 244, topDestinatario + 143, 79, 23).stroke();
535
+ this.doc.fontSize(5).text('OUTRAS DESP. ACESS.', left + 248, topDestinatario + 148, {
536
+ characterSpacing: 0.5,
537
+ });
538
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vOutro)).toFixed(2), left + 244 - 16, topDestinatario + 158, {
539
+ characterSpacing: 1,
540
+ align: 'right',
541
+ width: 86
542
+ });
543
+ this.doc.rect(left + 323, topDestinatario + 143, 91, 23).stroke();
544
+ this.doc.fontSize(5).text('VALOR DO IPI', left + 327, topDestinatario + 148, {
545
+ characterSpacing: 0.5,
546
+ });
547
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vIPI)).toFixed(2), left + 323 - 6, topDestinatario + 158, {
548
+ characterSpacing: 1,
549
+ align: 'right',
550
+ width: 86
551
+ });
552
+ this.doc.rect(left + 414, topDestinatario + 143, 152.93, 23).fillAndStroke('#DDDDDD', '#1c1c1c');
553
+ this.setLineStyle(0.75, '#1c1c1c');
554
+ this.doc.fontSize(5).text('VALOR TOTAL DA NOTA', left + 418, topDestinatario + 148, {
555
+ characterSpacing: 0.5,
556
+ });
557
+ this.doc.fontSize(8).text(parseFloat(String(this.total.ICMSTot.vNF)).toFixed(2), left + 480 - 8, topDestinatario + 158, {
558
+ characterSpacing: 1,
559
+ align: 'right',
560
+ width: 86
561
+ });
562
+ };
563
+ this.doc.fontSize(6).font('Times-Bold').text('CÁLCULO DO IMPOSTO', left, topDestinatario + 114, {
564
+ characterSpacing: 0.5,
565
+ });
566
+ _buildCalcImposto();
567
+ }
568
+ _builTransporte() {
569
+ const { top, left } = this.doc.page.margins;
570
+ this.setLineStyle(0.75, '#1c1c1c');
571
+ const topDestinatario = top + 233;
572
+ const getModFrete = () => {
573
+ // * 0=Contratação do Frete por conta do Remetente (CIF)
574
+ // * 1=Contratação do Frete por conta do Destinatário (FOB)
575
+ // * 2=Contratação do Frete por conta de Terceiros
576
+ // * 3=Transporte Próprio por conta do Remetente
577
+ // * 4=Transporte Próprio por conta do Destinatário
578
+ // * 9=Sem Ocorrência de Transporte. (Atualizado na NT 2016/002)
579
+ const modFrete = parseInt(String(this.transp.modFrete));
580
+ switch (modFrete) {
581
+ case 0:
582
+ return `${modFrete} - REMETENTE`;
583
+ case 1:
584
+ return `${modFrete} - DESTINATÁRIO`;
585
+ case 2:
586
+ return `${modFrete} - TERCEIROS`;
587
+ case 3:
588
+ return `${modFrete} - REMETENTE`;
589
+ case 4:
590
+ return `${modFrete} - DESTINATÁRIO`;
591
+ case 9:
592
+ return `${modFrete} - SEM FRETE`;
593
+ default:
594
+ return '';
595
+ }
596
+ };
597
+ const _buildVolumeTransporte = () => {
598
+ if (this.transp.vol) {
599
+ /** Posição da primeira linha */
600
+ let topTrnasport = topDestinatario + 166;
601
+ let topTrnasportTitle = topDestinatario + 171;
602
+ let topTrnasportValue = topDestinatario + 181;
603
+ const createVolume = (vol) => {
604
+ this.doc.rect(left, topTrnasport, 68.5, 23).stroke();
605
+ this.doc.fontSize(5).text('QUANTIDADE', left + 4, topTrnasportTitle, {
606
+ characterSpacing: 0.5,
607
+ });
608
+ this.doc.fontSize(8).text(String(vol?.qVol || ''), left - 8, topTrnasportValue, {
609
+ characterSpacing: 1,
610
+ align: 'right',
611
+ width: 68.5
612
+ });
613
+ this.doc.rect(left + 68.5, topTrnasport, 100.5, 23).stroke();
614
+ this.doc.fontSize(5).text('ESPÉCIE', left + 72.5, topTrnasportTitle, {
615
+ characterSpacing: 0.5,
616
+ });
617
+ this.doc.fontSize(8).text(String(vol?.esp || ''), left + 73.5, topTrnasportValue, {
618
+ characterSpacing: 1,
619
+ });
620
+ this.doc.rect(left + 169, topTrnasport, 100.5, 23).stroke();
621
+ this.doc.fontSize(5).text('MARCA', left + 173, topTrnasportTitle, {
622
+ characterSpacing: 0.5,
623
+ });
624
+ this.doc.fontSize(8).text(String(vol?.marca || ''), left + 174, topTrnasportValue, {
625
+ characterSpacing: 1,
626
+ });
627
+ this.doc.rect(left + 269.5, topTrnasport, 100.5, 23).stroke();
628
+ this.doc.fontSize(5).text('NUMERAÇÃO', left + 273.5, topTrnasportTitle, {
629
+ characterSpacing: 0.5,
630
+ });
631
+ this.doc.fontSize(8).text(String(vol?.nVol || ''), left + 274.5, topTrnasportValue, {
632
+ characterSpacing: 1,
633
+ });
634
+ this.doc.rect(left + 370, topTrnasport, 102.6, 23).stroke();
635
+ this.doc.fontSize(5).text('PESO BRUTO', left + 374, topTrnasportTitle, {
636
+ characterSpacing: 0.5,
637
+ });
638
+ this.doc.fontSize(8).text(String(vol?.nVol || ''), left + 375, topTrnasportValue, {
639
+ characterSpacing: 1,
640
+ });
641
+ //96,43
642
+ this.doc.rect(left + 472.5, topTrnasport, 94.43, 23).stroke();
643
+ this.doc.fontSize(5).text('PESO LÍQUIDO', left + 474.5, topTrnasportTitle, {
644
+ characterSpacing: 0.5,
645
+ });
646
+ this.doc.fontSize(8).text(String(vol?.nVol || ''), left + 475.5, topTrnasportValue, {
647
+ characterSpacing: 1,
648
+ });
649
+ /** Define posição da nova linha */
650
+ topTrnasport = topTrnasport + 23;
651
+ topTrnasportTitle = topTrnasportTitle + 23;
652
+ topTrnasportValue = topTrnasportValue + 23;
653
+ };
654
+ if (this.transp.vol instanceof Array) {
655
+ for (let vol of this.transp.vol) {
656
+ createVolume(vol);
657
+ }
658
+ }
659
+ else {
660
+ createVolume(this.transp.vol);
661
+ }
662
+ }
663
+ };
664
+ const _buildCalcImposto = () => {
665
+ const documento = this.documento.mascaraCnpjCpf(this.transp.transporta?.CNPJCPF || this.transp.transporta?.CNPJ || this.transp.transporta?.CPF || '');
666
+ /** LINHA 1 */
667
+ this.doc.rect(left, topDestinatario + 120, 248.5, 23).stroke();
668
+ this.doc.fontSize(5).font('Times-Roman').text('RAZÃO SOCIAL', left + 4, topDestinatario + 125, {
669
+ characterSpacing: 0.5,
670
+ });
671
+ this.doc.fontSize(8).text(this.transp.transporta?.xNome || '', left + 5, topDestinatario + 135, {
672
+ characterSpacing: 1,
673
+ width: 246
674
+ });
675
+ this.doc.rect(left + 248.5, topDestinatario + 120, 90, 23).stroke();
676
+ this.doc.fontSize(5).text('FRETE POR CONTA', left + 252.5, topDestinatario + 125, {
677
+ characterSpacing: 0.5,
678
+ });
679
+ this.doc.fontSize(8).text(getModFrete(), left + 253.5, topDestinatario + 135, {
680
+ characterSpacing: 1,
681
+ });
682
+ this.doc.rect(left + 338.5, topDestinatario + 120, 50, 23).stroke();
683
+ this.doc.fontSize(5).text('CÓDIGO ANTT', left + 342.5, topDestinatario + 125, {
684
+ characterSpacing: 0.5,
685
+ });
686
+ this.doc.fontSize(8).text(this.transp?.veicTransp?.RNTC || '', left + 343.5, topDestinatario + 135, {
687
+ characterSpacing: 1,
688
+ });
689
+ this.doc.rect(left + 388.5, topDestinatario + 120, 62, 23).stroke();
690
+ this.doc.fontSize(5).text('PLACA DO VEÍCULO', left + 391.5, topDestinatario + 125, {
691
+ characterSpacing: 0.5,
692
+ });
693
+ this.doc.fontSize(8).text(this.transp?.veicTransp?.placa || '', left + 393.5, topDestinatario + 135, {
694
+ characterSpacing: 1,
695
+ });
696
+ this.doc.rect(left + 450.5, topDestinatario + 120, 22, 23).stroke();
697
+ this.doc.fontSize(5).text('UF', left + 454.5, topDestinatario + 125, {
698
+ characterSpacing: 0.5,
699
+ });
700
+ this.doc.fontSize(8).text(this.transp?.transporta?.UF || '', left + 455.5, topDestinatario + 135, {
701
+ characterSpacing: 1,
702
+ });
703
+ this.doc.rect(left + 472.5, topDestinatario + 120, 94.43, 23).stroke();
704
+ this.doc.fontSize(5).text('CNPJ / CPF', left + 476.5, topDestinatario + 125, {
705
+ characterSpacing: 0.5,
706
+ });
707
+ this.doc.fontSize(8).text(documento, left + 477.5, topDestinatario + 135, {
708
+ characterSpacing: 1,
709
+ });
710
+ /** LINHA 2 */
711
+ this.doc.rect(left, topDestinatario + 143, 338.5, 23).stroke();
712
+ this.doc.fontSize(5).text('ENDEREÇO', left + 4, topDestinatario + 148, {
713
+ characterSpacing: 0.5,
714
+ });
715
+ this.doc.fontSize(8).text(this.transp.transporta?.xEnder || '', left + 4, topDestinatario + 158, {
716
+ characterSpacing: 1,
717
+ });
718
+ this.doc.rect(left + 338.5, topDestinatario + 143, 112, 23).stroke();
719
+ this.doc.fontSize(5).text('MUNICÍPIO', left + 342.5, topDestinatario + 148, {
720
+ characterSpacing: 0.5,
721
+ });
722
+ this.doc.fontSize(8).text(this.transp.transporta?.xMun || '', left + 343.5, topDestinatario + 158, {
723
+ characterSpacing: 1,
724
+ });
725
+ this.doc.rect(left + 450.5, topDestinatario + 143, 22, 23).stroke();
726
+ this.doc.fontSize(5).text('UF', left + 454.5, topDestinatario + 148, {
727
+ characterSpacing: 0.5,
728
+ });
729
+ this.doc.fontSize(8).text(this.transp?.transporta?.UF || '', left + 455.5, topDestinatario + 158, {
730
+ characterSpacing: 1,
731
+ });
732
+ this.doc.rect(left + 472.5, topDestinatario + 143, 94.43, 23).stroke();
733
+ this.doc.fontSize(5).text('INSCRIÇÃO ESTADUAL', left + 476.5, topDestinatario + 148, {
734
+ characterSpacing: 0.5,
735
+ });
736
+ this.doc.fontSize(8).text(this.transp?.transporta?.IE || '', left + 476.5, topDestinatario + 158, {
737
+ characterSpacing: 1,
738
+ });
739
+ };
740
+ this.doc.fontSize(6).font('Times-Bold').text('TRANSPORTADOR / VOLUMES TRANSPORTADOS', left, topDestinatario + 114, {
741
+ characterSpacing: 0.5,
742
+ });
743
+ _buildCalcImposto();
744
+ _buildVolumeTransporte();
745
+ }
746
+ _buildProdutos() {
747
+ const { left } = this.doc.page.margins;
748
+ this.setLineStyle(0.75, '#1c1c1c');
749
+ this.doc.fontSize(6).font('Times-Bold').fillColor('black').text('DADOS DO PRODUTO / SERVIÇOS', left, 452, {
750
+ characterSpacing: 0.5,
751
+ });
752
+ const tableTop = 458;
753
+ const defaultItemHeight = 15;
754
+ let y = tableTop;
755
+ let currentPage = 0;
756
+ const header = (top) => {
757
+ this.doc.rect(left, top, 40, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
758
+ this.setLineStyle(0.75, '#1c1c1c');
759
+ this.doc.font('Times-Roman').fontSize(5.7).text('CÓDIGO DO PROD. / SERV', left, top + 2.8, {
760
+ width: 40,
761
+ align: 'center',
762
+ });
763
+ this.doc.rect(left + 40, top, 138, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
764
+ this.setLineStyle(0.75, '#1c1c1c');
765
+ this.doc.text('DESCRIÇÃO DO PRODUTO / SERVIÇO', left + 40, top + 5.9, {
766
+ width: 138,
767
+ align: 'center'
768
+ });
769
+ this.doc.rect(left + 178, top, 30, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
770
+ this.setLineStyle(0.75, '#1c1c1c');
771
+ this.doc.text('NCM / SH', left + 178, top + 5.9, {
772
+ width: 30,
773
+ align: 'center'
774
+ });
775
+ this.doc.rect(left + 208, top, 17, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
776
+ this.setLineStyle(0.75, '#1c1c1c');
777
+ this.doc.text('CST', left + 208, top + 5.9, {
778
+ width: 17,
779
+ align: 'center'
780
+ });
781
+ this.doc.rect(left + 225, top, 28, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
782
+ this.setLineStyle(0.75, '#1c1c1c');
783
+ this.doc.text('CFOP', left + 225, top + 5.9, {
784
+ width: 28,
785
+ align: 'center'
786
+ });
787
+ this.doc.rect(left + 253, top, 23, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
788
+ this.setLineStyle(0.75, '#1c1c1c');
789
+ this.doc.text('UNID.', left + 253, top + 5.9, {
790
+ width: 23,
791
+ align: 'center'
792
+ });
793
+ this.doc.rect(left + 276, top, 25, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
794
+ this.setLineStyle(0.75, '#1c1c1c');
795
+ this.doc.text('QUANT.', left + 276, top + 5.9, {
796
+ width: 25,
797
+ align: 'center'
798
+ });
799
+ this.doc.rect(left + 301, top, 37.23, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
800
+ this.setLineStyle(0.75, '#1c1c1c');
801
+ this.doc.text('VALOR UNITÁRIO', left + 301, top + 2.9, {
802
+ width: 37.23,
803
+ align: 'center'
804
+ });
805
+ this.doc.rect(left + 338.23, top, 39.23, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
806
+ this.setLineStyle(0.75, '#1c1c1c');
807
+ this.doc.text('VALOR DESCONTO', left + 338.23, top + 2.9, {
808
+ width: 39.23,
809
+ align: 'center'
810
+ });
811
+ this.doc.rect(left + 377.46, top, 33.23, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
812
+ this.setLineStyle(0.75, '#1c1c1c');
813
+ this.doc.text('VALOR LIQUIDO', left + 377.46, top + 2.9, {
814
+ width: 33.23,
815
+ align: 'center'
816
+ });
817
+ this.doc.rect(left + 410.69, top, 38, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
818
+ this.setLineStyle(0.75, '#1c1c1c');
819
+ this.doc.text('BASE CÁLC. ICMS', left + 413.8, top + 2.9, {
820
+ width: 32,
821
+ align: 'center'
822
+ });
823
+ this.doc.rect(left + 448.69, top, 35, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
824
+ this.setLineStyle(0.75, '#1c1c1c');
825
+ this.doc.text('VALOR I.C.M.S.', left + 448.69, top + 2.9, {
826
+ width: 35,
827
+ align: 'center'
828
+ });
829
+ this.doc.rect(left + 483.69, top, 38, defaultItemHeight).fillAndStroke('#DDDDDD', '#1c1c1c');
830
+ this.setLineStyle(0.75, '#1c1c1c');
831
+ this.doc.text('VALOR I.P.I.', left + 490.69, top + 2.9, {
832
+ width: 25,
833
+ align: 'center'
834
+ });
835
+ this.doc.rect(left + 521.69, top, 45.2, 7.5).fillAndStroke('#DDDDDD', '#1c1c1c');
836
+ this.setLineStyle(0.75, '#1c1c1c');
837
+ this.doc.text('ALÍQUOTAS', left + 521.69, top + 2, {
838
+ width: 45,
839
+ align: 'center'
840
+ });
841
+ this.doc.rect(left + 521.69, top + 7.5, 22.5, 7.5).fillAndStroke('#DDDDDD', '#1c1c1c');
842
+ this.setLineStyle(0.75, '#1c1c1c');
843
+ this.doc.text('ICMS', left + 521.69, top + 9.5, {
844
+ width: 22.5,
845
+ align: 'center'
846
+ });
847
+ this.doc.rect(left + 544.19, top + 7.5, 22.75, 7.5).fillAndStroke('#DDDDDD', '#1c1c1c');
848
+ this.setLineStyle(0.75, '#1c1c1c');
849
+ this.doc.text('IPI', left + 544.19, top + 9.5, {
850
+ width: 22.5,
851
+ align: 'center'
852
+ });
853
+ };
854
+ const row = (top, item) => {
855
+ function getCST(ICMS) {
856
+ const chavesICMS = Object.keys(ICMS);
857
+ const listaIcmsSemCST = [
858
+ 'ICMSSN101',
859
+ 'ICMSSN102',
860
+ 'ICMSSN201',
861
+ 'ICMSSN202',
862
+ 'ICMSSN500',
863
+ 'ICMSSN900'
864
+ ];
865
+ const icmsSemCST = listaIcmsSemCST.includes(chavesICMS[0]);
866
+ let CST = '';
867
+ if (chavesICMS.length > 0) {
868
+ const tipoICMS = chavesICMS[0];
869
+ if (!icmsSemCST) {
870
+ CST = ICMS[tipoICMS].CST;
871
+ }
872
+ }
873
+ return CST;
874
+ }
875
+ function getValoresItem(ICMS) {
876
+ const chavesICMS = Object.keys(ICMS);
877
+ const listaIcmsSemvBC = [
878
+ 'ICMS02',
879
+ 'ICMS15',
880
+ 'ICMS30',
881
+ 'ICMS40',
882
+ 'ICMS53',
883
+ 'ICMS60',
884
+ 'ICMS61',
885
+ 'ICMSST',
886
+ 'ICMSSN101',
887
+ 'ICMSSN102',
888
+ 'ICMSSN201',
889
+ 'ICMSSN202',
890
+ 'ICMSSN500'
891
+ ];
892
+ const icmsSemvBC = listaIcmsSemvBC.includes(chavesICMS[0]);
893
+ let vBC = '0,00';
894
+ let vICMS = '0,00';
895
+ let pICMS = '0,00';
896
+ if (chavesICMS.length > 0) {
897
+ const tipoICMS = chavesICMS[0];
898
+ if (!icmsSemvBC) {
899
+ vBC = ICMS[tipoICMS].vBC;
900
+ vICMS = ICMS[tipoICMS].vICMS;
901
+ pICMS = ICMS[tipoICMS].pICMS;
902
+ return {
903
+ vBC: parseFloat(vBC).toFixed(2),
904
+ vICMS: parseFloat(vBC).toFixed(2),
905
+ pICMS: parseFloat(pICMS).toFixed(2)
906
+ };
907
+ }
908
+ }
909
+ return { vBC, vICMS, pICMS };
910
+ }
911
+ function getValoresIPI(IPI) {
912
+ if (!IPI) {
913
+ return {
914
+ vIPI: '0,00',
915
+ pIPI: '0,00'
916
+ };
917
+ }
918
+ let vIPI = parseFloat(String(IPI.IPITrib.vIPI)).toFixed(2);
919
+ let pIPI = parseFloat(String(IPI.IPITrib.pIPI)).toFixed(2);
920
+ return { vIPI, pIPI };
921
+ }
922
+ const CST = getCST(item.imposto.ICMS);
923
+ const { vIPI, pIPI } = getValoresIPI(item.imposto.IPI);
924
+ const { vBC, vICMS, pICMS } = getValoresItem(item.imposto.ICMS);
925
+ const text = item.infAdProd ? `${item.prod.xProd || ''}\n${item.infAdProd}` : item.prod.xProd || '';
926
+ const textHeight = this.doc.heightOfString(text, {
927
+ width: 138,
928
+ align: 'center'
929
+ });
930
+ const itemHeight = Math.max(defaultItemHeight, textHeight + 10); // 10 is padding
931
+ this.setLineStyle(0.75, '#1c1c1c');
932
+ this.doc.rect(left, top, 40, itemHeight).stroke();
933
+ this.doc.font('Times-Roman').fontSize(6).text(item.prod.cProd || '', left + 2, top + 3, {
934
+ width: 40,
935
+ });
936
+ this.doc.rect(left + 40, top, 138, itemHeight).stroke();
937
+ this.doc.text(text, left + 43, top + 4, {
938
+ width: 137,
939
+ });
940
+ this.doc.rect(left + 178, top, 30, itemHeight).stroke();
941
+ this.doc.text(String(item.prod.NCM) || '', left + 178, top + 5.9, {
942
+ width: 30,
943
+ align: 'center'
944
+ });
945
+ this.doc.rect(left + 208, top, 17, itemHeight).stroke();
946
+ this.doc.text(CST, left + 208, top + 5.9, {
947
+ width: 17,
948
+ align: 'center'
949
+ });
950
+ this.doc.rect(left + 225, top, 28, itemHeight).stroke();
951
+ this.doc.text(String(item.prod.CFOP || ''), left + 225, top + 5.9, {
952
+ width: 28,
953
+ align: 'center'
954
+ });
955
+ this.doc.rect(left + 253, top, 23, itemHeight).stroke();
956
+ this.doc.text(item.prod.uCom || item.prod.uTrib || '', left + 256, top + 5.9, {
957
+ width: 23,
958
+ });
959
+ const quant = parseFloat(String(item.prod.qCom || item.prod.qTrib)).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
960
+ this.doc.rect(left + 276, top, 25, itemHeight).stroke();
961
+ this.doc.text(String(quant || ''), left + 274.5, top + 5.9, {
962
+ width: 25,
963
+ align: 'right'
964
+ });
965
+ const valUnit = parseFloat(String(item.prod.vUnCom || item.prod.vUnTrib || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
966
+ this.doc.rect(left + 301, top, 37.23, itemHeight).stroke();
967
+ this.doc.text(valUnit, left + 299.5, top + 5.9, {
968
+ width: 37.23,
969
+ align: 'right'
970
+ });
971
+ const valDesc = parseFloat(String(item.prod.vDesc || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
972
+ this.doc.rect(left + 338.23, top, 39.23, itemHeight).stroke();
973
+ this.doc.text(valDesc, left + 336.73, top + 5.9, {
974
+ width: 39.23,
975
+ align: 'right'
976
+ });
977
+ const valLiq = parseFloat(String(item.prod.vProd || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
978
+ this.doc.rect(left + 377.46, top, 33.23, itemHeight).stroke();
979
+ this.doc.text(valLiq, left + 375.96, top + 5.9, {
980
+ width: 33.23,
981
+ align: 'right'
982
+ });
983
+ this.doc.rect(left + 410.69, top, 38, itemHeight).stroke();
984
+ this.doc.text(vBC, left + 409.19, top + 5.9, {
985
+ width: 38,
986
+ align: 'right'
987
+ });
988
+ this.doc.rect(left + 448.69, top, 35, itemHeight).stroke();
989
+ this.doc.text(vICMS, left + 447.19, top + 5.9, {
990
+ width: 35,
991
+ align: 'right'
992
+ });
993
+ this.doc.rect(left + 483.69, top, 38, itemHeight).stroke();
994
+ this.doc.text(vIPI, left + 482.19, top + 5.9, {
995
+ width: 38,
996
+ align: 'right'
997
+ });
998
+ this.doc.rect(left + 521.69, top, 22.5, itemHeight).stroke();
999
+ this.doc.text(pICMS, left + 520.19, top + 5.9, {
1000
+ width: 22.5,
1001
+ align: 'right'
1002
+ });
1003
+ this.doc.rect(left + 544.19, top, 22.75, itemHeight).stroke();
1004
+ this.doc.text(pIPI, left + 542.69, top + 5.9, {
1005
+ width: 22.5,
1006
+ align: 'right'
1007
+ });
1008
+ return itemHeight;
1009
+ };
1010
+ header(458);
1011
+ const createTable = (prod) => {
1012
+ if (y + defaultItemHeight > this.doc.page.height - 160) {
1013
+ this.doc.addPage();
1014
+ currentPage++;
1015
+ if (currentPage > 0) {
1016
+ y = 185;
1017
+ this.doc.fontSize(6).font('Times-Bold').fillColor('black').text('DADOS DO PRODUTO / SERVIÇOS', left, 175, {
1018
+ characterSpacing: 0.5,
1019
+ });
1020
+ header(185);
1021
+ }
1022
+ }
1023
+ const itemHeight = row(y + 15, prod);
1024
+ y += itemHeight;
1025
+ };
1026
+ // Adicionando itens da tabela
1027
+ if (this.det instanceof Array) {
1028
+ for (let i = 0; i < this.det.length; i++) {
1029
+ const prod = this.det[i];
1030
+ createTable(prod);
1031
+ }
1032
+ }
1033
+ else {
1034
+ createTable(this.det);
1035
+ }
1036
+ }
1037
+ _buildFooter() {
1038
+ const { left } = this.doc.page.margins;
1039
+ this.setLineStyle(0.75, '#1c1c1c');
1040
+ const topDestinatario = 820.45 - 88.5;
1041
+ this.doc.fontSize(6).font('Times-Bold').text('DADOS ADICIONAIS', left, topDestinatario - 5, {
1042
+ characterSpacing: 0.5,
1043
+ });
1044
+ this.doc.rect(left, topDestinatario, 408, 95).stroke();
1045
+ this.doc.fontSize(5).font('Times-Roman').text('INFORMAÇÕES COMPLEMENTARES', 10, topDestinatario + 4.5, {
1046
+ characterSpacing: 0.5
1047
+ });
1048
+ this.doc.fontSize(8).text(this.infAdic?.infCpl || '', 13, topDestinatario + 13, {
1049
+ characterSpacing: 1,
1050
+ width: 400,
1051
+ });
1052
+ this.doc.rect(left + 408, topDestinatario, 158.93, 95).stroke();
1053
+ this.doc.fontSize(5).text('RESERVADO AO FISCO', 408 + 10, topDestinatario + 4.5, {
1054
+ characterSpacing: 0.5
1055
+ });
1056
+ this.doc.fontSize(8).text(String(this.infAdic?.infAdFisco || ''), 13, topDestinatario + 13, {
1057
+ characterSpacing: 1,
1058
+ width: 400,
1059
+ });
1060
+ if (this.exibirMarcaDaguaDanfe) {
1061
+ const topPosition = Number(Number(this.ide.tpAmb)) !== 2 ? topDestinatario + 38 : topDestinatario + 58;
1062
+ const leftPosition = Number(Number(this.ide.tpAmb)) !== 2 ? left + 150 : left + 100;
1063
+ this.doc.fontSize(26).font('Times-Bold').fillColor('#c7c7c7').text('Treeunfe DFe', leftPosition, topPosition, {
1064
+ characterSpacing: 0.5,
1065
+ });
1066
+ }
1067
+ if (Number(Number(this.ide.tpAmb)) === 2) {
1068
+ this.doc.fontSize(14).font('Times-Bold').fillColor('grey').text('AMBIENTE DE HOMOLOGAÇÃO - NF-E SEM VALOR FISCAL', left + 100, topDestinatario + 45, {
1069
+ characterSpacing: 1
1070
+ });
1071
+ }
1072
+ // .rotate(45, { origin: [0, 0] })
1073
+ }
1074
+ async generatePDF(exibirMarcaDaguaDanfe) {
1075
+ try {
1076
+ this.exibirMarcaDaguaDanfe = exibirMarcaDaguaDanfe ?? true;
1077
+ const chave = this.chave;
1078
+ await this.generateBarcode(chave);
1079
+ this.doc.pipe(fs.createWriteStream(this.outputPath));
1080
+ this.drawHeader(true);
1081
+ this._buildDestinatario();
1082
+ this._builCalculoImposto();
1083
+ this._builTransporte();
1084
+ this.doc.on('pageAdded', () => {
1085
+ this.drawHeader(false);
1086
+ });
1087
+ this.drawFooter();
1088
+ this.doc.on('pageAdded', () => {
1089
+ this.drawFooter();
1090
+ });
1091
+ this._buildProdutos();
1092
+ this.doc.end();
1093
+ return {
1094
+ message: ` DANFE Gerada em '${this.outputPath}'`,
1095
+ success: true,
1096
+ };
1097
+ }
1098
+ catch (error) {
1099
+ throw new Error(`Erro ao gerar DANFE: ${error.message}`);
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ /**
1105
+ * @description :
1106
+ * @author : Marco Aurélio Silva Lima
1107
+ * @group :
1108
+ * @created :
1109
+ *
1110
+ * MODIFICATION LOG
1111
+ * - Version : 1.0.0
1112
+ * - Date : 3/7/2025
1113
+ * - Author : Cassio Seffrin
1114
+ * - Modification :
1115
+ **/
1116
+ /*
1117
+ * This file is part of Treeunfe DFe.
1118
+ *
1119
+ * Treeunfe DFe is free software: you can redistribute it and/or modify
1120
+ * it under the terms of the GNU General Public License as published by
1121
+ * the Free Software Foundation, either version 3 of the License, or
1122
+ * (at your option) any later version.
1123
+ *
1124
+ * Treeunfe DFe is distributed in the hope that it will be useful,
1125
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1126
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1127
+ * GNU General Public License for more details.
1128
+ *
1129
+ * You should have received a copy of the GNU General Public License
1130
+ * along with Treeunfe DFe. If not, see <https://www.gnu.org/licenses/>.
1131
+ */
1132
+ const baseDir = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
1133
+ const fontDir = process.env.NODE_ENV === 'production' ? '../resources/fonts/ARIAL.TTF' : '../../../../resources/fonts/ARIAL.TTF';
1134
+ const fontDirBold = process.env.NODE_ENV === 'production' ? '../resources/fonts/ARIALBD.TTF' : '../../../../resources/fonts/ARIALBD.TTF';
1135
+ class NFCEGerarDanfe {
1136
+ constructor(props) {
1137
+ this.saveQRCode = async (text) => {
1138
+ const filePath = path.resolve(baseDir, this.qrcodePath);
1139
+ try {
1140
+ await QRCode.toFile(`${filePath}/qrcode.png`, text, {
1141
+ color: {
1142
+ dark: '#000000', // Cor do código
1143
+ light: '#FFFFFF', // Cor de fundo
1144
+ },
1145
+ width: 300, // Largura da imagem
1146
+ });
1147
+ }
1148
+ catch (error) {
1149
+ console.error('Erro ao gerar o QR code:', error);
1150
+ console.error(error.stack);
1151
+ }
1152
+ };
1153
+ this.getQRCodeBuffer = async (text) => {
1154
+ try {
1155
+ const buffer = await QRCode.toBuffer(text, {
1156
+ color: {
1157
+ dark: '#000000', // Cor do código
1158
+ light: '#FFFFFF', // Cor de fundo
1159
+ },
1160
+ width: 300, // Largura da imagem
1161
+ });
1162
+ return buffer;
1163
+ }
1164
+ catch (error) {
1165
+ console.error('Erro ao gerar o QR code:', error);
1166
+ console.error(error.stack);
1167
+ throw new Error(`Erro ao gerar o QR code: ${error.message}`);
1168
+ }
1169
+ };
1170
+ const { data, chave, outputPath, pageWidth } = props;
1171
+ this.data = data;
1172
+ this.chave = chave.trim();
1173
+ this.outputPath = outputPath;
1174
+ this.enviada = false; // Valor padrão
1175
+ this.qrcodePath = outputPath; // Caminho padrão
1176
+ this.documento = new shared.ValidaCPFCNPJ(); // Inicialização correta
1177
+ this.protNFe = data.protNFe;
1178
+ const nfeData = Array.isArray(data.NFe) ? data.NFe[0] : data.NFe;
1179
+ const { det, ide, emit, dest, total, transp, pag, infAdic } = nfeData.infNFe;
1180
+ const infNFeSupl = nfeData.infNFeSupl;
1181
+ this.det = det;
1182
+ this.ide = ide;
1183
+ this.emit = emit;
1184
+ this.total = total;
1185
+ this.transp = transp;
1186
+ this.pag = pag;
1187
+ this.infAdic = infAdic;
1188
+ this.infNFeSupl = infNFeSupl;
1189
+ if (dest)
1190
+ this.dest = dest;
1191
+ if (this.protNFe?.infProt.nProt) {
1192
+ this.enviada = true;
1193
+ }
1194
+ function calculateHeight(itemsLength, itemHeight) {
1195
+ const headerHeight = 34.22975675056; // Altura do cabeçalho
1196
+ const footerHeight = 170; // Altura do rodapé -> 34.22975675056
1197
+ // Altura total é a soma das alturas dos itens + cabeçalho + rodapé
1198
+ return headerHeight + footerHeight + (itemsLength * itemHeight) + 5;
1199
+ }
1200
+ function calculateFontSize(width) {
1201
+ // Aqui você pode ajustar a fórmula para atender às suas necessidades
1202
+ return Math.min(width) * 0.02646;
1203
+ }
1204
+ this.larguraPadrao = 226.772;
1205
+ this.documentWidth = pageWidth || 226.772; // 158.74
1206
+ // const pageHeight = 300;
1207
+ let itensLength = 1;
1208
+ if (this.det instanceof Array) {
1209
+ itensLength = this.det.length;
1210
+ }
1211
+ const fontSize = calculateFontSize(this.documentWidth);
1212
+ this.fontSize = fontSize;
1213
+ this.itemHeight = fontSize * 1.116;
1214
+ const pageHeight = calculateHeight(itensLength, this.itemHeight);
1215
+ const fontPath = path.resolve(baseDir, fontDir);
1216
+ const fontPathBold = path.resolve(baseDir, fontDirBold);
1217
+ this.doc = new PDFDocument({
1218
+ margins: { top: 5.67, right: 5.67, bottom: 5.67, left: 5.67 },
1219
+ size: [this.documentWidth, pageHeight],
1220
+ bufferPages: true,
1221
+ layout: 'portrait',
1222
+ });
1223
+ this.doc.registerFont('Arial', fontPath);
1224
+ this.doc.registerFont('Arial-bold', fontPathBold);
1225
+ }
1226
+ createDir(path) {
1227
+ if (!fs.existsSync(path)) {
1228
+ fs.mkdirSync(path, { recursive: true });
1229
+ }
1230
+ }
1231
+ async generateBarcode(data) {
1232
+ try {
1233
+ const png = await bwipjs.toBuffer({
1234
+ bcid: 'code128', // Tipo de código de barras
1235
+ text: data, // Dado a ser codificado
1236
+ scaleX: 4, // Fator de escala
1237
+ height: 14, // Altura da barra
1238
+ includetext: false, // Incluir texto
1239
+ });
1240
+ const barcode = png.toString('base64');
1241
+ const buffer = Buffer.from(barcode, 'base64');
1242
+ const barcodeDir = this.qrcodePath;
1243
+ const barcodeFilePath = path.join(barcodeDir, 'barcode.png');
1244
+ // this.createDir(barcodeDir);
1245
+ fs.writeFileSync(barcodeFilePath, buffer);
1246
+ return buffer;
1247
+ }
1248
+ catch (err) {
1249
+ console.error('Erro ao gerar código de barras:', err);
1250
+ return null;
1251
+ }
1252
+ }
1253
+ centeredPos(texto) {
1254
+ const larguraPagina = this.doc.page.width;
1255
+ const larguraTexto = this.doc.fontSize(this.fontSize).widthOfString(texto);
1256
+ const posicaoX = (larguraPagina - larguraTexto) / 2;
1257
+ return posicaoX;
1258
+ }
1259
+ ajustarPosicao(posicaoOriginal, novaLargura) {
1260
+ return posicaoOriginal * (novaLargura / this.larguraPadrao);
1261
+ }
1262
+ calculaPosicao(text) {
1263
+ const { right, left } = this.doc.page.margins;
1264
+ const [pageWidth] = this.doc.page.size;
1265
+ const textWidth = this.doc.widthOfString(text);
1266
+ return Number(pageWidth) - textWidth - right - left;
1267
+ }
1268
+ drawHeader(_isFirstPage) {
1269
+ this._buildHeader();
1270
+ }
1271
+ drawFooter(qrCodeBuffer) {
1272
+ this._buildFooter(qrCodeBuffer);
1273
+ }
1274
+ _buildHeader() {
1275
+ const CNPJCPF = this.emit.CNPJCPF?.toString();
1276
+ const CNPJ = this.emit.CNPJ?.toString();
1277
+ const CPF = this.emit.CPF?.toString();
1278
+ const documento = this.documento.mascaraCnpjCpf(CNPJCPF || CNPJ || CPF || '');
1279
+ const identificationJoined = `${this.emit.enderEmit.xLgr}, ${this.emit.enderEmit.nro}, ${this.emit.enderEmit.xBairro}, ${this.emit.enderEmit.UF}`;
1280
+ /** IDENTIFICACAO EMITENTE */
1281
+ const _buildIdentificacaoEmit = () => {
1282
+ const centeredPosEmit = this.centeredPos(`CNPJ: ${documento} ${this.emit.xNome}`);
1283
+ const centeredPosEnd = this.centeredPos(identificationJoined);
1284
+ const centeredPosText = this.centeredPos('Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica');
1285
+ this.doc.font('Arial').fontSize(this.fontSize).text(`CNPJ: ${documento} `, centeredPosEmit, 2, {
1286
+ lineBreak: false,
1287
+ })
1288
+ .font('Arial-bold').text(this.emit.xNome)
1289
+ .fontSize(this.fontSize)
1290
+ .font('Arial')
1291
+ .text(identificationJoined, centeredPosEnd)
1292
+ .text('Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica', centeredPosText);
1293
+ };
1294
+ _buildIdentificacaoEmit();
1295
+ }
1296
+ _buildProdutos() {
1297
+ const { right, left, top } = this.doc.page.margins;
1298
+ const tableWidth = this.documentWidth - left - right;
1299
+ const startX = left;
1300
+ const tableTop = this.doc.y + top;
1301
+ const columnRatios = {
1302
+ codigo: 0.15,
1303
+ descricao: 0.40,
1304
+ qtdeUn: 0.15,
1305
+ unit: 0.15,
1306
+ total: 0.15
1307
+ };
1308
+ const columnSpacing = 0;
1309
+ const columnWidths = {
1310
+ codigo: tableWidth * columnRatios.codigo,
1311
+ descricao: tableWidth * columnRatios.descricao,
1312
+ qtdeUn: tableWidth * columnRatios.qtdeUn,
1313
+ unit: tableWidth * columnRatios.unit,
1314
+ total: tableWidth * columnRatios.total
1315
+ };
1316
+ const header = (top) => {
1317
+ let x = startX;
1318
+ this.doc.font('Arial-bold').fontSize(this.fontSize).text('Código', x, top, { width: columnWidths.codigo });
1319
+ x += columnWidths.codigo + columnSpacing;
1320
+ this.doc.text('Descrição', x, top, { width: columnWidths.descricao });
1321
+ x += columnWidths.descricao + columnSpacing;
1322
+ this.doc.text('Qtde', x, top, { width: columnWidths.qtdeUn, align: 'right' });
1323
+ x += columnWidths.qtdeUn + columnSpacing;
1324
+ this.doc.text('Unit', x, top, { width: columnWidths.unit, align: 'right' });
1325
+ x += columnWidths.unit + columnSpacing;
1326
+ this.doc.text('Total', x, top, { width: columnWidths.total, align: 'right' });
1327
+ };
1328
+ const row = (top, item) => {
1329
+ const quant = parseFloat(String(item.prod.qCom || item.prod.qTrib)).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1330
+ const valUnit = parseFloat(String(item.prod.vUnCom || item.prod.vUnTrib || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1331
+ const valLiq = parseFloat(String(item.prod.vProd || '0')).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1332
+ let x = startX;
1333
+ this.doc.font('Arial').fontSize(this.fontSize).text(item.prod.cProd, x, top, {
1334
+ width: columnWidths.codigo,
1335
+ align: 'left'
1336
+ });
1337
+ x += columnWidths.codigo + columnSpacing;
1338
+ const descricao = item.prod.xProd.slice(0, 120); // Limite de 120 caracteres
1339
+ const textWidth = this.doc.widthOfString(descricao);
1340
+ const lineCount = Math.ceil(textWidth / columnWidths.descricao);
1341
+ const descricaoOptions = {
1342
+ width: columnWidths.descricao,
1343
+ align: 'left',
1344
+ height: this.itemHeight * lineCount
1345
+ };
1346
+ this.doc.text(descricao, x, top, descricaoOptions);
1347
+ x += columnWidths.descricao + columnSpacing;
1348
+ this.doc.text(`${quant} ${item.prod.uCom}`, x, top, {
1349
+ width: columnWidths.qtdeUn,
1350
+ align: 'right'
1351
+ });
1352
+ x += columnWidths.qtdeUn + columnSpacing;
1353
+ this.doc.text(valUnit, x, top, {
1354
+ width: columnWidths.unit,
1355
+ align: 'right'
1356
+ });
1357
+ x += columnWidths.unit + columnSpacing;
1358
+ this.doc.text(valLiq, x, top, {
1359
+ width: columnWidths.total,
1360
+ align: 'right'
1361
+ });
1362
+ return descricaoOptions.height;
1363
+ };
1364
+ header(tableTop);
1365
+ let y = tableTop + this.itemHeight;
1366
+ if (this.det instanceof Array) {
1367
+ this.det.forEach((prod) => {
1368
+ row(y, prod);
1369
+ y += this.itemHeight;
1370
+ });
1371
+ }
1372
+ else {
1373
+ row(y, this.det);
1374
+ }
1375
+ }
1376
+ _buildTotais() {
1377
+ let tableTop = this.doc.y + 5;
1378
+ const quantidadeTotalDeItens = Array.isArray(this.det) ? this.det.length : 1;
1379
+ let valTotal = 0;
1380
+ let acrescimo = 0;
1381
+ let desconto = 0;
1382
+ if (Array.isArray(this.det)) {
1383
+ // Calcula o valor total dos produtos
1384
+ valTotal = this.det.reduce((sum, item) => sum + parseFloat(item.prod.vProd), 0);
1385
+ // Calcula o total dos acréscimos
1386
+ acrescimo = this.det.reduce((sum, item) => sum + (parseFloat(item.prod.vFrete || '0') + parseFloat(item.prod.vSeg || '0') + parseFloat(item.prod.vOutro || '0')), 0);
1387
+ // Calcula o total dos descontos
1388
+ desconto = this.det.reduce((sum, item) => sum + parseFloat(item.prod.vDesc || '0'), 0);
1389
+ }
1390
+ else {
1391
+ // Calcula o valor total do produto, os acréscimos, e desconto caso não seja um array
1392
+ valTotal = parseFloat(this.det.prod.vProd);
1393
+ acrescimo = parseFloat(this.det.prod.vFrete || '0') + parseFloat(this.det.prod.vSeg || '0') + parseFloat(this.det.prod.vOutro || '0');
1394
+ desconto = parseFloat(this.det.prod.vDesc || '0');
1395
+ }
1396
+ const valorTotal = valTotal.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1397
+ const acrescimoTotal = acrescimo.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1398
+ const descontoTotal = desconto.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1399
+ this.doc.text('Qtd. total de itens', 2, tableTop);
1400
+ this.doc.text(String(quantidadeTotalDeItens), this.calculaPosicao(String(quantidadeTotalDeItens)), tableTop, {
1401
+ align: 'right',
1402
+ });
1403
+ tableTop += this.itemHeight;
1404
+ this.doc.text('Valor total R$', 2, tableTop);
1405
+ this.doc.text(valorTotal, this.calculaPosicao(valorTotal), tableTop, {
1406
+ align: 'right',
1407
+ });
1408
+ tableTop += this.itemHeight;
1409
+ if (desconto > 0) {
1410
+ this.doc.text('Desconto R$', 2, tableTop);
1411
+ this.doc.text(descontoTotal, this.calculaPosicao(descontoTotal), tableTop, {
1412
+ align: 'right',
1413
+ });
1414
+ tableTop += this.itemHeight;
1415
+ }
1416
+ if (acrescimo > 0) {
1417
+ this.doc.text('Acréscimo R$', 2, tableTop);
1418
+ this.doc.text(acrescimoTotal, this.calculaPosicao(acrescimoTotal), tableTop, {
1419
+ align: 'right',
1420
+ });
1421
+ tableTop += this.itemHeight;
1422
+ }
1423
+ if (desconto > 0 || acrescimo > 0) {
1424
+ const totalPagar = parseFloat(String(valTotal + acrescimo - desconto)).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1425
+ this.doc.font('Arial-bold').text('Valor a Pagar R$', 2, tableTop);
1426
+ this.doc.text(totalPagar, this.calculaPosicao(totalPagar), tableTop, {
1427
+ align: 'right',
1428
+ });
1429
+ }
1430
+ tableTop += this.itemHeight + 2;
1431
+ this.doc.font('Arial').text('FORMA PAGAMENTO', 2, tableTop);
1432
+ // Tipos
1433
+ let topTiposPag = tableTop;
1434
+ if (Array.isArray(this.pag.detPag)) {
1435
+ for (let pagto of this.pag.detPag) {
1436
+ if (!pagto.xPag)
1437
+ pagto.xPag = shared.getDesTipoPag(pagto.tPag);
1438
+ this.doc.text(pagto.xPag || 'Não informado', 2, topTiposPag + this.itemHeight);
1439
+ topTiposPag += this.itemHeight;
1440
+ }
1441
+ }
1442
+ else {
1443
+ if (!this.pag.detPag.xPag)
1444
+ this.pag.detPag.xPag = shared.getDesTipoPag(this.pag.detPag.tPag);
1445
+ this.doc.text(this.pag.detPag.xPag || 'Não informado', 2, topTiposPag + this.itemHeight);
1446
+ }
1447
+ this.doc.text('VALOR PAGO R$', this.calculaPosicao('VALOR PAGO R$'), tableTop, {
1448
+ align: 'right',
1449
+ });
1450
+ // Valores
1451
+ let topValPags = tableTop;
1452
+ if (Array.isArray(this.pag.detPag)) {
1453
+ for (let pagto of this.pag.detPag) {
1454
+ const val = parseFloat(pagto.vPag).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1455
+ this.doc.text(val, this.calculaPosicao(val), topValPags + this.itemHeight, {
1456
+ align: 'right',
1457
+ });
1458
+ topValPags += this.itemHeight;
1459
+ }
1460
+ }
1461
+ else {
1462
+ const val = parseFloat(this.pag.detPag.vPag).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1463
+ this.doc.text(val, this.calculaPosicao(val), topValPags + this.itemHeight, {
1464
+ align: 'right',
1465
+ });
1466
+ }
1467
+ tableTop = topValPags;
1468
+ tableTop += 2 * this.itemHeight;
1469
+ let valTroco = 0;
1470
+ if (Array.isArray(this.pag.detPag)) {
1471
+ valTroco = this.pag.detPag.reduce((sum, item) => sum + parseFloat(item.vTroco || '0'), 0);
1472
+ }
1473
+ else {
1474
+ valTroco = parseFloat(this.pag.detPag.vTroco || '0');
1475
+ }
1476
+ const troco = valTroco.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 3 });
1477
+ this.doc.text('Troco R$', 2, tableTop);
1478
+ this.doc.text(troco, this.calculaPosicao(troco), tableTop, {
1479
+ align: 'right',
1480
+ });
1481
+ }
1482
+ _buildFooter(qrCodeBuffer) {
1483
+ let tableTop = this.doc.y + 5;
1484
+ this.doc.font('Arial-bold').text('Consulte pela Chave de Acesso em', 0, tableTop, {
1485
+ align: 'center'
1486
+ });
1487
+ tableTop += this.itemHeight;
1488
+ this.doc.font('Arial').text(this.infNFeSupl?.urlChave || '', 0, tableTop, {
1489
+ align: 'center'
1490
+ });
1491
+ tableTop += this.itemHeight;
1492
+ this.doc.text(this.protNFe?.infProt.chNFe || '', 0, tableTop, {
1493
+ align: 'center'
1494
+ });
1495
+ tableTop += this.itemHeight;
1496
+ // const filePath = path.resolve(baseDir, this.qrcodePath);
1497
+ // this.doc.image(`${filePath}/qrcode.png`, 2, tableTop, { width: 70.87, height: 70.87 });
1498
+ this.doc.image(qrCodeBuffer, 2, tableTop, { width: 70.87, height: 70.87 });
1499
+ tableTop += 4;
1500
+ let topBeforeQrCode = tableTop;
1501
+ const CNPJCPF = this.documento.mascaraCnpjCpf(this.dest?.CNPJCPF || this.dest?.CNPJ || this.dest?.CPF || this.dest?.idEstrangeiro || '');
1502
+ const xNome = this.dest?.xNome ?? 'Sem cliente identificado';
1503
+ const xLgr = this.dest?.enderDest?.xLgr ?? '';
1504
+ const nro = this.dest?.enderDest?.nro ?? '';
1505
+ const xBairro = this.dest?.enderDest?.xBairro ?? null;
1506
+ const xMun = this.dest?.enderDest?.xMun ?? '';
1507
+ const UF = this.dest?.enderDest?.UF ?? '';
1508
+ const enderecoPartes = [
1509
+ xLgr && `${xLgr}`,
1510
+ nro && `${nro}`,
1511
+ xBairro && `bairro: ${xBairro}`,
1512
+ xMun && `${xMun}`,
1513
+ UF && `${UF}`
1514
+ ].filter(Boolean);
1515
+ const enderecoStr = enderecoPartes.join(', ');
1516
+ if (CNPJCPF && CNPJCPF !== '') {
1517
+ this.doc.font('Arial-bold')
1518
+ .text(`CONSUMIDOR - DOC ${CNPJCPF}`, 75, tableTop, {
1519
+ align: 'left',
1520
+ lineGap: 1
1521
+ })
1522
+ .font('Arial')
1523
+ .text(` - ${xNome}`, {
1524
+ lineGap: 1
1525
+ });
1526
+ tableTop = this.doc.y + 4;
1527
+ this.doc.text(enderecoStr, 75, tableTop);
1528
+ tableTop = this.doc.y + 8;
1529
+ }
1530
+ else {
1531
+ this.doc.text('CONSUMIDOR NÃO IDENTIFICADO', 75, tableTop, {
1532
+ align: 'left',
1533
+ });
1534
+ tableTop = this.doc.y + 8;
1535
+ }
1536
+ const data = dateFns.parseISO(this.ide.dhEmi);
1537
+ const dtaEmi = dateFns.format(data, 'dd/MM/yyyy HH:mm:ss');
1538
+ let dtaAut = dateFns.format(new Date(), 'dd/MM/yyyy HH:mm:ss');
1539
+ if (this.protNFe?.infProt.dhRecbto) {
1540
+ const dataAut = dateFns.parseISO(this.protNFe?.infProt.dhRecbto);
1541
+ dtaAut = dateFns.format(dataAut, 'dd/MM/yyyy HH:mm:ss');
1542
+ }
1543
+ this.doc.font('Arial-bold')
1544
+ .text(`NFC-e nº ${this.ide.nNF} Série ${this.ide.serie} ${dtaEmi}`, 75, tableTop, {
1545
+ align: 'left',
1546
+ lineGap: 1
1547
+ })
1548
+ .text('Protocolo de autorização: ', {
1549
+ continued: true,
1550
+ lineGap: 1,
1551
+ })
1552
+ .font('Arial')
1553
+ .text(this.protNFe?.infProt.nProt || '123')
1554
+ .font('Arial-bold')
1555
+ .text('Data de autorização ', {
1556
+ continued: true,
1557
+ lineGap: 1,
1558
+ })
1559
+ .font('Arial')
1560
+ .text(dtaAut);
1561
+ tableTop = this.doc.y + 20;
1562
+ topBeforeQrCode += 70.87;
1563
+ this.doc.text(`Tributos Totais Incidentes (Lei Federal 12.741/2012): R$ ${parseFloat(this.total.ICMSTot.vTotTrib || '0').toFixed(2)}`, 0, topBeforeQrCode, {
1564
+ align: 'center'
1565
+ });
1566
+ }
1567
+ async generatePDF(exibirMarcaDaguaDanfe) {
1568
+ try {
1569
+ this.exibirMarcaDaguaDanfe = exibirMarcaDaguaDanfe || true;
1570
+ // await this.saveQRCode(this.infNFeSupl?.qrCode || '')
1571
+ const qrCodeBuffer = await this.getQRCodeBuffer(this.infNFeSupl?.qrCode || '');
1572
+ this.doc.pipe(fs.createWriteStream(this.outputPath));
1573
+ this.drawHeader(true);
1574
+ this._buildProdutos();
1575
+ this._buildTotais();
1576
+ this.drawFooter(qrCodeBuffer);
1577
+ this.doc.end();
1578
+ return {
1579
+ message: ` DANFE Gerada em '${this.outputPath}'`,
1580
+ success: true,
1581
+ };
1582
+ }
1583
+ catch (error) {
1584
+ throw new Error(`Erro ao gerar DANFE: ${error.message}`);
1585
+ }
1586
+ }
1587
+ }
1588
+
1589
+ exports.NFCEGerarDanfe = NFCEGerarDanfe;
1590
+ exports.NFEGerarDanfe = NFEGerarDanfe;
1591
+ //# sourceMappingURL=index.cjs.map