ghinfe 0.6.0 → 0.6.2

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 (110) hide show
  1. package/.env.example +24 -15
  2. package/LICENSE +21 -21
  3. package/README.md +491 -413
  4. package/docs/developer-guide.html +421 -421
  5. package/docs/openapi.yaml +428 -428
  6. package/examples/dce-homologacao.js +141 -0
  7. package/examples/emitir-nfce.js +51 -51
  8. package/examples/emitir-nfe.js +83 -83
  9. package/examples/emitir-nfse.js +46 -46
  10. package/examples/endpoints-sefaz.js +14 -14
  11. package/examples/eventos-nfe.js +49 -49
  12. package/examples/gerar-chave.js +25 -25
  13. package/examples/gerar-dace.js +59 -0
  14. package/examples/gerar-danfe.js +75 -75
  15. package/examples/gerar-dce.js +58 -0
  16. package/examples/layouts-nfse.js +51 -51
  17. package/examples/mock-sefaz.js +52 -52
  18. package/examples/nfse-eventos.js +57 -57
  19. package/examples/reforma-ibscbs.js +27 -27
  20. package/examples/reforma-nfe-xml.js +52 -52
  21. package/examples/status-sefaz.js +12 -12
  22. package/examples/validar-xsd.js +48 -48
  23. package/package.json +59 -68
  24. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/consSitDCeTiposBasico_v1.00.xsd +123 -0
  25. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/consSitDCe_v1.00.xsd +10 -0
  26. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/consStatServDCeTiposBasico_v1.00.xsd +110 -0
  27. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/consStatServDCe_v1.00.xsd +10 -0
  28. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/dceTiposBasico_v1.00.xsd +1388 -0
  29. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/retConsSitDCe_v1.00.xsd +10 -0
  30. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/retConsStatServDCe_v1.00.xsd +10 -0
  31. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/tiposGeralDCe_v1.00.xsd +712 -0
  32. package/schemas/dce/PL_DCe_100a_NT2024.001/consulta/xmldsig-core-schema_v1.01.xsd +98 -0
  33. package/schemas/dce/PL_DCe_100a_NT2024.001/dceTiposBasico_v1.00.xsd +1410 -0
  34. package/schemas/dce/PL_DCe_100a_NT2024.001/dce_v1.00.xsd +10 -0
  35. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/evCancDCe_v1.00.xsd +36 -0
  36. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/eventoDCeTiposBasico_v1.00.xsd +283 -0
  37. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/eventoDCe_v1.00.xsd +9 -0
  38. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/procEventoDCe_v1.00.xsd +10 -0
  39. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/retEventoDCe_v1.00.xsd +9 -0
  40. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/tiposGeralDCe_v1.00.xsd +712 -0
  41. package/schemas/dce/PL_DCe_100a_NT2024.001/evento/xmldsig-core-schema_v1.01.xsd +98 -0
  42. package/schemas/dce/PL_DCe_100a_NT2024.001/procDCe_v1.00.xsd +37 -0
  43. package/schemas/dce/PL_DCe_100a_NT2024.001/retDCe_v1.00.xsd +9 -0
  44. package/schemas/dce/PL_DCe_100a_NT2024.001/tiposGeralDCe_v1.00.xsd +712 -0
  45. package/schemas/dce/PL_DCe_100a_NT2024.001/xmldsig-core-schema_v1.01.xsd +98 -0
  46. package/schemas/nfe/PL_009_V4/enviNFe_v3.10.xsd +8 -8
  47. package/schemas/nfe/PL_009_V4/xmldsig-core-schema_v1.01.xsd +97 -97
  48. package/scripts/download-schemas.js +39 -39
  49. package/scripts/test-xsd.js +34 -34
  50. package/src/api/server.js +316 -316
  51. package/src/constants/sefaz.js +69 -69
  52. package/src/danfe/DanfeService.js +205 -205
  53. package/src/danfe/xml-extract.js +69 -69
  54. package/src/dce/builders/DCeEventoXmlBuilder.js +86 -0
  55. package/src/dce/builders/DCeXmlBuilder.js +345 -0
  56. package/src/dce/constants/dce.js +87 -0
  57. package/src/dce/dace/DaceService.js +356 -0
  58. package/src/dce/dace/dace-extract.js +114 -0
  59. package/src/dce/services/DCeService.js +263 -0
  60. package/src/dce/services/DCeSoapService.js +235 -0
  61. package/src/dce/services/DCeXmlService.js +67 -0
  62. package/src/dce/types/DCeDocument.js +106 -0
  63. package/src/dce/utils/qrcode.utils.js +59 -0
  64. package/src/errors/GhinfeError.js +13 -13
  65. package/src/errors/SefazError.js +25 -25
  66. package/src/errors/XsdValidationError.js +15 -15
  67. package/src/index.js +84 -60
  68. package/src/nfce/builders/NFCeXmlBuilder.js +178 -178
  69. package/src/nfce/constants/qrcode.js +26 -26
  70. package/src/nfce/services/NFCeService.js +188 -188
  71. package/src/nfce/services/NFCeXmlService.js +38 -38
  72. package/src/nfce/types/NFCeDocument.js +42 -42
  73. package/src/nfce/utils/qrcode.utils.js +92 -92
  74. package/src/nfe/builders/NFeEventoXmlBuilder.js +110 -110
  75. package/src/nfe/builders/NFeXmlBuilder.js +215 -215
  76. package/src/nfe/mocks/sefaz-responses.js +195 -195
  77. package/src/nfe/services/NFeEventoService.js +95 -95
  78. package/src/nfe/services/NFeService.js +196 -196
  79. package/src/nfe/services/NFeSignService.js +127 -111
  80. package/src/nfe/services/NFeSoapService.js +437 -437
  81. package/src/nfe/services/NFeXmlService.js +41 -41
  82. package/src/nfe/services/NFeXsdService.js +56 -56
  83. package/src/nfe/types/NFeDocument.js +92 -92
  84. package/src/nfe/types/NFeEvento.js +44 -44
  85. package/src/nfse/NFSeMunicipioResolver.js +42 -42
  86. package/src/nfse/builders/NFSeEventoXmlBuilder.js +92 -92
  87. package/src/nfse/builders/NFSeXmlBuilder.js +16 -16
  88. package/src/nfse/constants/municipios.js +82 -82
  89. package/src/nfse/layouts/adapters.js +202 -202
  90. package/src/nfse/mocks/nfse-responses.js +142 -142
  91. package/src/nfse/services/NFSeService.js +191 -191
  92. package/src/nfse/services/NFSeSoapService.js +232 -232
  93. package/src/nfse/services/NFSeXmlService.js +12 -12
  94. package/src/nfse/types/NFSeDocument.js +54 -54
  95. package/src/queue/NFCeQueue.js +63 -63
  96. package/src/queue/NFSeQueue.js +59 -59
  97. package/src/queue/NFeQueue.js +76 -76
  98. package/src/reforma/ibscbs.js +175 -175
  99. package/src/sefaz/SefazEndpointResolver.js +95 -95
  100. package/src/sefaz/ca/icp-brasil-raiz-v10.pem +38 -0
  101. package/src/sefaz/endpoints.registry.js +205 -205
  102. package/src/sefaz/httpsAgent.js +33 -0
  103. package/src/shared/fiscal.helpers.js +53 -53
  104. package/src/utils/certificate.utils.js +69 -47
  105. package/src/utils/chave.utils.js +205 -117
  106. package/src/utils/code128.utils.js +67 -0
  107. package/src/utils/date.utils.js +26 -26
  108. package/src/utils/xml.utils.js +44 -44
  109. package/src/validation/XsdValidator.js +133 -114
  110. package/src/validation/schemas.js +18 -14
