nfe-lib-node 1.0.0 → 1.1.0
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.
- package/README.md +8 -2
- package/dist/Assinador.d.ts +15 -0
- package/dist/Assinador.d.ts.map +1 -0
- package/dist/Assinador.js +84 -0
- package/dist/Assinador.js.map +1 -0
- package/dist/Certificado.d.ts +13 -0
- package/dist/Certificado.d.ts.map +1 -0
- package/dist/Certificado.js +49 -0
- package/dist/Certificado.js.map +1 -0
- package/dist/Danfe.d.ts +16 -0
- package/dist/Danfe.d.ts.map +1 -0
- package/dist/Danfe.js +371 -0
- package/dist/Danfe.js.map +1 -0
- package/dist/NFe.d.ts +22 -0
- package/dist/NFe.d.ts.map +1 -0
- package/dist/NFe.js +102 -0
- package/dist/NFe.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +2403 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -6,10 +6,16 @@ Pague apenas os seus impostos, não pela emissão! 😉
|
|
|
6
6
|
|
|
7
7
|
## 📦 Instalação
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Instale diretamente via NPM:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
|
|
12
|
+
npm install nfe-lib-node
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Ou, para clonar e rodar localmente:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git clone https://github.com/rafconrado/nfe-lib-node.git
|
|
13
19
|
cd nfe-lib-node
|
|
14
20
|
npm install
|
|
15
21
|
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class Assinador {
|
|
2
|
+
private privateKeyPem;
|
|
3
|
+
private publicCertPem;
|
|
4
|
+
constructor(pfxBuffer: Buffer, password?: string | undefined);
|
|
5
|
+
/**
|
|
6
|
+
* Extrai a chave privada e o certificado público do PFX
|
|
7
|
+
*/
|
|
8
|
+
private extractPemFromPfx;
|
|
9
|
+
private getLeafCert;
|
|
10
|
+
/**
|
|
11
|
+
* Assina o XML da Nota Fiscal Eletrônica no padrão SEFAZ (XMLDSig)
|
|
12
|
+
*/
|
|
13
|
+
assinarXmlNFe(xmlCru: string): string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=Assinador.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Assinador.d.ts","sourceRoot":"","sources":["../src/Assinador.ts"],"names":[],"mappings":"AAIA,qBAAa,SAAS;IACpB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAS;IAE9B,YAAY,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,EAI3D;IAED;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,WAAW;IAanB;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAqC3C;CACF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { SignedXml } from 'xml-crypto';
|
|
2
|
+
import forge from 'node-forge';
|
|
3
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
4
|
+
export class Assinador {
|
|
5
|
+
privateKeyPem;
|
|
6
|
+
publicCertPem;
|
|
7
|
+
constructor(pfxBuffer, password) {
|
|
8
|
+
const { privateKey, certificate } = this.extractPemFromPfx(pfxBuffer, password);
|
|
9
|
+
this.privateKeyPem = privateKey;
|
|
10
|
+
this.publicCertPem = certificate;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extrai a chave privada e o certificado público do PFX
|
|
14
|
+
*/
|
|
15
|
+
extractPemFromPfx(pfxBuffer, password) {
|
|
16
|
+
const p12Asn1 = forge.asn1.fromDer(pfxBuffer.toString('binary'));
|
|
17
|
+
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password || '');
|
|
18
|
+
let privateKeyPem = '';
|
|
19
|
+
let certPem = '';
|
|
20
|
+
const certBagOid = forge.pki.oids.certBag;
|
|
21
|
+
const certBags = p12.getBags({ bagType: certBagOid })[certBagOid] ?? [];
|
|
22
|
+
const cert = this.getLeafCert(certBags);
|
|
23
|
+
if (cert) {
|
|
24
|
+
certPem = forge.pki.certificateToPem(cert);
|
|
25
|
+
}
|
|
26
|
+
const keyBagOid = forge.pki.oids.pkcs8ShroudedKeyBag;
|
|
27
|
+
const keyBags = p12.getBags({ bagType: keyBagOid });
|
|
28
|
+
const key = keyBags[keyBagOid]?.[0]?.key;
|
|
29
|
+
if (key) {
|
|
30
|
+
privateKeyPem = forge.pki.privateKeyToPem(key);
|
|
31
|
+
}
|
|
32
|
+
if (!privateKeyPem || !certPem) {
|
|
33
|
+
throw new Error('Não foi possível extrair a chave privada ou o certificado do PFX.');
|
|
34
|
+
}
|
|
35
|
+
return { privateKey: privateKeyPem, certificate: certPem };
|
|
36
|
+
}
|
|
37
|
+
getLeafCert(certBags) {
|
|
38
|
+
for (const bag of certBags) {
|
|
39
|
+
if (!bag.cert)
|
|
40
|
+
continue;
|
|
41
|
+
const isCa = bag.cert.extensions?.some((ext) => ext.name === 'basicConstraints' && ext.cA === true);
|
|
42
|
+
if (!isCa) {
|
|
43
|
+
return bag.cert;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return certBags[0]?.cert;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Assina o XML da Nota Fiscal Eletrônica no padrão SEFAZ (XMLDSig)
|
|
50
|
+
*/
|
|
51
|
+
assinarXmlNFe(xmlCru) {
|
|
52
|
+
const doc = new DOMParser().parseFromString(xmlCru, 'text/xml');
|
|
53
|
+
const infNFe = doc.getElementsByTagName('infNFe')[0];
|
|
54
|
+
if (!infNFe) {
|
|
55
|
+
throw new Error('Tag <infNFe> não encontrada no XML. O XML fornecido não é uma NF-e válida.');
|
|
56
|
+
}
|
|
57
|
+
const id = infNFe.getAttribute('Id');
|
|
58
|
+
if (!id) {
|
|
59
|
+
throw new Error('A tag <infNFe> precisa ter o atributo Id (ex: Id="NFe12345...")');
|
|
60
|
+
}
|
|
61
|
+
const sig = new SignedXml();
|
|
62
|
+
// A SEFAZ exige URI=#IdDaNota e essas duas transforms
|
|
63
|
+
sig.addReference({
|
|
64
|
+
xpath: `//*[@Id='${id}']`,
|
|
65
|
+
transforms: [
|
|
66
|
+
'http://www.w3.org/2000/09/xmldsig#enveloped-signature',
|
|
67
|
+
'http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
|
|
68
|
+
],
|
|
69
|
+
digestAlgorithm: 'http://www.w3.org/2000/09/xmldsig#sha1',
|
|
70
|
+
uri: `#${id}`,
|
|
71
|
+
});
|
|
72
|
+
sig.privateKey = this.privateKeyPem;
|
|
73
|
+
sig.signatureAlgorithm = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
|
|
74
|
+
sig.canonicalizationAlgorithm = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
|
|
75
|
+
// Em xml-crypto v6, basta passar o publicCert
|
|
76
|
+
sig.publicCert = Buffer.from(this.publicCertPem);
|
|
77
|
+
sig.computeSignature(xmlCru, {
|
|
78
|
+
prefix: '',
|
|
79
|
+
location: { reference: `//*[local-name(.)='NFe']`, action: 'append' },
|
|
80
|
+
});
|
|
81
|
+
return sig.getSignedXml();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=Assinador.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Assinador.js","sourceRoot":"","sources":["../src/Assinador.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import https from 'https';
|
|
2
|
+
export declare class Certificado {
|
|
3
|
+
pfxBuffer: Buffer;
|
|
4
|
+
password?: string | undefined;
|
|
5
|
+
constructor(pfxBuffer: Buffer, password?: string | undefined);
|
|
6
|
+
/**
|
|
7
|
+
* Retorna um https.Agent configurado com o certificado para autenticação mútua TLS (exigida pela SEFAZ).
|
|
8
|
+
*/
|
|
9
|
+
getHttpsAgent(): https.Agent;
|
|
10
|
+
private extractPemFromPfx;
|
|
11
|
+
private getLeafCert;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Certificado.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Certificado.d.ts","sourceRoot":"","sources":["../src/Certificado.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,qBAAa,WAAW;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAErC,YAAY,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,EAG3D;IAED;;OAEG;IACI,aAAa,IAAI,KAAK,CAAC,KAAK,CAOlC;IAED,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,WAAW;CAYpB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import forge from 'node-forge';
|
|
3
|
+
export class Certificado {
|
|
4
|
+
pfxBuffer;
|
|
5
|
+
password;
|
|
6
|
+
constructor(pfxBuffer, password) {
|
|
7
|
+
this.pfxBuffer = pfxBuffer;
|
|
8
|
+
this.password = password;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Retorna um https.Agent configurado com o certificado para autenticação mútua TLS (exigida pela SEFAZ).
|
|
12
|
+
*/
|
|
13
|
+
getHttpsAgent() {
|
|
14
|
+
const { privateKey, certificate } = this.extractPemFromPfx();
|
|
15
|
+
return new https.Agent({
|
|
16
|
+
cert: certificate,
|
|
17
|
+
key: privateKey,
|
|
18
|
+
rejectUnauthorized: false, // Em ambientes de homologação da Sefaz, a cadeia pode ser inválida
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
extractPemFromPfx() {
|
|
22
|
+
const p12Asn1 = forge.asn1.fromDer(this.pfxBuffer.toString('binary'));
|
|
23
|
+
const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, this.password ?? '');
|
|
24
|
+
const certBagOid = forge.pki.oids.certBag;
|
|
25
|
+
const certBags = p12.getBags({ bagType: certBagOid })[certBagOid] ?? [];
|
|
26
|
+
const cert = this.getLeafCert(certBags);
|
|
27
|
+
const certPem = cert ? forge.pki.certificateToPem(cert) : '';
|
|
28
|
+
const keyBagOid = forge.pki.oids.pkcs8ShroudedKeyBag;
|
|
29
|
+
const keyBags = p12.getBags({ bagType: keyBagOid })[keyBagOid] ?? [];
|
|
30
|
+
const key = keyBags[0]?.key;
|
|
31
|
+
const privateKeyPem = key ? forge.pki.privateKeyToPem(key) : '';
|
|
32
|
+
if (!privateKeyPem || !certPem) {
|
|
33
|
+
throw new Error('Não foi possível extrair a chave privada ou o certificado do PFX.');
|
|
34
|
+
}
|
|
35
|
+
return { privateKey: privateKeyPem, certificate: certPem };
|
|
36
|
+
}
|
|
37
|
+
getLeafCert(certBags) {
|
|
38
|
+
for (const bag of certBags) {
|
|
39
|
+
if (!bag.cert)
|
|
40
|
+
continue;
|
|
41
|
+
const isCa = bag.cert.extensions?.some((ext) => ext.name === 'basicConstraints' && ext.cA === true);
|
|
42
|
+
if (!isCa) {
|
|
43
|
+
return bag.cert;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return certBags[0]?.cert;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=Certificado.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Certificado.js","sourceRoot":"","sources":["../src/Certificado.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,OAAO,WAAW;IACf,SAAS,CAAS;IAClB,QAAQ,CAAsB;IAErC,YAAY,SAAiB,EAAE,QAA6B;QAC1D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,aAAa;QAClB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC7D,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC;YACrB,IAAI,EAAE,WAAW;YACjB,GAAG,EAAE,UAAU;YACf,kBAAkB,EAAE,KAAK,EAAE,mEAAmE;SAC/F,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB;QACvB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAEtE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAiB,CAAC;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAE7D,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAA6B,CAAC;QAC/D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACrE,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QAC5B,MAAM,aAAa,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEhE,IAAI,CAAC,aAAa,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;QAED,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAC7D,CAAC;IAEO,WAAW,CAAC,QAA4B;QAC9C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,SAAS;YACxB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CACpC,CAAC,GAAoC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,kBAAkB,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI,CAC7F,CAAC;YACF,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,GAAG,CAAC,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAC3B,CAAC;CACF"}
|
package/dist/Danfe.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class Danfe {
|
|
2
|
+
static fromXml(xmlNFe: string, xmlRetornoSefaz?: string): Buffer;
|
|
3
|
+
private static getDescricaoFrete;
|
|
4
|
+
private static getDescricaoPagamento;
|
|
5
|
+
private static formatDecimal;
|
|
6
|
+
private static getTag;
|
|
7
|
+
private static formatDoc;
|
|
8
|
+
private static formatDateTime;
|
|
9
|
+
private static drawSectionHeader;
|
|
10
|
+
private static drawBox;
|
|
11
|
+
private static drawText;
|
|
12
|
+
private static escapePdfText;
|
|
13
|
+
private static drawCode128C;
|
|
14
|
+
private static buildPdfBuffer;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=Danfe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Danfe.d.ts","sourceRoot":"","sources":["../src/Danfe.ts"],"names":[],"mappings":"AAwDA,qBAAa,KAAK;IAChB,OAAc,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CA4OtE;IAED,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAYhC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAcpC,OAAO,CAAC,MAAM,CAAC,aAAa;IAM5B,OAAO,CAAC,MAAM,CAAC,MAAM;IAYrB,OAAO,CAAC,MAAM,CAAC,SAAS;IAWxB,OAAO,CAAC,MAAM,CAAC,cAAc;IAO7B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAIhC,OAAO,CAAC,MAAM,CAAC,OAAO;IAoBtB,OAAO,CAAC,MAAM,CAAC,QAAQ;IAMvB,OAAO,CAAC,MAAM,CAAC,aAAa;IAS5B,OAAO,CAAC,MAAM,CAAC,YAAY;IAgC3B,OAAO,CAAC,MAAM,CAAC,cAAc;CA6B9B"}
|
package/dist/Danfe.js
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
2
|
+
const CODE128_PATTERNS = [
|
|
3
|
+
'212222', '222122', '222221', '121223', '121322', '131222', '122213', '122312', '132212', '221213',
|
|
4
|
+
'221312', '231212', '112232', '122132', '122231', '113222', '123122', '123221', '223211', '221132',
|
|
5
|
+
'221231', '213212', '223112', '312131', '311222', '321122', '321221', '312212', '322112', '322211',
|
|
6
|
+
'212123', '212321', '232121', '111323', '131123', '131321', '112313', '132113', '132311', '211313',
|
|
7
|
+
'231113', '231311', '112133', '112331', '132131', '113123', '113321', '133121', '313121', '211331',
|
|
8
|
+
'231131', '213113', '213311', '213131', '311123', '311321', '331121', '312113', '312311', '332111',
|
|
9
|
+
'314111', '221411', '431111', '111224', '111422', '121124', '121421', '141122', '141221', '112214',
|
|
10
|
+
'112412', '122114', '122411', '142112', '142211', '241211', '221114', '413111', '241112', '134111',
|
|
11
|
+
'111242', '121142', '121241', '114212', '124112', '124211', '411212', '421112', '421211', '212141',
|
|
12
|
+
'214121', '412121', '111143', '111341', '131141', '114113', '114311', '411113', '411311', '113141',
|
|
13
|
+
'114131', '311141', '411131', '211412', '211214', '211232', '2331112',
|
|
14
|
+
];
|
|
15
|
+
const COLUNAS_ITENS = [
|
|
16
|
+
{ x: 20, w: 42, label: 'COD. PROD' },
|
|
17
|
+
{ x: 62, w: 155, label: 'DESCRICAO DO PRODUTO / SERVICO' },
|
|
18
|
+
{ x: 217, w: 36, label: 'NCM/SH' },
|
|
19
|
+
{ x: 253, w: 28, label: 'O/CSOSN' },
|
|
20
|
+
{ x: 281, w: 24, label: 'CFOP' },
|
|
21
|
+
{ x: 305, w: 18, label: 'UN' },
|
|
22
|
+
{ x: 323, w: 34, label: 'QUANT.' },
|
|
23
|
+
{ x: 357, w: 36, label: 'V. UNIT.' },
|
|
24
|
+
{ x: 393, w: 36, label: 'V. TOTAL' },
|
|
25
|
+
{ x: 429, w: 34, label: 'B.C. ICMS' },
|
|
26
|
+
{ x: 463, w: 32, label: 'V. ICMS' },
|
|
27
|
+
{ x: 495, w: 28, label: 'V. IPI' },
|
|
28
|
+
{ x: 523, w: 26, label: 'AL. ICMS' },
|
|
29
|
+
{ x: 549, w: 26, label: 'AL. IPI' },
|
|
30
|
+
];
|
|
31
|
+
export class Danfe {
|
|
32
|
+
static fromXml(xmlNFe, xmlRetornoSefaz) {
|
|
33
|
+
const doc = new DOMParser().parseFromString(xmlNFe, 'text/xml');
|
|
34
|
+
const docRetorno = xmlRetornoSefaz
|
|
35
|
+
? new DOMParser().parseFromString(xmlRetornoSefaz, 'text/xml')
|
|
36
|
+
: doc;
|
|
37
|
+
const infNFe = doc.getElementsByTagName('infNFe')[0];
|
|
38
|
+
const ide = doc.getElementsByTagName('ide')[0];
|
|
39
|
+
const emit = doc.getElementsByTagName('emit')[0];
|
|
40
|
+
const enderEmit = emit?.getElementsByTagName('enderEmit')[0];
|
|
41
|
+
const dest = doc.getElementsByTagName('dest')[0];
|
|
42
|
+
const enderDest = dest?.getElementsByTagName('enderDest')[0];
|
|
43
|
+
const icmsTot = doc.getElementsByTagName('ICMSTot')[0];
|
|
44
|
+
const transp = doc.getElementsByTagName('transp')[0];
|
|
45
|
+
const transporta = transp?.getElementsByTagName('transporta')[0];
|
|
46
|
+
const vol = transp?.getElementsByTagName('vol')[0];
|
|
47
|
+
const detPag = doc.getElementsByTagName('detPag')[0];
|
|
48
|
+
const infAdic = doc.getElementsByTagName('infAdic')[0];
|
|
49
|
+
const infProt = docRetorno.getElementsByTagName('infProt')[0] ??
|
|
50
|
+
doc.getElementsByTagName('infProt')[0];
|
|
51
|
+
const rawId = infNFe?.getAttribute('Id') ?? '';
|
|
52
|
+
const chave = rawId.replace(/^NFe/, '').padStart(44, '0');
|
|
53
|
+
const chaveFormatada = chave.replace(/(\d{4})(?=\d)/g, '$1 ');
|
|
54
|
+
const tpAmb = this.getTag(ide, 'tpAmb', '2');
|
|
55
|
+
const natOp = this.getTag(ide, 'natOp', '');
|
|
56
|
+
const nNF = this.getTag(ide, 'nNF', '1');
|
|
57
|
+
const serie = this.getTag(ide, 'serie', '1');
|
|
58
|
+
const tpNF = this.getTag(ide, 'tpNF', '1');
|
|
59
|
+
const dhEmi = this.formatDateTime(this.getTag(ide, 'dhEmi', ''));
|
|
60
|
+
const dhSaiEnt = this.formatDateTime(this.getTag(ide, 'dhSaiEnt', this.getTag(ide, 'dhEmi', '')));
|
|
61
|
+
const emitNome = this.getTag(emit, 'xNome', '');
|
|
62
|
+
const emitCnpj = this.formatDoc(this.getTag(emit, 'CNPJ', this.getTag(emit, 'CPF', '')));
|
|
63
|
+
const emitIe = this.getTag(emit, 'IE', '');
|
|
64
|
+
const emitIeSt = this.getTag(emit, 'IEST', '');
|
|
65
|
+
const emitEnd = `${this.getTag(enderEmit, 'xLgr', '')}, ${this.getTag(enderEmit, 'nro', '')} - ${this.getTag(enderEmit, 'xBairro', '')}`;
|
|
66
|
+
const emitMunUfCep = `${this.getTag(enderEmit, 'xMun', '')}/${this.getTag(enderEmit, 'UF', '')} - CEP ${this.getTag(enderEmit, 'CEP', '')} - Fone ${this.getTag(enderEmit, 'fone', '')}`;
|
|
67
|
+
const destNome = this.getTag(dest, 'xNome', '');
|
|
68
|
+
const destDoc = this.formatDoc(this.getTag(dest, 'CNPJ', this.getTag(dest, 'CPF', '')));
|
|
69
|
+
const destEnd = `${this.getTag(enderDest, 'xLgr', '')}, ${this.getTag(enderDest, 'nro', '')}`;
|
|
70
|
+
const destBairro = this.getTag(enderDest, 'xBairro', '');
|
|
71
|
+
const destCep = this.getTag(enderDest, 'CEP', '');
|
|
72
|
+
const destMun = this.getTag(enderDest, 'xMun', '');
|
|
73
|
+
const destUf = this.getTag(enderDest, 'UF', '');
|
|
74
|
+
const destFone = this.getTag(enderDest, 'fone', '');
|
|
75
|
+
const destIe = this.getTag(dest, 'IE', '');
|
|
76
|
+
const cStat = this.getTag(infProt, 'cStat', this.getTag(docRetorno, 'cStat', ''));
|
|
77
|
+
const xMotivo = this.getTag(infProt, 'xMotivo', this.getTag(docRetorno, 'xMotivo', ''));
|
|
78
|
+
const nProt = this.getTag(infProt, 'nProt', '');
|
|
79
|
+
const dhRecbto = this.formatDateTime(this.getTag(infProt, 'dhRecbto', this.getTag(docRetorno, 'dhRecbto', '')));
|
|
80
|
+
const protocoloTexto = nProt
|
|
81
|
+
? `${nProt} - ${dhRecbto}`
|
|
82
|
+
: `cStat ${cStat} - ${xMotivo.slice(0, 38)} (${dhRecbto})`;
|
|
83
|
+
const detNodes = doc.getElementsByTagName('det');
|
|
84
|
+
const itens = [];
|
|
85
|
+
for (let i = 0; i < detNodes.length; i++) {
|
|
86
|
+
const det = detNodes[i];
|
|
87
|
+
if (!det)
|
|
88
|
+
continue;
|
|
89
|
+
const prod = det.getElementsByTagName('prod')[0];
|
|
90
|
+
const icms = det.getElementsByTagName('ICMS')[0];
|
|
91
|
+
const ipi = det.getElementsByTagName('IPI')[0];
|
|
92
|
+
const orig = this.getTag(icms, 'orig', '0');
|
|
93
|
+
const csosnOrCst = this.getTag(icms, 'CSOSN', this.getTag(icms, 'CST', '00'));
|
|
94
|
+
itens.push({
|
|
95
|
+
cProd: this.getTag(prod, 'cProd', ''),
|
|
96
|
+
xProd: this.getTag(prod, 'xProd', ''),
|
|
97
|
+
ncm: this.getTag(prod, 'NCM', ''),
|
|
98
|
+
origCsosnCst: `${orig}/${csosnOrCst}`,
|
|
99
|
+
cfop: this.getTag(prod, 'CFOP', ''),
|
|
100
|
+
uCom: this.getTag(prod, 'uCom', ''),
|
|
101
|
+
qCom: this.formatDecimal(this.getTag(prod, 'qCom', '0.00')),
|
|
102
|
+
vUnCom: this.formatDecimal(this.getTag(prod, 'vUnCom', '0.00')),
|
|
103
|
+
vProd: this.formatDecimal(this.getTag(prod, 'vProd', '0.00')),
|
|
104
|
+
vBC: this.formatDecimal(this.getTag(icms, 'vBC', '0.00')),
|
|
105
|
+
vICMS: this.formatDecimal(this.getTag(icms, 'vICMS', '0.00')),
|
|
106
|
+
vIPI: this.formatDecimal(this.getTag(ipi, 'vIPI', '0.00')),
|
|
107
|
+
pICMS: this.formatDecimal(this.getTag(icms, 'pICMS', '0.00')),
|
|
108
|
+
pIPI: this.formatDecimal(this.getTag(ipi, 'pIPI', '0.00')),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const cmds = [];
|
|
112
|
+
cmds.push('0.5 w');
|
|
113
|
+
this.drawBox(cmds, 20, 782, 450, 38, 'RECEBEMOS DE ' + emitNome.slice(0, 65) + ' OS PRODUTOS CONSTANTES DA NOTA FISCAL INDICADA AO LADO');
|
|
114
|
+
this.drawBox(cmds, 20, 782, 110, 20, 'DATA DE RECEBIMENTO');
|
|
115
|
+
this.drawBox(cmds, 130, 782, 340, 20, 'IDENTIFICACAO E ASSINATURA DO RECEBEDOR');
|
|
116
|
+
this.drawBox(cmds, 470, 782, 105, 38, 'NF-e', `No. ${nNF.padStart(9, '0')} / Serie ${serie}`, 7.5, true);
|
|
117
|
+
cmds.push('[2 2] 0 d 0.4 w 20 776 m 575 776 l S [] 0 d 0.5 w');
|
|
118
|
+
this.drawBox(cmds, 20, 688, 220, 82, 'IDENTIFICACAO DO EMITENTE');
|
|
119
|
+
this.drawText(cmds, 24, 752, emitNome.slice(0, 38), 7.5, true);
|
|
120
|
+
this.drawText(cmds, 24, 739, emitEnd.slice(0, 45), 6.5, false);
|
|
121
|
+
this.drawText(cmds, 24, 728, emitMunUfCep.slice(0, 47), 6.5, false);
|
|
122
|
+
if (tpAmb === '2') {
|
|
123
|
+
this.drawText(cmds, 24, 695, 'AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL', 6.5, true);
|
|
124
|
+
}
|
|
125
|
+
this.drawBox(cmds, 240, 688, 95, 82, '');
|
|
126
|
+
this.drawText(cmds, 268, 756, 'DANFE', 11, true);
|
|
127
|
+
this.drawText(cmds, 246, 746, 'Documento Auxiliar da', 6, false);
|
|
128
|
+
this.drawText(cmds, 245, 738, 'Nota Fiscal Eletronica', 6, false);
|
|
129
|
+
this.drawText(cmds, 246, 725, '0 - ENTRADA', 6, false);
|
|
130
|
+
this.drawText(cmds, 246, 717, '1 - SAIDA', 6, false);
|
|
131
|
+
this.drawBox(cmds, 312, 716, 15, 15, '');
|
|
132
|
+
this.drawText(cmds, 317, 720, tpNF, 8.5, true);
|
|
133
|
+
this.drawText(cmds, 246, 703, `No. ${nNF.padStart(9, '0')}`, 7.5, true);
|
|
134
|
+
this.drawText(cmds, 246, 693, `SERIE: ${serie.padStart(3, '0')} FL 1/1`, 6.5, true);
|
|
135
|
+
this.drawBox(cmds, 335, 729, 240, 41, 'CONTROLE DO FISCO');
|
|
136
|
+
this.drawCode128C(cmds, chave, 348, 733, 214, 26);
|
|
137
|
+
this.drawBox(cmds, 335, 688, 240, 41, 'CHAVE DE ACESSO', chaveFormatada, 7, true);
|
|
138
|
+
this.drawBox(cmds, 20, 666, 315, 22, 'NATUREZA DA OPERACAO', natOp, 7.5, false);
|
|
139
|
+
this.drawBox(cmds, 335, 666, 240, 22, 'PROTOCOLO DE AUTORIZACAO DE USO', protocoloTexto, 6.5, true);
|
|
140
|
+
this.drawBox(cmds, 20, 644, 185, 22, 'INSCRICAO ESTADUAL', emitIe, 7.5, false);
|
|
141
|
+
this.drawBox(cmds, 205, 644, 185, 22, 'INSC. ESTADUAL DO SUBST. TRIBUTARIO', emitIeSt, 7.5, false);
|
|
142
|
+
this.drawBox(cmds, 390, 644, 185, 22, 'CNPJ / CPF', emitCnpj, 7.5, true);
|
|
143
|
+
this.drawSectionHeader(cmds, 20, 633, 'DESTINATARIO / REMETENTE');
|
|
144
|
+
this.drawBox(cmds, 20, 609, 340, 22, 'NOME / RAZAO SOCIAL', destNome.slice(0, 64), 7.5, false);
|
|
145
|
+
this.drawBox(cmds, 360, 609, 130, 22, 'CNPJ / CPF', destDoc, 7.5, true);
|
|
146
|
+
this.drawBox(cmds, 490, 609, 85, 22, 'DATA DA EMISSAO', dhEmi.slice(0, 10), 7.5, false);
|
|
147
|
+
this.drawBox(cmds, 20, 587, 270, 22, 'ENDERECO', destEnd.slice(0, 48), 7.5, false);
|
|
148
|
+
this.drawBox(cmds, 290, 587, 120, 22, 'BAIRRO / DISTRITO', destBairro.slice(0, 24), 7.5, false);
|
|
149
|
+
this.drawBox(cmds, 410, 587, 80, 22, 'CEP', destCep, 7.5, false);
|
|
150
|
+
this.drawBox(cmds, 490, 587, 85, 22, 'DATA SAIDA/ENTRADA', dhSaiEnt.slice(0, 10), 7.5, false);
|
|
151
|
+
this.drawBox(cmds, 20, 565, 220, 22, 'MUNICIPIO', destMun, 7.5, false);
|
|
152
|
+
this.drawBox(cmds, 240, 565, 95, 22, 'FONE / FAX', destFone, 7.5, false);
|
|
153
|
+
this.drawBox(cmds, 335, 565, 30, 22, 'UF', destUf, 7.5, false);
|
|
154
|
+
this.drawBox(cmds, 365, 565, 125, 22, 'INSCRICAO ESTADUAL', destIe, 7.5, false);
|
|
155
|
+
this.drawBox(cmds, 490, 565, 85, 22, 'HORA DA SAIDA', dhSaiEnt.slice(11, 19), 7.5, false);
|
|
156
|
+
this.drawSectionHeader(cmds, 20, 554, 'FATURA / PAGAMENTO');
|
|
157
|
+
const tPag = this.getTag(detPag, 'tPag', '01');
|
|
158
|
+
const vPag = this.formatDecimal(this.getTag(detPag, 'vPag', '0.00'));
|
|
159
|
+
this.drawBox(cmds, 20, 530, 185, 22, 'FORMA DE PAGAMENTO', this.getDescricaoPagamento(tPag), 7.5, false);
|
|
160
|
+
this.drawBox(cmds, 205, 530, 185, 22, 'VALOR DO PAGAMENTO (R$)', vPag, 7.5, true);
|
|
161
|
+
this.drawBox(cmds, 390, 530, 185, 22, 'TROCO (R$)', this.formatDecimal(this.getTag(doc.getElementsByTagName('pag')[0], 'vTroco', '0.00')), 7.5, false);
|
|
162
|
+
this.drawSectionHeader(cmds, 20, 519, 'CALCULO DO IMPOSTO');
|
|
163
|
+
this.drawBox(cmds, 20, 495, 70, 22, 'BASE CALC. ICMS', this.formatDecimal(this.getTag(icmsTot, 'vBC', '0.00')), 7.5, false);
|
|
164
|
+
this.drawBox(cmds, 90, 495, 68, 22, 'VALOR DO ICMS', this.formatDecimal(this.getTag(icmsTot, 'vICMS', '0.00')), 7.5, false);
|
|
165
|
+
this.drawBox(cmds, 158, 495, 68, 22, 'BASE CALC. ICMS ST', this.formatDecimal(this.getTag(icmsTot, 'vBCST', '0.00')), 7.5, false);
|
|
166
|
+
this.drawBox(cmds, 226, 495, 68, 22, 'VALOR ICMS SUBST.', this.formatDecimal(this.getTag(icmsTot, 'vST', '0.00')), 7.5, false);
|
|
167
|
+
this.drawBox(cmds, 294, 495, 65, 22, 'V. IMP. IMPORTACAO', this.formatDecimal(this.getTag(icmsTot, 'vII', '0.00')), 7.5, false);
|
|
168
|
+
this.drawBox(cmds, 359, 495, 65, 22, 'VALOR DO FCP', this.formatDecimal(this.getTag(icmsTot, 'vFCP', '0.00')), 7.5, false);
|
|
169
|
+
this.drawBox(cmds, 424, 495, 65, 22, 'VALOR DO PIS', this.formatDecimal(this.getTag(icmsTot, 'vPIS', '0.00')), 7.5, false);
|
|
170
|
+
this.drawBox(cmds, 489, 495, 86, 22, 'V. TOTAL PRODUTOS', this.formatDecimal(this.getTag(icmsTot, 'vProd', '0.00')), 7.5, true);
|
|
171
|
+
this.drawBox(cmds, 20, 473, 70, 22, 'VALOR DO FRETE', this.formatDecimal(this.getTag(icmsTot, 'vFrete', '0.00')), 7.5, false);
|
|
172
|
+
this.drawBox(cmds, 90, 473, 68, 22, 'VALOR DO SEGURO', this.formatDecimal(this.getTag(icmsTot, 'vSeg', '0.00')), 7.5, false);
|
|
173
|
+
this.drawBox(cmds, 158, 473, 68, 22, 'DESCONTO', this.formatDecimal(this.getTag(icmsTot, 'vDesc', '0.00')), 7.5, false);
|
|
174
|
+
this.drawBox(cmds, 226, 473, 68, 22, 'OUTRAS DESPESAS', this.formatDecimal(this.getTag(icmsTot, 'vOutro', '0.00')), 7.5, false);
|
|
175
|
+
this.drawBox(cmds, 294, 473, 65, 22, 'VALOR TOTAL IPI', this.formatDecimal(this.getTag(icmsTot, 'vIPI', '0.00')), 7.5, false);
|
|
176
|
+
this.drawBox(cmds, 359, 473, 65, 22, 'V. APROX. TRIBUTOS', this.formatDecimal(this.getTag(icmsTot, 'vTotTrib', '0.00')), 7.5, false);
|
|
177
|
+
this.drawBox(cmds, 424, 473, 65, 22, 'VALOR DA COFINS', this.formatDecimal(this.getTag(icmsTot, 'vCOFINS', '0.00')), 7.5, false);
|
|
178
|
+
this.drawBox(cmds, 489, 473, 86, 22, 'V. TOTAL DA NOTA', this.formatDecimal(this.getTag(icmsTot, 'vNF', '0.00')), 8.5, true);
|
|
179
|
+
this.drawSectionHeader(cmds, 20, 462, 'TRANSPORTADOR / VOLUMES TRANSPORTADOS');
|
|
180
|
+
const modFrete = this.getTag(transp, 'modFrete', '9');
|
|
181
|
+
this.drawBox(cmds, 20, 438, 210, 22, 'NOME / RAZAO SOCIAL', this.getTag(transporta, 'xNome', ''), 7.5, false);
|
|
182
|
+
this.drawBox(cmds, 230, 438, 95, 22, 'FRETE POR CONTA', this.getDescricaoFrete(modFrete), 7, false);
|
|
183
|
+
this.drawBox(cmds, 325, 438, 65, 22, 'CODIGO ANTT', '', 7.5, false);
|
|
184
|
+
this.drawBox(cmds, 390, 438, 65, 22, 'PLACA DO VEICULO', '', 7.5, false);
|
|
185
|
+
this.drawBox(cmds, 455, 438, 25, 22, 'UF', '', 7.5, false);
|
|
186
|
+
this.drawBox(cmds, 480, 438, 95, 22, 'CNPJ / CPF', this.formatDoc(this.getTag(transporta, 'CNPJ', '')), 7.5, false);
|
|
187
|
+
this.drawBox(cmds, 20, 416, 85, 22, 'QUANTIDADE', this.getTag(vol, 'qVol', ''), 7.5, false);
|
|
188
|
+
this.drawBox(cmds, 105, 416, 110, 22, 'ESPECIE', this.getTag(vol, 'esp', ''), 7.5, false);
|
|
189
|
+
this.drawBox(cmds, 215, 416, 100, 22, 'MARCA', this.getTag(vol, 'marca', ''), 7.5, false);
|
|
190
|
+
this.drawBox(cmds, 315, 416, 90, 22, 'NUMERACAO', this.getTag(vol, 'nVol', ''), 7.5, false);
|
|
191
|
+
this.drawBox(cmds, 405, 416, 85, 22, 'PESO BRUTO', this.getTag(vol, 'pesoB', ''), 7.5, false);
|
|
192
|
+
this.drawBox(cmds, 490, 416, 85, 22, 'PESO LIQUIDO', this.getTag(vol, 'pesoL', ''), 7.5, false);
|
|
193
|
+
this.drawSectionHeader(cmds, 20, 405, 'DADOS DOS PRODUTOS / SERVICOS');
|
|
194
|
+
const headerY = 388;
|
|
195
|
+
const headerH = 14;
|
|
196
|
+
const tableBottomY = 112;
|
|
197
|
+
const tableBodyH = headerY - tableBottomY;
|
|
198
|
+
for (const col of COLUNAS_ITENS) {
|
|
199
|
+
cmds.push(`${col.x} ${headerY} ${col.w} ${headerH} re S`);
|
|
200
|
+
this.drawText(cmds, col.x + 2, headerY + 4, col.label, 5, true);
|
|
201
|
+
cmds.push(`${col.x} ${tableBottomY} ${col.w} ${tableBodyH} re S`);
|
|
202
|
+
}
|
|
203
|
+
let rowY = headerY - 11;
|
|
204
|
+
for (const item of itens) {
|
|
205
|
+
if (rowY < tableBottomY + 8)
|
|
206
|
+
break;
|
|
207
|
+
this.drawText(cmds, 22, rowY, item.cProd.slice(0, 9), 6, false);
|
|
208
|
+
this.drawText(cmds, 64, rowY, item.xProd.slice(0, 36), 6, false);
|
|
209
|
+
this.drawText(cmds, 219, rowY, item.ncm, 6, false);
|
|
210
|
+
this.drawText(cmds, 255, rowY, item.origCsosnCst, 6, false);
|
|
211
|
+
this.drawText(cmds, 283, rowY, item.cfop, 6, false);
|
|
212
|
+
this.drawText(cmds, 307, rowY, item.uCom.slice(0, 4), 6, false);
|
|
213
|
+
this.drawText(cmds, 325, rowY, item.qCom, 6, false);
|
|
214
|
+
this.drawText(cmds, 359, rowY, item.vUnCom, 6, false);
|
|
215
|
+
this.drawText(cmds, 395, rowY, item.vProd, 6, false);
|
|
216
|
+
this.drawText(cmds, 431, rowY, item.vBC, 6, false);
|
|
217
|
+
this.drawText(cmds, 465, rowY, item.vICMS, 6, false);
|
|
218
|
+
this.drawText(cmds, 497, rowY, item.vIPI, 6, false);
|
|
219
|
+
this.drawText(cmds, 525, rowY, item.pICMS, 6, false);
|
|
220
|
+
this.drawText(cmds, 551, rowY, item.pIPI, 6, false);
|
|
221
|
+
cmds.push(`[1 2] 0 d 0.25 w 20 ${rowY - 4} m 575 ${rowY - 4} l S [] 0 d 0.5 w`);
|
|
222
|
+
rowY -= 13;
|
|
223
|
+
}
|
|
224
|
+
if (tpAmb === '2') {
|
|
225
|
+
cmds.push('0.78 g');
|
|
226
|
+
this.drawText(cmds, 115, 245, 'SEM VALOR FISCAL - HOMOLOGACAO', 18, true);
|
|
227
|
+
cmds.push('0 g');
|
|
228
|
+
}
|
|
229
|
+
this.drawSectionHeader(cmds, 20, 100, 'DADOS ADICIONAIS');
|
|
230
|
+
const infCpl = this.getTag(infAdic, 'infCpl', '');
|
|
231
|
+
const textoAdicional = infCpl
|
|
232
|
+
? `${infCpl} | Status SEFAZ: ${cStat} - ${xMotivo}`
|
|
233
|
+
: `Ambiente: ${tpAmb === '2' ? '2 - Homologacao (Sem Valor Fiscal)' : '1 - Producao'} | Status SEFAZ: ${cStat} - ${xMotivo}`;
|
|
234
|
+
this.drawBox(cmds, 20, 40, 370, 57, 'INFORMACOES COMPLEMENTARES', textoAdicional.slice(0, 82), 6.5, false);
|
|
235
|
+
this.drawBox(cmds, 390, 40, 185, 57, 'RESERVADO AO FISCO', '', 6.5, false);
|
|
236
|
+
this.drawText(cmds, 543, 33, 'nfe-lib-node', 5.5, false);
|
|
237
|
+
return this.buildPdfBuffer(cmds.join('\n'));
|
|
238
|
+
}
|
|
239
|
+
static getDescricaoFrete(modFrete) {
|
|
240
|
+
const mapa = {
|
|
241
|
+
'0': '0-Remetente (CIF)',
|
|
242
|
+
'1': '1-Destinatario (FOB)',
|
|
243
|
+
'2': '2-Terceiros',
|
|
244
|
+
'3': '3-Proprio Remet.',
|
|
245
|
+
'4': '4-Proprio Dest.',
|
|
246
|
+
'9': '9-Sem Transporte',
|
|
247
|
+
};
|
|
248
|
+
return mapa[modFrete] ?? modFrete;
|
|
249
|
+
}
|
|
250
|
+
static getDescricaoPagamento(tPag) {
|
|
251
|
+
const mapa = {
|
|
252
|
+
'01': '01 - Dinheiro',
|
|
253
|
+
'02': '02 - Cheque',
|
|
254
|
+
'03': '03 - Cartao de Credito',
|
|
255
|
+
'04': '04 - Cartao de Debito',
|
|
256
|
+
'15': '15 - Boleto Bancario',
|
|
257
|
+
'17': '17 - PIX',
|
|
258
|
+
'90': '90 - Sem Pagamento',
|
|
259
|
+
'99': '99 - Outros',
|
|
260
|
+
};
|
|
261
|
+
return mapa[tPag] ?? `Codigo ${tPag}`;
|
|
262
|
+
}
|
|
263
|
+
static formatDecimal(val) {
|
|
264
|
+
const num = Number(val.replace(',', '.'));
|
|
265
|
+
if (Number.isNaN(num))
|
|
266
|
+
return val;
|
|
267
|
+
return num.toFixed(2).replace('.', ',');
|
|
268
|
+
}
|
|
269
|
+
static getTag(parent, tagName, fallback) {
|
|
270
|
+
if (!parent || typeof parent.getElementsByTagName !== 'function') {
|
|
271
|
+
return fallback;
|
|
272
|
+
}
|
|
273
|
+
const node = parent.getElementsByTagName(tagName)[0];
|
|
274
|
+
return node?.textContent?.trim() || fallback;
|
|
275
|
+
}
|
|
276
|
+
static formatDoc(doc) {
|
|
277
|
+
const digits = doc.replace(/\D/g, '');
|
|
278
|
+
if (digits.length === 14) {
|
|
279
|
+
return digits.replace(/^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})$/, '$1.$2.$3/$4-$5');
|
|
280
|
+
}
|
|
281
|
+
if (digits.length === 11) {
|
|
282
|
+
return digits.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})$/, '$1.$2.$3-$4');
|
|
283
|
+
}
|
|
284
|
+
return doc;
|
|
285
|
+
}
|
|
286
|
+
static formatDateTime(iso) {
|
|
287
|
+
if (!iso || iso.length < 19)
|
|
288
|
+
return iso;
|
|
289
|
+
const datePart = `${iso.slice(8, 10)}/${iso.slice(5, 7)}/${iso.slice(0, 4)}`;
|
|
290
|
+
const timePart = iso.slice(11, 19);
|
|
291
|
+
return `${datePart} ${timePart}`;
|
|
292
|
+
}
|
|
293
|
+
static drawSectionHeader(cmds, x, y, title) {
|
|
294
|
+
this.drawText(cmds, x, y, title, 6, true);
|
|
295
|
+
}
|
|
296
|
+
static drawBox(cmds, x, y, w, h, label, value = '', valueSize = 7.5, boldValue = false) {
|
|
297
|
+
cmds.push(`${x} ${y} ${w} ${h} re S`);
|
|
298
|
+
if (label) {
|
|
299
|
+
this.drawText(cmds, x + 2.5, y + h - 6.5, label, 5, false);
|
|
300
|
+
}
|
|
301
|
+
if (value) {
|
|
302
|
+
this.drawText(cmds, x + 2.5, y + 4.5, value, valueSize, boldValue);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
static drawText(cmds, x, y, text, size, bold) {
|
|
306
|
+
const font = bold ? '/F2' : '/F1';
|
|
307
|
+
const escaped = this.escapePdfText(text);
|
|
308
|
+
cmds.push(`BT ${font} ${size} Tf ${x} ${y} Td (${escaped}) Tj ET`);
|
|
309
|
+
}
|
|
310
|
+
static escapePdfText(text) {
|
|
311
|
+
return text
|
|
312
|
+
.normalize('NFD')
|
|
313
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
314
|
+
.replace(/\\/g, '\\\\')
|
|
315
|
+
.replace(/\(/g, '\\(')
|
|
316
|
+
.replace(/\)/g, '\\)');
|
|
317
|
+
}
|
|
318
|
+
static drawCode128C(cmds, digits, x, y, width, height) {
|
|
319
|
+
const clean = digits.replace(/\D/g, '').padStart(44, '0').slice(0, 44);
|
|
320
|
+
const codes = [105];
|
|
321
|
+
let checksum = 105;
|
|
322
|
+
for (let i = 0; i < clean.length; i += 2) {
|
|
323
|
+
const pairVal = parseInt(clean.slice(i, i + 2), 10);
|
|
324
|
+
codes.push(pairVal);
|
|
325
|
+
checksum += pairVal * (i / 2 + 1);
|
|
326
|
+
}
|
|
327
|
+
codes.push(checksum % 103);
|
|
328
|
+
codes.push(106);
|
|
329
|
+
const patterns = codes.map((c) => CODE128_PATTERNS[c] ?? '212222');
|
|
330
|
+
const totalModules = patterns.reduce((acc, p) => acc + p.split('').reduce((s, d) => s + Number(d), 0), 0);
|
|
331
|
+
const moduleWidth = width / totalModules;
|
|
332
|
+
let cursorX = x;
|
|
333
|
+
for (const pattern of patterns) {
|
|
334
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
335
|
+
const modCount = Number(pattern[i] ?? '1');
|
|
336
|
+
const barW = modCount * moduleWidth;
|
|
337
|
+
if (i % 2 === 0) {
|
|
338
|
+
cmds.push(`${cursorX.toFixed(2)} ${y.toFixed(2)} ${barW.toFixed(2)} ${height.toFixed(2)} re f`);
|
|
339
|
+
}
|
|
340
|
+
cursorX += barW;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
static buildPdfBuffer(contentStream) {
|
|
345
|
+
const streamBytes = Buffer.byteLength(contentStream, 'latin1');
|
|
346
|
+
const objects = [
|
|
347
|
+
'1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n',
|
|
348
|
+
'2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n',
|
|
349
|
+
'3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595.28 841.89] /Resources << /Font << /F1 4 0 R /F2 5 0 R >> >> /Contents 6 0 R >>\nendobj\n',
|
|
350
|
+
'4 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>\nendobj\n',
|
|
351
|
+
'5 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>\nendobj\n',
|
|
352
|
+
`6 0 obj\n<< /Length ${streamBytes} >>\nstream\n${contentStream}\nendstream\nendobj\n`,
|
|
353
|
+
];
|
|
354
|
+
let pdf = '%PDF-1.4\n';
|
|
355
|
+
const offsets = [0];
|
|
356
|
+
for (const obj of objects) {
|
|
357
|
+
offsets.push(Buffer.byteLength(pdf, 'latin1'));
|
|
358
|
+
pdf += obj;
|
|
359
|
+
}
|
|
360
|
+
const xrefStart = Buffer.byteLength(pdf, 'latin1');
|
|
361
|
+
pdf += `xref\n0 ${objects.length + 1}\n`;
|
|
362
|
+
pdf += '0000000000 65535 f \n';
|
|
363
|
+
for (let i = 1; i <= objects.length; i++) {
|
|
364
|
+
const offset = offsets[i] ?? 0;
|
|
365
|
+
pdf += `${String(offset).padStart(10, '0')} 00000 n \n`;
|
|
366
|
+
}
|
|
367
|
+
pdf += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xrefStart}\n%%EOF\n`;
|
|
368
|
+
return Buffer.from(pdf, 'latin1');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=Danfe.js.map
|