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,232 +1,232 @@
1
- import axios from 'axios';
2
- import { GhinfeError } from '../../errors/GhinfeError.js';
3
- import { NFSeMunicipioResolver } from '../NFSeMunicipioResolver.js';
4
- import {
5
- buildMockGerarNfseResponse,
6
- buildMockCancelarNfseResponse,
7
- buildMockSubstituirNfseResponse,
8
- NFSE_MOCK_RESPONSES,
9
- } from '../mocks/nfse-responses.js';
10
-
11
- export class NFSeSoapError extends GhinfeError {
12
- /**
13
- * @param {string} codigo
14
- * @param {string} mensagem
15
- * @param {Record<string, unknown>} [details]
16
- */
17
- constructor(codigo, mensagem, details = {}) {
18
- super(`NFS-e [${codigo}]: ${mensagem}`, `NFSE_${codigo}`, { codigo, mensagem, ...details });
19
- this.name = 'NFSeSoapError';
20
- this.codigo = codigo;
21
- }
22
- }
23
-
24
- /**
25
- * Comunicação SOAP com prefeituras (NFS-e ABRASF).
26
- */
27
- export class NFSeSoapService {
28
- /**
29
- * @param {{ mock?: boolean, endpoint?: string, timeout?: number, mockScenario?: string }} [options]
30
- */
31
- constructor(options = {}) {
32
- this.mock = options.mock ?? true;
33
- this.endpoint = options.endpoint;
34
- this.timeout = options.timeout ?? 30000;
35
- this.mockScenario = options.mockScenario ?? 'autorizada';
36
- }
37
-
38
- /**
39
- * @param {string} xmlRps
40
- * @param {string} codigoMunicipio
41
- * @param {number} [ambiente]
42
- */
43
- async gerarNfse(xmlRps, codigoMunicipio, ambiente = 2) {
44
- if (this.mock) {
45
- return this.#mockGerarNfse(xmlRps);
46
- }
47
-
48
- const { url } = this.endpoint
49
- ? { url: this.endpoint }
50
- : NFSeMunicipioResolver.resolver(codigoMunicipio, ambiente);
51
-
52
- const envelope = this.#buildEnvelope('GerarNfse', xmlRps);
53
-
54
- try {
55
- const response = await axios.post(url, envelope, {
56
- headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: 'GerarNfse' },
57
- timeout: this.timeout,
58
- responseType: 'text',
59
- });
60
-
61
- return this.#processarRetorno(response.data);
62
- } catch (error) {
63
- if (axios.isAxiosError(error)) {
64
- throw new GhinfeError(`Falha SOAP NFS-e: ${error.message}`, 'NFSE_HTTP_ERROR', {
65
- status: error.response?.status,
66
- });
67
- }
68
- throw error;
69
- }
70
- }
71
-
72
- /** @param {string} metodo @param {string} xml */
73
- #buildEnvelope(metodo, xml) {
74
- const escaped = xml.replace(/</g, '&lt;').replace(/>/g, '&gt;');
75
- return `<?xml version="1.0" encoding="utf-8"?>
76
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
77
- <soap:Body>
78
- <${metodo} xmlns="http://www.abrasf.org.br/nfse.xsd">
79
- <nfseDadosMsg>${escaped}</nfseDadosMsg>
80
- </${metodo}>
81
- </soap:Body>
82
- </soap:Envelope>`;
83
- }
84
-
85
- /**
86
- * @param {string} xmlCancelamento
87
- * @param {string} codigoMunicipio
88
- * @param {number} [ambiente]
89
- */
90
- async cancelarNfse(xmlCancelamento, codigoMunicipio, ambiente = 2) {
91
- if (this.mock) {
92
- await new Promise((r) => setTimeout(r, 150));
93
- const numero = xmlCancelamento.match(/<Numero>(\d+)<\/Numero>/)?.[1] ?? '';
94
- const resultado = this.mockScenario === 'rejeicao'
95
- ? NFSE_MOCK_RESPONSES.rejeicao
96
- : NFSE_MOCK_RESPONSES.cancelada;
97
- const xml = buildMockCancelarNfseResponse(numero, resultado);
98
- return this.#processarRetornoEvento(xml, { mock: true, operacao: 'cancelamento' });
99
- }
100
-
101
- return this.#postMetodo('CancelarNfse', xmlCancelamento, codigoMunicipio, ambiente, 'cancelamento');
102
- }
103
-
104
- /**
105
- * @param {string} xmlSubstituicao
106
- * @param {string} codigoMunicipio
107
- * @param {number} [ambiente]
108
- */
109
- async substituirNfse(xmlSubstituicao, codigoMunicipio, ambiente = 2) {
110
- if (this.mock) {
111
- await new Promise((r) => setTimeout(r, 150));
112
- const resultado = this.mockScenario === 'rejeicao'
113
- ? NFSE_MOCK_RESPONSES.rejeicao
114
- : NFSE_MOCK_RESPONSES.substituida;
115
- const xml = buildMockSubstituirNfseResponse(resultado);
116
- return this.#processarRetornoEvento(xml, { mock: true, operacao: 'substituicao' });
117
- }
118
-
119
- return this.#postMetodo('SubstituirNfse', xmlSubstituicao, codigoMunicipio, ambiente, 'substituicao');
120
- }
121
-
122
- /**
123
- * @param {string} metodo
124
- * @param {string} xml
125
- * @param {string} codigoMunicipio
126
- * @param {number} ambiente
127
- * @param {string} operacao
128
- */
129
- async #postMetodo(metodo, xml, codigoMunicipio, ambiente, operacao) {
130
- const { url } = this.endpoint
131
- ? { url: this.endpoint }
132
- : NFSeMunicipioResolver.resolver(codigoMunicipio, ambiente);
133
-
134
- const envelope = this.#buildEnvelope(metodo, xml);
135
-
136
- try {
137
- const response = await axios.post(url, envelope, {
138
- headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: metodo },
139
- timeout: this.timeout,
140
- responseType: 'text',
141
- });
142
- return this.#processarRetornoEvento(response.data, { operacao });
143
- } catch (error) {
144
- if (axios.isAxiosError(error)) {
145
- throw new GhinfeError(`Falha SOAP NFS-e (${operacao}): ${error.message}`, 'NFSE_HTTP_ERROR', {
146
- status: error.response?.status,
147
- });
148
- }
149
- throw error;
150
- }
151
- }
152
-
153
- /** @param {string} xmlRps */
154
- async #mockGerarNfse(xmlRps) {
155
- await new Promise((r) => setTimeout(r, 200));
156
-
157
- const numeroMatch = xmlRps.match(/<Numero>(\d+)<\/Numero>/);
158
- const numeroRps = numeroMatch?.[1] ?? '1';
159
-
160
- const scenario = this.mockScenario === 'rejeicao'
161
- ? NFSE_MOCK_RESPONSES.rejeicao
162
- : NFSE_MOCK_RESPONSES.autorizada;
163
-
164
- const innerXml = buildMockGerarNfseResponse(numeroRps, scenario);
165
- return this.#processarRetorno(innerXml, { mock: true });
166
- }
167
-
168
- /** @param {string} xml @param {Record<string, unknown>} [meta] */
169
- #processarRetorno(xml, meta = {}) {
170
- const codigoMatch = xml.match(/<Codigo>([^<]+)<\/Codigo>/);
171
- const mensagemMatch = xml.match(/<Mensagem>([^<]+)<\/Mensagem>/);
172
- const numeroNfseMatch = xml.match(/<InfNfse[\s\S]*?<Numero>(\d+)<\/Numero>/);
173
- const codVerifMatch = xml.match(/<CodigoVerificacao>([^<]+)<\/CodigoVerificacao>/);
174
-
175
- const temNfse = xml.includes('<ListaNfse>') || xml.includes('<InfNfse>');
176
-
177
- if (temNfse && !xml.includes('ListaMensagemRetorno')) {
178
- return {
179
- sucesso: true,
180
- autorizado: true,
181
- numeroNfse: numeroNfseMatch?.[1],
182
- codigoVerificacao: codVerifMatch?.[1],
183
- xmlRetorno: xml,
184
- ...meta,
185
- };
186
- }
187
-
188
- const codigo = codigoMatch?.[1] ?? 'E999';
189
- const mensagem = mensagemMatch?.[1] ?? 'Retorno não identificado';
190
- throw new NFSeSoapError(codigo, mensagem, { xmlRetorno: xml, ...meta });
191
- }
192
-
193
- /**
194
- * @param {string} xml
195
- * @param {Record<string, unknown>} [meta]
196
- */
197
- #processarRetornoEvento(xml, meta = {}) {
198
- if (xml.includes('ListaMensagemRetorno') && !xml.includes('RetCancelamento') && !xml.includes('RetSubstituicao')) {
199
- const codigo = xml.match(/<Codigo>([^<]+)<\/Codigo>/)?.[1] ?? 'E999';
200
- const mensagem = xml.match(/<Mensagem>([^<]+)<\/Mensagem>/)?.[1] ?? 'Retorno não identificado';
201
- throw new NFSeSoapError(codigo, mensagem, { xmlRetorno: xml, ...meta });
202
- }
203
-
204
- if (xml.includes('RetCancelamento') || xml.includes('Confirmacao')) {
205
- const numero = xml.match(/<Numero>(\d+)<\/Numero>/)?.[1];
206
- return {
207
- sucesso: true,
208
- cancelado: true,
209
- numeroNfse: numero,
210
- xmlRetorno: xml,
211
- ...meta,
212
- };
213
- }
214
-
215
- if (xml.includes('RetSubstituicao') || xml.includes('NfseSubstituidora')) {
216
- const nova = xml.match(/<NfseSubstituidora>[\s\S]*?<Numero>(\d+)<\/Numero>/)?.[1];
217
- const antiga = xml.match(/<NfseSubstituida>[\s\S]*?<Numero>(\d+)<\/Numero>/)?.[1];
218
- const codVerif = xml.match(/<CodigoVerificacao>([^<]+)<\/CodigoVerificacao>/)?.[1];
219
- return {
220
- sucesso: true,
221
- substituido: true,
222
- numeroNfse: nova,
223
- numeroNfseSubstituida: antiga,
224
- codigoVerificacao: codVerif,
225
- xmlRetorno: xml,
226
- ...meta,
227
- };
228
- }
229
-
230
- return this.#processarRetorno(xml, meta);
231
- }
232
- }
1
+ import axios from 'axios';
2
+ import { GhinfeError } from '../../errors/GhinfeError.js';
3
+ import { NFSeMunicipioResolver } from '../NFSeMunicipioResolver.js';
4
+ import {
5
+ buildMockGerarNfseResponse,
6
+ buildMockCancelarNfseResponse,
7
+ buildMockSubstituirNfseResponse,
8
+ NFSE_MOCK_RESPONSES,
9
+ } from '../mocks/nfse-responses.js';
10
+
11
+ export class NFSeSoapError extends GhinfeError {
12
+ /**
13
+ * @param {string} codigo
14
+ * @param {string} mensagem
15
+ * @param {Record<string, unknown>} [details]
16
+ */
17
+ constructor(codigo, mensagem, details = {}) {
18
+ super(`NFS-e [${codigo}]: ${mensagem}`, `NFSE_${codigo}`, { codigo, mensagem, ...details });
19
+ this.name = 'NFSeSoapError';
20
+ this.codigo = codigo;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Comunicação SOAP com prefeituras (NFS-e ABRASF).
26
+ */
27
+ export class NFSeSoapService {
28
+ /**
29
+ * @param {{ mock?: boolean, endpoint?: string, timeout?: number, mockScenario?: string }} [options]
30
+ */
31
+ constructor(options = {}) {
32
+ this.mock = options.mock ?? true;
33
+ this.endpoint = options.endpoint;
34
+ this.timeout = options.timeout ?? 30000;
35
+ this.mockScenario = options.mockScenario ?? 'autorizada';
36
+ }
37
+
38
+ /**
39
+ * @param {string} xmlRps
40
+ * @param {string} codigoMunicipio
41
+ * @param {number} [ambiente]
42
+ */
43
+ async gerarNfse(xmlRps, codigoMunicipio, ambiente = 2) {
44
+ if (this.mock) {
45
+ return this.#mockGerarNfse(xmlRps);
46
+ }
47
+
48
+ const { url } = this.endpoint
49
+ ? { url: this.endpoint }
50
+ : NFSeMunicipioResolver.resolver(codigoMunicipio, ambiente);
51
+
52
+ const envelope = this.#buildEnvelope('GerarNfse', xmlRps);
53
+
54
+ try {
55
+ const response = await axios.post(url, envelope, {
56
+ headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: 'GerarNfse' },
57
+ timeout: this.timeout,
58
+ responseType: 'text',
59
+ });
60
+
61
+ return this.#processarRetorno(response.data);
62
+ } catch (error) {
63
+ if (axios.isAxiosError(error)) {
64
+ throw new GhinfeError(`Falha SOAP NFS-e: ${error.message}`, 'NFSE_HTTP_ERROR', {
65
+ status: error.response?.status,
66
+ });
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+
72
+ /** @param {string} metodo @param {string} xml */
73
+ #buildEnvelope(metodo, xml) {
74
+ const escaped = xml.replace(/</g, '&lt;').replace(/>/g, '&gt;');
75
+ return `<?xml version="1.0" encoding="utf-8"?>
76
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
77
+ <soap:Body>
78
+ <${metodo} xmlns="http://www.abrasf.org.br/nfse.xsd">
79
+ <nfseDadosMsg>${escaped}</nfseDadosMsg>
80
+ </${metodo}>
81
+ </soap:Body>
82
+ </soap:Envelope>`;
83
+ }
84
+
85
+ /**
86
+ * @param {string} xmlCancelamento
87
+ * @param {string} codigoMunicipio
88
+ * @param {number} [ambiente]
89
+ */
90
+ async cancelarNfse(xmlCancelamento, codigoMunicipio, ambiente = 2) {
91
+ if (this.mock) {
92
+ await new Promise((r) => setTimeout(r, 150));
93
+ const numero = xmlCancelamento.match(/<Numero>(\d+)<\/Numero>/)?.[1] ?? '';
94
+ const resultado = this.mockScenario === 'rejeicao'
95
+ ? NFSE_MOCK_RESPONSES.rejeicao
96
+ : NFSE_MOCK_RESPONSES.cancelada;
97
+ const xml = buildMockCancelarNfseResponse(numero, resultado);
98
+ return this.#processarRetornoEvento(xml, { mock: true, operacao: 'cancelamento' });
99
+ }
100
+
101
+ return this.#postMetodo('CancelarNfse', xmlCancelamento, codigoMunicipio, ambiente, 'cancelamento');
102
+ }
103
+
104
+ /**
105
+ * @param {string} xmlSubstituicao
106
+ * @param {string} codigoMunicipio
107
+ * @param {number} [ambiente]
108
+ */
109
+ async substituirNfse(xmlSubstituicao, codigoMunicipio, ambiente = 2) {
110
+ if (this.mock) {
111
+ await new Promise((r) => setTimeout(r, 150));
112
+ const resultado = this.mockScenario === 'rejeicao'
113
+ ? NFSE_MOCK_RESPONSES.rejeicao
114
+ : NFSE_MOCK_RESPONSES.substituida;
115
+ const xml = buildMockSubstituirNfseResponse(resultado);
116
+ return this.#processarRetornoEvento(xml, { mock: true, operacao: 'substituicao' });
117
+ }
118
+
119
+ return this.#postMetodo('SubstituirNfse', xmlSubstituicao, codigoMunicipio, ambiente, 'substituicao');
120
+ }
121
+
122
+ /**
123
+ * @param {string} metodo
124
+ * @param {string} xml
125
+ * @param {string} codigoMunicipio
126
+ * @param {number} ambiente
127
+ * @param {string} operacao
128
+ */
129
+ async #postMetodo(metodo, xml, codigoMunicipio, ambiente, operacao) {
130
+ const { url } = this.endpoint
131
+ ? { url: this.endpoint }
132
+ : NFSeMunicipioResolver.resolver(codigoMunicipio, ambiente);
133
+
134
+ const envelope = this.#buildEnvelope(metodo, xml);
135
+
136
+ try {
137
+ const response = await axios.post(url, envelope, {
138
+ headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: metodo },
139
+ timeout: this.timeout,
140
+ responseType: 'text',
141
+ });
142
+ return this.#processarRetornoEvento(response.data, { operacao });
143
+ } catch (error) {
144
+ if (axios.isAxiosError(error)) {
145
+ throw new GhinfeError(`Falha SOAP NFS-e (${operacao}): ${error.message}`, 'NFSE_HTTP_ERROR', {
146
+ status: error.response?.status,
147
+ });
148
+ }
149
+ throw error;
150
+ }
151
+ }
152
+
153
+ /** @param {string} xmlRps */
154
+ async #mockGerarNfse(xmlRps) {
155
+ await new Promise((r) => setTimeout(r, 200));
156
+
157
+ const numeroMatch = xmlRps.match(/<Numero>(\d+)<\/Numero>/);
158
+ const numeroRps = numeroMatch?.[1] ?? '1';
159
+
160
+ const scenario = this.mockScenario === 'rejeicao'
161
+ ? NFSE_MOCK_RESPONSES.rejeicao
162
+ : NFSE_MOCK_RESPONSES.autorizada;
163
+
164
+ const innerXml = buildMockGerarNfseResponse(numeroRps, scenario);
165
+ return this.#processarRetorno(innerXml, { mock: true });
166
+ }
167
+
168
+ /** @param {string} xml @param {Record<string, unknown>} [meta] */
169
+ #processarRetorno(xml, meta = {}) {
170
+ const codigoMatch = xml.match(/<Codigo>([^<]+)<\/Codigo>/);
171
+ const mensagemMatch = xml.match(/<Mensagem>([^<]+)<\/Mensagem>/);
172
+ const numeroNfseMatch = xml.match(/<InfNfse[\s\S]*?<Numero>(\d+)<\/Numero>/);
173
+ const codVerifMatch = xml.match(/<CodigoVerificacao>([^<]+)<\/CodigoVerificacao>/);
174
+
175
+ const temNfse = xml.includes('<ListaNfse>') || xml.includes('<InfNfse>');
176
+
177
+ if (temNfse && !xml.includes('ListaMensagemRetorno')) {
178
+ return {
179
+ sucesso: true,
180
+ autorizado: true,
181
+ numeroNfse: numeroNfseMatch?.[1],
182
+ codigoVerificacao: codVerifMatch?.[1],
183
+ xmlRetorno: xml,
184
+ ...meta,
185
+ };
186
+ }
187
+
188
+ const codigo = codigoMatch?.[1] ?? 'E999';
189
+ const mensagem = mensagemMatch?.[1] ?? 'Retorno não identificado';
190
+ throw new NFSeSoapError(codigo, mensagem, { xmlRetorno: xml, ...meta });
191
+ }
192
+
193
+ /**
194
+ * @param {string} xml
195
+ * @param {Record<string, unknown>} [meta]
196
+ */
197
+ #processarRetornoEvento(xml, meta = {}) {
198
+ if (xml.includes('ListaMensagemRetorno') && !xml.includes('RetCancelamento') && !xml.includes('RetSubstituicao')) {
199
+ const codigo = xml.match(/<Codigo>([^<]+)<\/Codigo>/)?.[1] ?? 'E999';
200
+ const mensagem = xml.match(/<Mensagem>([^<]+)<\/Mensagem>/)?.[1] ?? 'Retorno não identificado';
201
+ throw new NFSeSoapError(codigo, mensagem, { xmlRetorno: xml, ...meta });
202
+ }
203
+
204
+ if (xml.includes('RetCancelamento') || xml.includes('Confirmacao')) {
205
+ const numero = xml.match(/<Numero>(\d+)<\/Numero>/)?.[1];
206
+ return {
207
+ sucesso: true,
208
+ cancelado: true,
209
+ numeroNfse: numero,
210
+ xmlRetorno: xml,
211
+ ...meta,
212
+ };
213
+ }
214
+
215
+ if (xml.includes('RetSubstituicao') || xml.includes('NfseSubstituidora')) {
216
+ const nova = xml.match(/<NfseSubstituidora>[\s\S]*?<Numero>(\d+)<\/Numero>/)?.[1];
217
+ const antiga = xml.match(/<NfseSubstituida>[\s\S]*?<Numero>(\d+)<\/Numero>/)?.[1];
218
+ const codVerif = xml.match(/<CodigoVerificacao>([^<]+)<\/CodigoVerificacao>/)?.[1];
219
+ return {
220
+ sucesso: true,
221
+ substituido: true,
222
+ numeroNfse: nova,
223
+ numeroNfseSubstituida: antiga,
224
+ codigoVerificacao: codVerif,
225
+ xmlRetorno: xml,
226
+ ...meta,
227
+ };
228
+ }
229
+
230
+ return this.#processarRetorno(xml, meta);
231
+ }
232
+ }
@@ -1,12 +1,12 @@
1
- import { NFSeXmlBuilder } from '../builders/NFSeXmlBuilder.js';
2
-
3
- export class NFSeXmlService {
4
- constructor() {
5
- this.builder = new NFSeXmlBuilder();
6
- }
7
-
8
- /** @param {import('../types/NFSeDocument.js').NFSeDocumento} documento @param {string} [layout] */
9
- gerarXml(documento, layout) {
10
- return this.builder.buildGerarNfse(documento, layout);
11
- }
12
- }
1
+ import { NFSeXmlBuilder } from '../builders/NFSeXmlBuilder.js';
2
+
3
+ export class NFSeXmlService {
4
+ constructor() {
5
+ this.builder = new NFSeXmlBuilder();
6
+ }
7
+
8
+ /** @param {import('../types/NFSeDocument.js').NFSeDocumento} documento @param {string} [layout] */
9
+ gerarXml(documento, layout) {
10
+ return this.builder.buildGerarNfse(documento, layout);
11
+ }
12
+ }
@@ -1,54 +1,54 @@
1
- /**
2
- * @typedef {Object} NFSeTomador
3
- * @property {string} [cnpj]
4
- * @property {string} [cpf]
5
- * @property {string} razaoSocial
6
- * @property {string} [email]
7
- * @property {string} [telefone]
8
- * @property {Object} [endereco]
9
- * @property {string} endereco.logradouro
10
- * @property {string} endereco.numero
11
- * @property {string} [endereco.complemento]
12
- * @property {string} endereco.bairro
13
- * @property {string} endereco.codigoMunicipio IBGE
14
- * @property {string} endereco.uf
15
- * @property {string} endereco.cep
16
- */
17
-
18
- /**
19
- * @typedef {Object} NFSeServico
20
- * @property {string} itemListaServico LC 116 (ex: "01.01")
21
- * @property {string} discriminacao
22
- * @property {string} codigoMunicipio IBGE prestação
23
- * @property {number} valorServicos
24
- * @property {number} [valorDeducoes]
25
- * @property {number} [valorPis]
26
- * @property {number} [valorCofins]
27
- * @property {number} [valorInss]
28
- * @property {number} [valorIr]
29
- * @property {number} [valorCsll]
30
- * @property {number} [aliquotaIss]
31
- * @property {number} [valorIss]
32
- * @property {number} [descontoIncondicionado]
33
- * @property {number} [descontoCondicionado]
34
- * @property {number} [issRetido] 1=Sim, 2=Não
35
- */
36
-
37
- /**
38
- * @typedef {Object} NFSeDocumento
39
- * @property {number} numero RPS
40
- * @property {string} [serie]
41
- * @property {number} [tipo] 1=RPS
42
- * @property {number} [ambiente] 1=Produção, 2=Homologação
43
- * @property {string} codigoMunicipio IBGE do prestador
44
- * @property {string} cnpjPrestador
45
- * @property {string} inscricaoMunicipal
46
- * @property {number} [naturezaOperacao] 1=Tributação no município
47
- * @property {number} [optanteSimplesNacional] 1=Sim, 2=Não
48
- * @property {number} [incentivadorCultural] 1=Sim, 2=Não
49
- * @property {NFSeServico} servico
50
- * @property {NFSeTomador} tomador
51
- * @property {string} [informacoesComplementares]
52
- */
53
-
54
- export {};
1
+ /**
2
+ * @typedef {Object} NFSeTomador
3
+ * @property {string} [cnpj]
4
+ * @property {string} [cpf]
5
+ * @property {string} razaoSocial
6
+ * @property {string} [email]
7
+ * @property {string} [telefone]
8
+ * @property {Object} [endereco]
9
+ * @property {string} endereco.logradouro
10
+ * @property {string} endereco.numero
11
+ * @property {string} [endereco.complemento]
12
+ * @property {string} endereco.bairro
13
+ * @property {string} endereco.codigoMunicipio IBGE
14
+ * @property {string} endereco.uf
15
+ * @property {string} endereco.cep
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} NFSeServico
20
+ * @property {string} itemListaServico LC 116 (ex: "01.01")
21
+ * @property {string} discriminacao
22
+ * @property {string} codigoMunicipio IBGE prestação
23
+ * @property {number} valorServicos
24
+ * @property {number} [valorDeducoes]
25
+ * @property {number} [valorPis]
26
+ * @property {number} [valorCofins]
27
+ * @property {number} [valorInss]
28
+ * @property {number} [valorIr]
29
+ * @property {number} [valorCsll]
30
+ * @property {number} [aliquotaIss]
31
+ * @property {number} [valorIss]
32
+ * @property {number} [descontoIncondicionado]
33
+ * @property {number} [descontoCondicionado]
34
+ * @property {number} [issRetido] 1=Sim, 2=Não
35
+ */
36
+
37
+ /**
38
+ * @typedef {Object} NFSeDocumento
39
+ * @property {number} numero RPS
40
+ * @property {string} [serie]
41
+ * @property {number} [tipo] 1=RPS
42
+ * @property {number} [ambiente] 1=Produção, 2=Homologação
43
+ * @property {string} codigoMunicipio IBGE do prestador
44
+ * @property {string} cnpjPrestador
45
+ * @property {string} inscricaoMunicipal
46
+ * @property {number} [naturezaOperacao] 1=Tributação no município
47
+ * @property {number} [optanteSimplesNacional] 1=Sim, 2=Não
48
+ * @property {number} [incentivadorCultural] 1=Sim, 2=Não
49
+ * @property {NFSeServico} servico
50
+ * @property {NFSeTomador} tomador
51
+ * @property {string} [informacoesComplementares]
52
+ */
53
+
54
+ export {};