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,142 +1,142 @@
1
- /**
2
- * Respostas mock NFS-e para desenvolvimento.
3
- */
4
- export const NFSE_MOCK_RESPONSES = {
5
- autorizada: {
6
- sucesso: true,
7
- codigo: 'E000',
8
- mensagem: 'NFS-e autorizada com sucesso',
9
- numeroNfse: '2026000001',
10
- codigoVerificacao: 'ABC1-DEF2',
11
- },
12
- rejeicao: {
13
- sucesso: false,
14
- codigo: 'E001',
15
- mensagem: 'Rejeição: RPS já convertido em NFS-e',
16
- },
17
- cancelada: {
18
- sucesso: true,
19
- codigo: 'E000',
20
- mensagem: 'NFS-e cancelada com sucesso',
21
- numeroNfse: '2026000001',
22
- },
23
- substituida: {
24
- sucesso: true,
25
- codigo: 'E000',
26
- mensagem: 'NFS-e substituída com sucesso',
27
- numeroNfse: '2026000002',
28
- codigoVerificacao: 'XYZ9-SUB1',
29
- numeroNfseSubstituida: '2026000001',
30
- },
31
- };
32
-
33
- /**
34
- * @param {string} numeroRps
35
- * @param {{ codigo: string, mensagem: string, numeroNfse?: string, codigoVerificacao?: string }} resultado
36
- */
37
- export function buildMockGerarNfseResponse(numeroRps, resultado) {
38
- const dh = new Date().toISOString();
39
-
40
- if (resultado.codigo === 'E000') {
41
- return `<?xml version="1.0" encoding="UTF-8"?>
42
- <GerarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
43
- <ListaNfse>
44
- <CompNfse>
45
- <Nfse versao="2.04">
46
- <InfNfse Id="NFS${resultado.numeroNfse}">
47
- <Numero>${resultado.numeroNfse}</Numero>
48
- <CodigoVerificacao>${resultado.codigoVerificacao}</CodigoVerificacao>
49
- <DataEmissao>${dh}</DataEmissao>
50
- <IdentificacaoRps>
51
- <Numero>${numeroRps}</Numero>
52
- <Serie>NF</Serie>
53
- <Tipo>1</Tipo>
54
- </IdentificacaoRps>
55
- </InfNfse>
56
- </Nfse>
57
- </CompNfse>
58
- </ListaNfse>
59
- </GerarNfseResposta>`;
60
- }
61
-
62
- return `<?xml version="1.0" encoding="UTF-8"?>
63
- <GerarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
64
- <ListaMensagemRetorno>
65
- <MensagemRetorno>
66
- <Codigo>${resultado.codigo}</Codigo>
67
- <Mensagem>${resultado.mensagem}</Mensagem>
68
- </MensagemRetorno>
69
- </ListaMensagemRetorno>
70
- </GerarNfseResposta>`;
71
- }
72
-
73
- /**
74
- * @param {string} numeroNfse
75
- * @param {{ codigo: string, mensagem: string }} resultado
76
- */
77
- export function buildMockCancelarNfseResponse(numeroNfse, resultado) {
78
- const dh = new Date().toISOString();
79
- if (resultado.codigo === 'E000') {
80
- return `<?xml version="1.0" encoding="UTF-8"?>
81
- <CancelarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
82
- <RetCancelamento>
83
- <NfseCancelamento>
84
- <Confirmacao>
85
- <Pedido>
86
- <InfPedidoCancelamento>
87
- <IdentificacaoNfse>
88
- <Numero>${numeroNfse}</Numero>
89
- </IdentificacaoNfse>
90
- </InfPedidoCancelamento>
91
- </Pedido>
92
- <DataHora>${dh}</DataHora>
93
- </Confirmacao>
94
- </NfseCancelamento>
95
- </RetCancelamento>
96
- </CancelarNfseResposta>`;
97
- }
98
- return `<?xml version="1.0" encoding="UTF-8"?>
99
- <CancelarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
100
- <ListaMensagemRetorno>
101
- <MensagemRetorno>
102
- <Codigo>${resultado.codigo}</Codigo>
103
- <Mensagem>${resultado.mensagem}</Mensagem>
104
- </MensagemRetorno>
105
- </ListaMensagemRetorno>
106
- </CancelarNfseResposta>`;
107
- }
108
-
109
- /**
110
- * @param {{ codigo: string, mensagem: string, numeroNfse?: string, codigoVerificacao?: string, numeroNfseSubstituida?: string }} resultado
111
- */
112
- export function buildMockSubstituirNfseResponse(resultado) {
113
- const dh = new Date().toISOString();
114
- if (resultado.codigo === 'E000') {
115
- return `<?xml version="1.0" encoding="UTF-8"?>
116
- <SubstituirNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
117
- <RetSubstituicao>
118
- <NfseSubstituida>
119
- <InfNfse>
120
- <Numero>${resultado.numeroNfseSubstituida ?? '2026000001'}</Numero>
121
- </InfNfse>
122
- </NfseSubstituida>
123
- <NfseSubstituidora>
124
- <InfNfse Id="NFS${resultado.numeroNfse}">
125
- <Numero>${resultado.numeroNfse}</Numero>
126
- <CodigoVerificacao>${resultado.codigoVerificacao}</CodigoVerificacao>
127
- <DataEmissao>${dh}</DataEmissao>
128
- </InfNfse>
129
- </NfseSubstituidora>
130
- </RetSubstituicao>
131
- </SubstituirNfseResposta>`;
132
- }
133
- return `<?xml version="1.0" encoding="UTF-8"?>
134
- <SubstituirNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
135
- <ListaMensagemRetorno>
136
- <MensagemRetorno>
137
- <Codigo>${resultado.codigo}</Codigo>
138
- <Mensagem>${resultado.mensagem}</Mensagem>
139
- </MensagemRetorno>
140
- </ListaMensagemRetorno>
141
- </SubstituirNfseResposta>`;
142
- }
1
+ /**
2
+ * Respostas mock NFS-e para desenvolvimento.
3
+ */
4
+ export const NFSE_MOCK_RESPONSES = {
5
+ autorizada: {
6
+ sucesso: true,
7
+ codigo: 'E000',
8
+ mensagem: 'NFS-e autorizada com sucesso',
9
+ numeroNfse: '2026000001',
10
+ codigoVerificacao: 'ABC1-DEF2',
11
+ },
12
+ rejeicao: {
13
+ sucesso: false,
14
+ codigo: 'E001',
15
+ mensagem: 'Rejeição: RPS já convertido em NFS-e',
16
+ },
17
+ cancelada: {
18
+ sucesso: true,
19
+ codigo: 'E000',
20
+ mensagem: 'NFS-e cancelada com sucesso',
21
+ numeroNfse: '2026000001',
22
+ },
23
+ substituida: {
24
+ sucesso: true,
25
+ codigo: 'E000',
26
+ mensagem: 'NFS-e substituída com sucesso',
27
+ numeroNfse: '2026000002',
28
+ codigoVerificacao: 'XYZ9-SUB1',
29
+ numeroNfseSubstituida: '2026000001',
30
+ },
31
+ };
32
+
33
+ /**
34
+ * @param {string} numeroRps
35
+ * @param {{ codigo: string, mensagem: string, numeroNfse?: string, codigoVerificacao?: string }} resultado
36
+ */
37
+ export function buildMockGerarNfseResponse(numeroRps, resultado) {
38
+ const dh = new Date().toISOString();
39
+
40
+ if (resultado.codigo === 'E000') {
41
+ return `<?xml version="1.0" encoding="UTF-8"?>
42
+ <GerarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
43
+ <ListaNfse>
44
+ <CompNfse>
45
+ <Nfse versao="2.04">
46
+ <InfNfse Id="NFS${resultado.numeroNfse}">
47
+ <Numero>${resultado.numeroNfse}</Numero>
48
+ <CodigoVerificacao>${resultado.codigoVerificacao}</CodigoVerificacao>
49
+ <DataEmissao>${dh}</DataEmissao>
50
+ <IdentificacaoRps>
51
+ <Numero>${numeroRps}</Numero>
52
+ <Serie>NF</Serie>
53
+ <Tipo>1</Tipo>
54
+ </IdentificacaoRps>
55
+ </InfNfse>
56
+ </Nfse>
57
+ </CompNfse>
58
+ </ListaNfse>
59
+ </GerarNfseResposta>`;
60
+ }
61
+
62
+ return `<?xml version="1.0" encoding="UTF-8"?>
63
+ <GerarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
64
+ <ListaMensagemRetorno>
65
+ <MensagemRetorno>
66
+ <Codigo>${resultado.codigo}</Codigo>
67
+ <Mensagem>${resultado.mensagem}</Mensagem>
68
+ </MensagemRetorno>
69
+ </ListaMensagemRetorno>
70
+ </GerarNfseResposta>`;
71
+ }
72
+
73
+ /**
74
+ * @param {string} numeroNfse
75
+ * @param {{ codigo: string, mensagem: string }} resultado
76
+ */
77
+ export function buildMockCancelarNfseResponse(numeroNfse, resultado) {
78
+ const dh = new Date().toISOString();
79
+ if (resultado.codigo === 'E000') {
80
+ return `<?xml version="1.0" encoding="UTF-8"?>
81
+ <CancelarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
82
+ <RetCancelamento>
83
+ <NfseCancelamento>
84
+ <Confirmacao>
85
+ <Pedido>
86
+ <InfPedidoCancelamento>
87
+ <IdentificacaoNfse>
88
+ <Numero>${numeroNfse}</Numero>
89
+ </IdentificacaoNfse>
90
+ </InfPedidoCancelamento>
91
+ </Pedido>
92
+ <DataHora>${dh}</DataHora>
93
+ </Confirmacao>
94
+ </NfseCancelamento>
95
+ </RetCancelamento>
96
+ </CancelarNfseResposta>`;
97
+ }
98
+ return `<?xml version="1.0" encoding="UTF-8"?>
99
+ <CancelarNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
100
+ <ListaMensagemRetorno>
101
+ <MensagemRetorno>
102
+ <Codigo>${resultado.codigo}</Codigo>
103
+ <Mensagem>${resultado.mensagem}</Mensagem>
104
+ </MensagemRetorno>
105
+ </ListaMensagemRetorno>
106
+ </CancelarNfseResposta>`;
107
+ }
108
+
109
+ /**
110
+ * @param {{ codigo: string, mensagem: string, numeroNfse?: string, codigoVerificacao?: string, numeroNfseSubstituida?: string }} resultado
111
+ */
112
+ export function buildMockSubstituirNfseResponse(resultado) {
113
+ const dh = new Date().toISOString();
114
+ if (resultado.codigo === 'E000') {
115
+ return `<?xml version="1.0" encoding="UTF-8"?>
116
+ <SubstituirNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
117
+ <RetSubstituicao>
118
+ <NfseSubstituida>
119
+ <InfNfse>
120
+ <Numero>${resultado.numeroNfseSubstituida ?? '2026000001'}</Numero>
121
+ </InfNfse>
122
+ </NfseSubstituida>
123
+ <NfseSubstituidora>
124
+ <InfNfse Id="NFS${resultado.numeroNfse}">
125
+ <Numero>${resultado.numeroNfse}</Numero>
126
+ <CodigoVerificacao>${resultado.codigoVerificacao}</CodigoVerificacao>
127
+ <DataEmissao>${dh}</DataEmissao>
128
+ </InfNfse>
129
+ </NfseSubstituidora>
130
+ </RetSubstituicao>
131
+ </SubstituirNfseResposta>`;
132
+ }
133
+ return `<?xml version="1.0" encoding="UTF-8"?>
134
+ <SubstituirNfseResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
135
+ <ListaMensagemRetorno>
136
+ <MensagemRetorno>
137
+ <Codigo>${resultado.codigo}</Codigo>
138
+ <Mensagem>${resultado.mensagem}</Mensagem>
139
+ </MensagemRetorno>
140
+ </ListaMensagemRetorno>
141
+ </SubstituirNfseResposta>`;
142
+ }
@@ -1,191 +1,191 @@
1
- import { NFSeXmlBuilder } from '../builders/NFSeXmlBuilder.js';
2
- import { NFSeEventoXmlBuilder } from '../builders/NFSeEventoXmlBuilder.js';
3
- import { NFSeSoapService } from './NFSeSoapService.js';
4
- import { NFeSignService } from '../../nfe/services/NFeSignService.js';
5
- import { NFSeMunicipioResolver } from '../NFSeMunicipioResolver.js';
6
- import { NFSE_LAYOUTS } from '../constants/municipios.js';
7
- import { GhinfeError } from '../../errors/GhinfeError.js';
8
-
9
- /**
10
- * Orquestrador NFS-e — emissão, cancelamento e substituição.
11
- */
12
- export class NFSeService {
13
- /**
14
- * @param {{
15
- * mock?: boolean,
16
- * endpoint?: string,
17
- * mockScenario?: string,
18
- * layout?: string,
19
- * }} [options]
20
- */
21
- constructor(options = {}) {
22
- this.options = options;
23
- this.builder = new NFSeXmlBuilder();
24
- this.eventoBuilder = new NFSeEventoXmlBuilder();
25
- this.signService = new NFeSignService();
26
- this.soapService = new NFSeSoapService(options);
27
- }
28
-
29
- /** @param {import('../types/NFSeDocument.js').NFSeDocumento} documento */
30
- resolverLayout(documento) {
31
- if (this.options.layout) return this.options.layout;
32
- try {
33
- const info = NFSeMunicipioResolver.resolver(
34
- documento.codigoMunicipio,
35
- documento.ambiente ?? 2
36
- );
37
- return info.layout ?? NFSE_LAYOUTS.ABRASF;
38
- } catch {
39
- return NFSE_LAYOUTS.ABRASF;
40
- }
41
- }
42
-
43
- /**
44
- * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
45
- * @param {string} [layout]
46
- */
47
- gerarXml(documento, layout) {
48
- return this.builder.buildGerarNfse(documento, layout ?? this.resolverLayout(documento));
49
- }
50
-
51
- /**
52
- * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
53
- * @param {{ pfx: Buffer|string, senha: string }} certificado
54
- * @param {string} [layout]
55
- */
56
- gerarXmlAssinado(documento, certificado, layout) {
57
- const xml = this.gerarXml(documento, layout);
58
- return this.signService.assinarRps(xml, certificado.pfx, certificado.senha);
59
- }
60
-
61
- /**
62
- * @param {{
63
- * numeroNfse: string,
64
- * cnpjPrestador: string,
65
- * inscricaoMunicipal: string,
66
- * codigoMunicipio: string,
67
- * codigoCancelamento?: string,
68
- * }} dados
69
- */
70
- gerarXmlCancelamento(dados) {
71
- return this.eventoBuilder.buildCancelamento(dados);
72
- }
73
-
74
- /**
75
- * @param {{
76
- * numeroNfseSubstituida: string,
77
- * cnpjPrestador: string,
78
- * inscricaoMunicipal: string,
79
- * codigoMunicipio: string,
80
- * codigoCancelamento?: string,
81
- * documentoSubstituto: import('../types/NFSeDocument.js').NFSeDocumento,
82
- * }} dados
83
- */
84
- gerarXmlSubstituicao(dados) {
85
- const xmlRps = this.gerarXml(dados.documentoSubstituto);
86
- return this.eventoBuilder.buildSubstituicao({
87
- ...dados,
88
- xmlRpsSubstituto: xmlRps,
89
- });
90
- }
91
-
92
- /**
93
- * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
94
- * @param {{ pfx?: Buffer|string, senha?: string }} [certificado]
95
- */
96
- async emitir(documento, certificado) {
97
- const layout = this.resolverLayout(documento);
98
- let xml = this.gerarXml(documento, layout);
99
- let xmlAssinado = null;
100
-
101
- if (certificado?.pfx && certificado?.senha) {
102
- xmlAssinado = this.signService.assinarRps(xml, certificado.pfx, certificado.senha);
103
- xml = xmlAssinado;
104
- }
105
-
106
- const retorno = await this.soapService.gerarNfse(
107
- xml,
108
- documento.codigoMunicipio,
109
- documento.ambiente ?? 2
110
- );
111
-
112
- return {
113
- layout,
114
- xmlGerado: xmlAssinado ? this.gerarXml(documento, layout) : xml,
115
- xmlAssinado,
116
- retorno,
117
- };
118
- }
119
-
120
- /**
121
- * Cancela NFS-e já autorizada.
122
- * @param {{
123
- * numeroNfse: string,
124
- * cnpjPrestador: string,
125
- * inscricaoMunicipal: string,
126
- * codigoMunicipio: string,
127
- * codigoCancelamento?: string,
128
- * ambiente?: number,
129
- * }} dados
130
- */
131
- async cancelar(dados) {
132
- const xml = this.gerarXmlCancelamento(dados);
133
- const retorno = await this.soapService.cancelarNfse(
134
- xml,
135
- dados.codigoMunicipio,
136
- dados.ambiente ?? 2
137
- );
138
- return { tipo: 'cancelamento', xmlGerado: xml, retorno };
139
- }
140
-
141
- /**
142
- * Substitui NFS-e por um novo RPS.
143
- * @param {{
144
- * numeroNfseSubstituida: string,
145
- * cnpjPrestador: string,
146
- * inscricaoMunicipal: string,
147
- * codigoMunicipio: string,
148
- * codigoCancelamento?: string,
149
- * documentoSubstituto: import('../types/NFSeDocument.js').NFSeDocumento,
150
- * ambiente?: number,
151
- * }} dados
152
- * @param {{ pfx?: Buffer|string, senha?: string }} [certificado]
153
- */
154
- async substituir(dados, certificado) {
155
- let xmlEnvio = this.gerarXmlSubstituicao(dados);
156
-
157
- if (certificado?.pfx && certificado?.senha) {
158
- const xmlRps = this.gerarXmlAssinado(dados.documentoSubstituto, certificado);
159
- xmlEnvio = this.eventoBuilder.buildSubstituicao({
160
- ...dados,
161
- xmlRpsSubstituto: xmlRps,
162
- });
163
- }
164
-
165
- const retorno = await this.soapService.substituirNfse(
166
- xmlEnvio,
167
- dados.codigoMunicipio,
168
- dados.ambiente ?? 2
169
- );
170
-
171
- return { tipo: 'substituicao', xmlGerado: xmlEnvio, retorno };
172
- }
173
-
174
- /**
175
- * @param {Awaited<ReturnType<NFSeService['emitir']>>} resultado
176
- */
177
- toPersistencePayload(resultado) {
178
- if (!resultado.retorno.autorizado) {
179
- throw new GhinfeError('NFS-e não autorizada', 'NFSE_NOT_AUTHORIZED', resultado.retorno);
180
- }
181
-
182
- return {
183
- numero_nfse: resultado.retorno.numeroNfse,
184
- codigo_verificacao: resultado.retorno.codigoVerificacao,
185
- layout: resultado.layout,
186
- xml_rps: resultado.xmlAssinado ?? resultado.xmlGerado,
187
- xml_retorno: resultado.retorno.xmlRetorno,
188
- autorizado_em: new Date(),
189
- };
190
- }
191
- }
1
+ import { NFSeXmlBuilder } from '../builders/NFSeXmlBuilder.js';
2
+ import { NFSeEventoXmlBuilder } from '../builders/NFSeEventoXmlBuilder.js';
3
+ import { NFSeSoapService } from './NFSeSoapService.js';
4
+ import { NFeSignService } from '../../nfe/services/NFeSignService.js';
5
+ import { NFSeMunicipioResolver } from '../NFSeMunicipioResolver.js';
6
+ import { NFSE_LAYOUTS } from '../constants/municipios.js';
7
+ import { GhinfeError } from '../../errors/GhinfeError.js';
8
+
9
+ /**
10
+ * Orquestrador NFS-e — emissão, cancelamento e substituição.
11
+ */
12
+ export class NFSeService {
13
+ /**
14
+ * @param {{
15
+ * mock?: boolean,
16
+ * endpoint?: string,
17
+ * mockScenario?: string,
18
+ * layout?: string,
19
+ * }} [options]
20
+ */
21
+ constructor(options = {}) {
22
+ this.options = options;
23
+ this.builder = new NFSeXmlBuilder();
24
+ this.eventoBuilder = new NFSeEventoXmlBuilder();
25
+ this.signService = new NFeSignService();
26
+ this.soapService = new NFSeSoapService(options);
27
+ }
28
+
29
+ /** @param {import('../types/NFSeDocument.js').NFSeDocumento} documento */
30
+ resolverLayout(documento) {
31
+ if (this.options.layout) return this.options.layout;
32
+ try {
33
+ const info = NFSeMunicipioResolver.resolver(
34
+ documento.codigoMunicipio,
35
+ documento.ambiente ?? 2
36
+ );
37
+ return info.layout ?? NFSE_LAYOUTS.ABRASF;
38
+ } catch {
39
+ return NFSE_LAYOUTS.ABRASF;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
45
+ * @param {string} [layout]
46
+ */
47
+ gerarXml(documento, layout) {
48
+ return this.builder.buildGerarNfse(documento, layout ?? this.resolverLayout(documento));
49
+ }
50
+
51
+ /**
52
+ * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
53
+ * @param {{ pfx: Buffer|string, senha: string }} certificado
54
+ * @param {string} [layout]
55
+ */
56
+ gerarXmlAssinado(documento, certificado, layout) {
57
+ const xml = this.gerarXml(documento, layout);
58
+ return this.signService.assinarRps(xml, certificado.pfx, certificado.senha);
59
+ }
60
+
61
+ /**
62
+ * @param {{
63
+ * numeroNfse: string,
64
+ * cnpjPrestador: string,
65
+ * inscricaoMunicipal: string,
66
+ * codigoMunicipio: string,
67
+ * codigoCancelamento?: string,
68
+ * }} dados
69
+ */
70
+ gerarXmlCancelamento(dados) {
71
+ return this.eventoBuilder.buildCancelamento(dados);
72
+ }
73
+
74
+ /**
75
+ * @param {{
76
+ * numeroNfseSubstituida: string,
77
+ * cnpjPrestador: string,
78
+ * inscricaoMunicipal: string,
79
+ * codigoMunicipio: string,
80
+ * codigoCancelamento?: string,
81
+ * documentoSubstituto: import('../types/NFSeDocument.js').NFSeDocumento,
82
+ * }} dados
83
+ */
84
+ gerarXmlSubstituicao(dados) {
85
+ const xmlRps = this.gerarXml(dados.documentoSubstituto);
86
+ return this.eventoBuilder.buildSubstituicao({
87
+ ...dados,
88
+ xmlRpsSubstituto: xmlRps,
89
+ });
90
+ }
91
+
92
+ /**
93
+ * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
94
+ * @param {{ pfx?: Buffer|string, senha?: string }} [certificado]
95
+ */
96
+ async emitir(documento, certificado) {
97
+ const layout = this.resolverLayout(documento);
98
+ let xml = this.gerarXml(documento, layout);
99
+ let xmlAssinado = null;
100
+
101
+ if (certificado?.pfx && certificado?.senha) {
102
+ xmlAssinado = this.signService.assinarRps(xml, certificado.pfx, certificado.senha);
103
+ xml = xmlAssinado;
104
+ }
105
+
106
+ const retorno = await this.soapService.gerarNfse(
107
+ xml,
108
+ documento.codigoMunicipio,
109
+ documento.ambiente ?? 2
110
+ );
111
+
112
+ return {
113
+ layout,
114
+ xmlGerado: xmlAssinado ? this.gerarXml(documento, layout) : xml,
115
+ xmlAssinado,
116
+ retorno,
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Cancela NFS-e já autorizada.
122
+ * @param {{
123
+ * numeroNfse: string,
124
+ * cnpjPrestador: string,
125
+ * inscricaoMunicipal: string,
126
+ * codigoMunicipio: string,
127
+ * codigoCancelamento?: string,
128
+ * ambiente?: number,
129
+ * }} dados
130
+ */
131
+ async cancelar(dados) {
132
+ const xml = this.gerarXmlCancelamento(dados);
133
+ const retorno = await this.soapService.cancelarNfse(
134
+ xml,
135
+ dados.codigoMunicipio,
136
+ dados.ambiente ?? 2
137
+ );
138
+ return { tipo: 'cancelamento', xmlGerado: xml, retorno };
139
+ }
140
+
141
+ /**
142
+ * Substitui NFS-e por um novo RPS.
143
+ * @param {{
144
+ * numeroNfseSubstituida: string,
145
+ * cnpjPrestador: string,
146
+ * inscricaoMunicipal: string,
147
+ * codigoMunicipio: string,
148
+ * codigoCancelamento?: string,
149
+ * documentoSubstituto: import('../types/NFSeDocument.js').NFSeDocumento,
150
+ * ambiente?: number,
151
+ * }} dados
152
+ * @param {{ pfx?: Buffer|string, senha?: string }} [certificado]
153
+ */
154
+ async substituir(dados, certificado) {
155
+ let xmlEnvio = this.gerarXmlSubstituicao(dados);
156
+
157
+ if (certificado?.pfx && certificado?.senha) {
158
+ const xmlRps = this.gerarXmlAssinado(dados.documentoSubstituto, certificado);
159
+ xmlEnvio = this.eventoBuilder.buildSubstituicao({
160
+ ...dados,
161
+ xmlRpsSubstituto: xmlRps,
162
+ });
163
+ }
164
+
165
+ const retorno = await this.soapService.substituirNfse(
166
+ xmlEnvio,
167
+ dados.codigoMunicipio,
168
+ dados.ambiente ?? 2
169
+ );
170
+
171
+ return { tipo: 'substituicao', xmlGerado: xmlEnvio, retorno };
172
+ }
173
+
174
+ /**
175
+ * @param {Awaited<ReturnType<NFSeService['emitir']>>} resultado
176
+ */
177
+ toPersistencePayload(resultado) {
178
+ if (!resultado.retorno.autorizado) {
179
+ throw new GhinfeError('NFS-e não autorizada', 'NFSE_NOT_AUTHORIZED', resultado.retorno);
180
+ }
181
+
182
+ return {
183
+ numero_nfse: resultado.retorno.numeroNfse,
184
+ codigo_verificacao: resultado.retorno.codigoVerificacao,
185
+ layout: resultado.layout,
186
+ xml_rps: resultado.xmlAssinado ?? resultado.xmlGerado,
187
+ xml_retorno: resultado.retorno.xmlRetorno,
188
+ autorizado_em: new Date(),
189
+ };
190
+ }
191
+ }