@@ -1,92 +1,92 @@
1
- import crypto from 'crypto';
2
- import { NFCE_QRCODE_URLS, NFCE_URL_CHAVE } from '../constants/qrcode.js';
3
- import { GhinfeError } from '../../errors/GhinfeError.js';
4
-
5
- /**
6
- * Extrai DigestValue da assinatura XML para compor QR Code v3.
7
- * @param {string} xmlAssinado
8
- */
9
- export function extrairDigestValor(xmlAssinado) {
10
- const match = xmlAssinado.match(/<DigestValue>([^<]+)<\/DigestValue>/);
11
- return match?.[1] ?? '';
12
- }
13
-
14
- /**
15
- * Gera hash QR Code NFC-e versão 3.
16
- * SHA1(chave + versao + tpAmb + cDest + vNF + vICMS + digVal + idCSC + CSC)
17
- */
18
- export function gerarHashQrCodeV3(chaveAcesso, ambiente, cDest, vNF, vICMS, digVal, idCSC, csc) {
19
- const vNFStr = Number(vNF).toFixed(2);
20
- const vICMSStr = Number(vICMS).toFixed(2);
21
- const id = idCSC.padStart(6, '0');
22
- const input = `${chaveAcesso}3${ambiente}${cDest}${vNFStr}${vICMSStr}${digVal}${id}${csc}`;
23
- return crypto.createHash('sha1').update(input).digest('hex').toUpperCase();
24
- }
25
-
26
- /**
27
- * Monta URL do QR Code NFC-e versão 3 (layout exigido pelo XSD PL_009_V4).
28
- * @param {{
29
- * chaveAcesso: string,
30
- * uf: string,
31
- * ambiente?: number,
32
- * cDest?: string,
33
- * valorNF: number,
34
- * valorICMS?: number,
35
- * digVal: string,
36
- * idCSC: string,
37
- * csc: string,
38
- * }} params
39
- */
40
- export function gerarUrlQrCodeV3(params) {
41
- const ambiente = params.ambiente ?? 2;
42
- const uf = params.uf.toUpperCase();
43
- const baseUrl = NFCE_QRCODE_URLS[uf]?.[ambiente];
44
-
45
- if (!baseUrl) {
46
- throw new GhinfeError(
47
- `URL de QR Code NFC-e não configurada para UF ${uf} ambiente ${ambiente}`,
48
- 'NFCE_QRCODE_URL_MISSING'
49
- );
50
- }
51
-
52
- const cDest = (params.cDest ?? '').replace(/\D/g, '');
53
- const vNFStr = Number(params.valorNF).toFixed(2);
54
- const vICMSStr = Number(params.valorICMS ?? 0).toFixed(2);
55
- const idCSC = params.idCSC.padStart(6, '0');
56
- const hash = gerarHashQrCodeV3(
57
- params.chaveAcesso,
58
- ambiente,
59
- cDest,
60
- params.valorNF,
61
- params.valorICMS ?? 0,
62
- params.digVal,
63
- idCSC,
64
- params.csc
65
- );
66
-
67
- const p = `${params.chaveAcesso}|3|${ambiente}|${cDest}|${vNFStr}|${vICMSStr}|${params.digVal}|${idCSC}|${hash}`;
68
- return `${baseUrl}?p=${p}`;
69
- }
70
-
71
- /**
72
- * @param {string} uf
73
- * @param {number} [ambiente]
74
- */
75
- export function obterUrlChave(uf, ambiente = 2) {
76
- const url = NFCE_URL_CHAVE[uf.toUpperCase()]?.[ambiente];
77
- if (!url) {
78
- return NFCE_QRCODE_URLS[uf.toUpperCase()]?.[ambiente] ?? 'https://www.nfce.fazenda.sp.gov.br/consulta';
79
- }
80
- return url;
81
- }
82
-
83
- /**
84
- * Insere infNFeSupl no XML assinado da NFC-e.
85
- * @param {string} xmlAssinado
86
- * @param {string} qrCodeUrl
87
- * @param {string} urlChave
88
- */
89
- export function inserirInfNFeSupl(xmlAssinado, qrCodeUrl, urlChave) {
90
- const supl = `<infNFeSupl><qrCode><![CDATA[${qrCodeUrl}]]></qrCode><urlChave>${urlChave}</urlChave></infNFeSupl>`;
91
- return xmlAssinado.replace('</NFe>', `${supl}</NFe>`);
92
- }
1
+ import crypto from 'crypto';
2
+ import { NFCE_QRCODE_URLS, NFCE_URL_CHAVE } from '../constants/qrcode.js';
3
+ import { GhinfeError } from '../../errors/GhinfeError.js';
4
+
5
+ /**
6
+ * Extrai DigestValue da assinatura XML para compor QR Code v3.
7
+ * @param {string} xmlAssinado
8
+ */
9
+ export function extrairDigestValor(xmlAssinado) {
10
+ const match = xmlAssinado.match(/<DigestValue>([^<]+)<\/DigestValue>/);
11
+ return match?.[1] ?? '';
12
+ }
13
+
14
+ /**
15
+ * Gera hash QR Code NFC-e versão 3.
16
+ * SHA1(chave + versao + tpAmb + cDest + vNF + vICMS + digVal + idCSC + CSC)
17
+ */
18
+ export function gerarHashQrCodeV3(chaveAcesso, ambiente, cDest, vNF, vICMS, digVal, idCSC, csc) {
19
+ const vNFStr = Number(vNF).toFixed(2);
20
+ const vICMSStr = Number(vICMS).toFixed(2);
21
+ const id = idCSC.padStart(6, '0');
22
+ const input = `${chaveAcesso}3${ambiente}${cDest}${vNFStr}${vICMSStr}${digVal}${id}${csc}`;
23
+ return crypto.createHash('sha1').update(input).digest('hex').toUpperCase();
24
+ }
25
+
26
+ /**
27
+ * Monta URL do QR Code NFC-e versão 3 (layout exigido pelo XSD PL_009_V4).
28
+ * @param {{
29
+ * chaveAcesso: string,
30
+ * uf: string,
31
+ * ambiente?: number,
32
+ * cDest?: string,
33
+ * valorNF: number,
34
+ * valorICMS?: number,
35
+ * digVal: string,
36
+ * idCSC: string,
37
+ * csc: string,
38
+ * }} params
39
+ */
40
+ export function gerarUrlQrCodeV3(params) {
41
+ const ambiente = params.ambiente ?? 2;
42
+ const uf = params.uf.toUpperCase();
43
+ const baseUrl = NFCE_QRCODE_URLS[uf]?.[ambiente];
44
+
45
+ if (!baseUrl) {
46
+ throw new GhinfeError(
47
+ `URL de QR Code NFC-e não configurada para UF ${uf} ambiente ${ambiente}`,
48
+ 'NFCE_QRCODE_URL_MISSING'
49
+ );
50
+ }
51
+
52
+ const cDest = (params.cDest ?? '').replace(/\D/g, '');
53
+ const vNFStr = Number(params.valorNF).toFixed(2);
54
+ const vICMSStr = Number(params.valorICMS ?? 0).toFixed(2);
55
+ const idCSC = params.idCSC.padStart(6, '0');
56
+ const hash = gerarHashQrCodeV3(
57
+ params.chaveAcesso,
58
+ ambiente,
59
+ cDest,
60
+ params.valorNF,
61
+ params.valorICMS ?? 0,
62
+ params.digVal,
63
+ idCSC,
64
+ params.csc
65
+ );
66
+
67
+ const p = `${params.chaveAcesso}|3|${ambiente}|${cDest}|${vNFStr}|${vICMSStr}|${params.digVal}|${idCSC}|${hash}`;
68
+ return `${baseUrl}?p=${p}`;
69
+ }
70
+
71
+ /**
72
+ * @param {string} uf
73
+ * @param {number} [ambiente]
74
+ */
75
+ export function obterUrlChave(uf, ambiente = 2) {
76
+ const url = NFCE_URL_CHAVE[uf.toUpperCase()]?.[ambiente];
77
+ if (!url) {
78
+ return NFCE_QRCODE_URLS[uf.toUpperCase()]?.[ambiente] ?? 'https://www.nfce.fazenda.sp.gov.br/consulta';
79
+ }
80
+ return url;
81
+ }
82
+
83
+ /**
84
+ * Insere infNFeSupl no XML assinado da NFC-e.
85
+ * @param {string} xmlAssinado
86
+ * @param {string} qrCodeUrl
87
+ * @param {string} urlChave
88
+ */
89
+ export function inserirInfNFeSupl(xmlAssinado, qrCodeUrl, urlChave) {
90
+ const supl = `<infNFeSupl><qrCode><![CDATA[${qrCodeUrl}]]></qrCode><urlChave>${urlChave}</urlChave></infNFeSupl>`;
91
+ return xmlAssinado.replace('</NFe>', `${supl}</NFe>`);
92
+ }
@@ -1,110 +1,110 @@
1
- import { create } from 'xmlbuilder2';
2
- import { UF_IBGE } from '../../constants/sefaz.js';
3
- import { NFE_EVENTOS, CCE_COND_USO } from '../types/NFeEvento.js';
4
- import { formatSefazDateTime } from '../../utils/date.utils.js';
5
- import { GhinfeError } from '../../errors/GhinfeError.js';
6
-
7
- const VERSAO_EVENTO = '1.00';
8
-
9
- /**
10
- * Monta XML de eventos NF-e (cancelamento, CC-e, etc.).
11
- */
12
- export class NFeEventoXmlBuilder {
13
- /**
14
- * @param {import('../types/NFeEvento.js').NFeCancelamento} dados
15
- * @returns {string}
16
- */
17
- buildCancelamento(dados) {
18
- this.#validarBase(dados);
19
- if (!dados.protocolo) {
20
- throw new GhinfeError('protocolo é obrigatório para cancelamento', 'CANCEL_PROTOCOLO_REQUIRED');
21
- }
22
- if (!dados.justificativa || dados.justificativa.trim().length < 15) {
23
- throw new GhinfeError(
24
- 'justificativa deve ter no mínimo 15 caracteres',
25
- 'CANCEL_JUSTIFICATIVA_MIN'
26
- );
27
- }
28
-
29
- return this.#buildEvento(dados, NFE_EVENTOS.CANCELAMENTO, (det) => {
30
- det.ele('descEvento').txt('Cancelamento').up();
31
- det.ele('nProt').txt(dados.protocolo).up();
32
- det.ele('xJust').txt(dados.justificativa.trim()).up();
33
- });
34
- }
35
-
36
- /**
37
- * @param {import('../types/NFeEvento.js').NFeCartaCorrecao} dados
38
- * @returns {string}
39
- */
40
- buildCartaCorrecao(dados) {
41
- this.#validarBase(dados);
42
- if (!dados.correcao || dados.correcao.trim().length < 15) {
43
- throw new GhinfeError(
44
- 'correcao deve ter no mínimo 15 caracteres',
45
- 'CCE_TEXTO_MIN'
46
- );
47
- }
48
- if (dados.correcao.length > 1000) {
49
- throw new GhinfeError('correcao não pode exceder 1000 caracteres', 'CCE_TEXTO_MAX');
50
- }
51
-
52
- return this.#buildEvento(dados, NFE_EVENTOS.CARTA_CORRECAO, (det) => {
53
- det.ele('descEvento').txt('Carta de Correcao').up();
54
- det.ele('xCorrecao').txt(dados.correcao.trim()).up();
55
- det.ele('xCondUso').txt(CCE_COND_USO).up();
56
- });
57
- }
58
-
59
- /**
60
- * @param {import('../types/NFeEvento.js').NFeEventoBase} dados
61
- * @param {string} tpEvento
62
- * @param {(det: import('xmlbuilder2').XMLBuilder) => void} buildDetEvento
63
- */
64
- #buildEvento(dados, tpEvento, buildDetEvento) {
65
- const sequencia = dados.sequencia ?? 1;
66
- const idLote = dados.idLote ?? '1';
67
- const cOrgao = UF_IBGE[dados.uf.toUpperCase()] ?? '35';
68
- const dhEvento = formatSefazDateTime();
69
- const idInfEvento = `ID${tpEvento}${dados.chaveAcesso}${String(sequencia).padStart(2, '0')}`;
70
-
71
- const root = create({ version: '1.0', encoding: 'UTF-8' })
72
- .ele('envEvento', { xmlns: 'http://www.portalfiscal.inf.br/nfe', versao: VERSAO_EVENTO })
73
- .ele('idLote').txt(idLote).up();
74
-
75
- const evento = root.ele('evento', { versao: VERSAO_EVENTO });
76
- const infEvento = evento.ele('infEvento', { Id: idInfEvento });
77
-
78
- infEvento
79
- .ele('cOrgao').txt(cOrgao).up()
80
- .ele('tpAmb').txt(String(dados.ambiente ?? 2)).up()
81
- .ele('CNPJ').txt(dados.cnpj.replace(/\D/g, '')).up()
82
- .ele('chNFe').txt(dados.chaveAcesso).up()
83
- .ele('dhEvento').txt(dhEvento).up()
84
- .ele('tpEvento').txt(tpEvento).up()
85
- .ele('nSeqEvento').txt(String(sequencia)).up()
86
- .ele('verEvento').txt(VERSAO_EVENTO).up();
87
-
88
- const detEvento = infEvento.ele('detEvento', { versao: VERSAO_EVENTO });
89
- buildDetEvento(detEvento);
90
- detEvento.up();
91
- infEvento.up();
92
- evento.up();
93
-
94
- return root.end({ prettyPrint: false, headless: false });
95
- }
96
-
97
- /** @param {import('../types/NFeEvento.js').NFeEventoBase} dados */
98
- #validarBase(dados) {
99
- const chave = dados.chaveAcesso?.replace(/\D/g, '');
100
- if (!chave || chave.length !== 44) {
101
- throw new GhinfeError('chaveAcesso deve conter 44 dígitos', 'INVALID_CHAVE');
102
- }
103
- if (!dados.cnpj) {
104
- throw new GhinfeError('cnpj do autor do evento é obrigatório', 'INVALID_CNPJ');
105
- }
106
- if (!dados.uf) {
107
- throw new GhinfeError('uf é obrigatória', 'INVALID_UF');
108
- }
109
- }
110
- }
1
+ import { create } from 'xmlbuilder2';
2
+ import { UF_IBGE } from '../../constants/sefaz.js';
3
+ import { NFE_EVENTOS, CCE_COND_USO } from '../types/NFeEvento.js';
4
+ import { formatSefazDateTime } from '../../utils/date.utils.js';
5
+ import { GhinfeError } from '../../errors/GhinfeError.js';
6
+
7
+ const VERSAO_EVENTO = '1.00';
8
+
9
+ /**
10
+ * Monta XML de eventos NF-e (cancelamento, CC-e, etc.).
11
+ */
12
+ export class NFeEventoXmlBuilder {
13
+ /**
14
+ * @param {import('../types/NFeEvento.js').NFeCancelamento} dados
15
+ * @returns {string}
16
+ */
17
+ buildCancelamento(dados) {
18
+ this.#validarBase(dados);
19
+ if (!dados.protocolo) {
20
+ throw new GhinfeError('protocolo é obrigatório para cancelamento', 'CANCEL_PROTOCOLO_REQUIRED');
21
+ }
22
+ if (!dados.justificativa || dados.justificativa.trim().length < 15) {
23
+ throw new GhinfeError(
24
+ 'justificativa deve ter no mínimo 15 caracteres',
25
+ 'CANCEL_JUSTIFICATIVA_MIN'
26
+ );
27
+ }
28
+
29
+ return this.#buildEvento(dados, NFE_EVENTOS.CANCELAMENTO, (det) => {
30
+ det.ele('descEvento').txt('Cancelamento').up();
31
+ det.ele('nProt').txt(dados.protocolo).up();
32
+ det.ele('xJust').txt(dados.justificativa.trim()).up();
33
+ });
34
+ }
35
+
36
+ /**
37
+ * @param {import('../types/NFeEvento.js').NFeCartaCorrecao} dados
38
+ * @returns {string}
39
+ */
40
+ buildCartaCorrecao(dados) {
41
+ this.#validarBase(dados);
42
+ if (!dados.correcao || dados.correcao.trim().length < 15) {
43
+ throw new GhinfeError(
44
+ 'correcao deve ter no mínimo 15 caracteres',
45
+ 'CCE_TEXTO_MIN'
46
+ );
47
+ }
48
+ if (dados.correcao.length > 1000) {
49
+ throw new GhinfeError('correcao não pode exceder 1000 caracteres', 'CCE_TEXTO_MAX');
50
+ }
51
+
52
+ return this.#buildEvento(dados, NFE_EVENTOS.CARTA_CORRECAO, (det) => {
53
+ det.ele('descEvento').txt('Carta de Correcao').up();
54
+ det.ele('xCorrecao').txt(dados.correcao.trim()).up();
55
+ det.ele('xCondUso').txt(CCE_COND_USO).up();
56
+ });
57
+ }
58
+
59
+ /**
60
+ * @param {import('../types/NFeEvento.js').NFeEventoBase} dados
61
+ * @param {string} tpEvento
62
+ * @param {(det: import('xmlbuilder2').XMLBuilder) => void} buildDetEvento
63
+ */
64
+ #buildEvento(dados, tpEvento, buildDetEvento) {
65
+ const sequencia = dados.sequencia ?? 1;
66
+ const idLote = dados.idLote ?? '1';
67
+ const cOrgao = UF_IBGE[dados.uf.toUpperCase()] ?? '35';
68
+ const dhEvento = formatSefazDateTime();
69
+ const idInfEvento = `ID${tpEvento}${dados.chaveAcesso}${String(sequencia).padStart(2, '0')}`;
70
+
71
+ const root = create({ version: '1.0', encoding: 'UTF-8' })
72
+ .ele('envEvento', { xmlns: 'http://www.portalfiscal.inf.br/nfe', versao: VERSAO_EVENTO })
73
+ .ele('idLote').txt(idLote).up();
74
+
75
+ const evento = root.ele('evento', { versao: VERSAO_EVENTO });
76
+ const infEvento = evento.ele('infEvento', { Id: idInfEvento });
77
+
78
+ infEvento
79
+ .ele('cOrgao').txt(cOrgao).up()
80
+ .ele('tpAmb').txt(String(dados.ambiente ?? 2)).up()
81
+ .ele('CNPJ').txt(dados.cnpj.replace(/\D/g, '')).up()
82
+ .ele('chNFe').txt(dados.chaveAcesso).up()
83
+ .ele('dhEvento').txt(dhEvento).up()
84
+ .ele('tpEvento').txt(tpEvento).up()
85
+ .ele('nSeqEvento').txt(String(sequencia)).up()
86
+ .ele('verEvento').txt(VERSAO_EVENTO).up();
87
+
88
+ const detEvento = infEvento.ele('detEvento', { versao: VERSAO_EVENTO });
89
+ buildDetEvento(detEvento);
90
+ detEvento.up();
91
+ infEvento.up();
92
+ evento.up();
93
+
94
+ return root.end({ prettyPrint: false, headless: false });
95
+ }
96
+
97
+ /** @param {import('../types/NFeEvento.js').NFeEventoBase} dados */
98
+ #validarBase(dados) {
99
+ const chave = dados.chaveAcesso?.replace(/\D/g, '');
100
+ if (!chave || chave.length !== 44) {
101
+ throw new GhinfeError('chaveAcesso deve conter 44 dígitos', 'INVALID_CHAVE');
102
+ }
103
+ if (!dados.cnpj) {
104
+ throw new GhinfeError('cnpj do autor do evento é obrigatório', 'INVALID_CNPJ');
105
+ }
106
+ if (!dados.uf) {
107
+ throw new GhinfeError('uf é obrigatória', 'INVALID_UF');
108
+ }
109
+ }
110
+ }