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,202 +1,202 @@
1
- import { create } from 'xmlbuilder2';
2
- import {
3
- NFSE_NAMESPACE,
4
- GINFES_NAMESPACE,
5
- BETHA_NAMESPACE,
6
- ISSNET_NAMESPACE,
7
- NFSE_LAYOUTS,
8
- } from '../constants/municipios.js';
9
- import { formatSefazDateTime } from '../../utils/date.utils.js';
10
- import { GhinfeError } from '../../errors/GhinfeError.js';
11
-
12
- /**
13
- * Monta o bloco InfRps / InfDeclaracaoPrestacaoServico comum aos layouts.
14
- * @param {import('xmlbuilder2').XMLBuilder} parent
15
- * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
16
- * @param {string} idAttr
17
- */
18
- function appendInfRps(parent, documento, idAttr = 'InfRps') {
19
- const dataEmissao = formatSefazDateTime();
20
- const idRps = `RPS${documento.numero}`;
21
- const valorServicos = documento.servico.valorServicos;
22
- const valorIss = documento.servico.valorIss ?? 0;
23
- const baseCalculo = valorServicos - (documento.servico.valorDeducoes ?? 0);
24
- const valorLiquido =
25
- valorServicos -
26
- (documento.servico.descontoIncondicionado ?? 0) -
27
- (documento.servico.descontoCondicionado ?? 0);
28
-
29
- const inf = parent.ele(idAttr, { Id: idRps });
30
-
31
- const idRpsNode = inf.ele('IdentificacaoRps');
32
- idRpsNode.ele('Numero').txt(String(documento.numero)).up();
33
- idRpsNode.ele('Serie').txt(documento.serie ?? 'NF').up();
34
- idRpsNode.ele('Tipo').txt(String(documento.tipo ?? 1)).up();
35
- idRpsNode.up();
36
-
37
- inf
38
- .ele('DataEmissao').txt(dataEmissao).up()
39
- .ele('NaturezaOperacao').txt(String(documento.naturezaOperacao ?? 1)).up()
40
- .ele('OptanteSimplesNacional').txt(String(documento.optanteSimplesNacional ?? 1)).up()
41
- .ele('IncentivadorCultural').txt(String(documento.incentivadorCultural ?? 2)).up()
42
- .ele('Status').txt('1').up();
43
-
44
- const servico = inf.ele('Servico');
45
- const valores = servico.ele('Valores');
46
- valores
47
- .ele('ValorServicos').txt(dec(valorServicos)).up()
48
- .ele('ValorDeducoes').txt(dec(documento.servico.valorDeducoes ?? 0)).up()
49
- .ele('ValorPis').txt(dec(documento.servico.valorPis ?? 0)).up()
50
- .ele('ValorCofins').txt(dec(documento.servico.valorCofins ?? 0)).up()
51
- .ele('ValorInss').txt(dec(documento.servico.valorInss ?? 0)).up()
52
- .ele('ValorIr').txt(dec(documento.servico.valorIr ?? 0)).up()
53
- .ele('ValorCsll').txt(dec(documento.servico.valorCsll ?? 0)).up()
54
- .ele('IssRetido').txt(String(documento.servico.issRetido ?? 2)).up()
55
- .ele('ValorIss').txt(dec(valorIss)).up()
56
- .ele('BaseCalculo').txt(dec(baseCalculo)).up()
57
- .ele('Aliquota').txt(dec(documento.servico.aliquotaIss ?? 0, 4)).up()
58
- .ele('ValorLiquidoNfse').txt(dec(valorLiquido)).up()
59
- .ele('DescontoIncondicionado').txt(dec(documento.servico.descontoIncondicionado ?? 0)).up()
60
- .ele('DescontoCondicionado').txt(dec(documento.servico.descontoCondicionado ?? 0)).up();
61
- valores.up();
62
-
63
- servico
64
- .ele('ItemListaServico').txt(documento.servico.itemListaServico).up()
65
- .ele('Discriminacao').txt(documento.servico.discriminacao).up()
66
- .ele('CodigoMunicipio').txt(documento.servico.codigoMunicipio).up();
67
- servico.up();
68
-
69
- const prestador = inf.ele('Prestador');
70
- prestador
71
- .ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up()
72
- .ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
73
- prestador.up();
74
-
75
- const tomador = inf.ele('Tomador');
76
- const identTomador = tomador.ele('IdentificacaoTomador').ele('CpfCnpj');
77
- const docTomador = (documento.tomador.cnpj ?? documento.tomador.cpf ?? '').replace(/\D/g, '');
78
- if (docTomador.length === 14) identTomador.ele('Cnpj').txt(docTomador).up();
79
- else if (docTomador.length === 11) identTomador.ele('Cpf').txt(docTomador).up();
80
- identTomador.up().up();
81
- tomador.ele('RazaoSocial').txt(documento.tomador.razaoSocial).up();
82
-
83
- if (documento.tomador.endereco) {
84
- const end = tomador.ele('Endereco');
85
- const e = documento.tomador.endereco;
86
- end.ele('Endereco').txt(e.logradouro).up();
87
- end.ele('Numero').txt(e.numero).up();
88
- if (e.complemento) end.ele('Complemento').txt(e.complemento).up();
89
- end.ele('Bairro').txt(e.bairro).up();
90
- end.ele('CodigoMunicipio').txt(e.codigoMunicipio).up();
91
- end.ele('Uf').txt(e.uf).up();
92
- end.ele('Cep').txt(e.cep.replace(/\D/g, '')).up();
93
- end.up();
94
- }
95
-
96
- if (documento.tomador.email) {
97
- tomador.ele('Contato').ele('Email').txt(documento.tomador.email).up().up();
98
- }
99
- tomador.up();
100
-
101
- if (documento.informacoesComplementares) {
102
- inf.ele('Observacao').txt(documento.informacoesComplementares).up();
103
- }
104
-
105
- return inf;
106
- }
107
-
108
- /** @param {number} v @param {number} [d] */
109
- function dec(v, d = 2) {
110
- return Number(v).toFixed(d);
111
- }
112
-
113
- /**
114
- * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
115
- */
116
- function validarDocumento(documento) {
117
- if (!documento.numero) throw new GhinfeError('numero do RPS é obrigatório', 'NFSE_NUMERO_REQUIRED');
118
- if (!documento.cnpjPrestador) throw new GhinfeError('cnpjPrestador é obrigatório', 'NFSE_CNPJ_REQUIRED');
119
- if (!documento.inscricaoMunicipal) throw new GhinfeError('inscricaoMunicipal é obrigatória', 'NFSE_IM_REQUIRED');
120
- if (!documento.servico) throw new GhinfeError('servico é obrigatório', 'NFSE_SERVICO_REQUIRED');
121
- if (!documento.tomador) throw new GhinfeError('tomador é obrigatório', 'NFSE_TOMADOR_REQUIRED');
122
- }
123
-
124
- /**
125
- * Adapters de layout municipal.
126
- * Mantêm o mesmo objeto de domínio e trocam o wrapper/namespace XML.
127
- */
128
- export const NFSeLayoutAdapters = {
129
- [NFSE_LAYOUTS.ABRASF]: {
130
- nome: 'ABRASF 2.04',
131
- build(documento) {
132
- validarDocumento(documento);
133
- const doc = create({ version: '1.0', encoding: 'UTF-8' })
134
- .ele('GerarNfseEnvio', { xmlns: NFSE_NAMESPACE });
135
- const rps = doc.ele('Rps');
136
- appendInfRps(rps, documento, 'InfRps');
137
- return doc.end({ prettyPrint: false, headless: false });
138
- },
139
- },
140
-
141
- [NFSE_LAYOUTS.GINFES]: {
142
- nome: 'GINFES',
143
- build(documento) {
144
- validarDocumento(documento);
145
- const doc = create({ version: '1.0', encoding: 'UTF-8' })
146
- .ele('EnviarLoteRpsEnvio', { xmlns: GINFES_NAMESPACE });
147
- const lote = doc.ele('LoteRps', { Id: `Lote${documento.numero}`, versao: '3.00' });
148
- lote.ele('NumeroLote').txt(String(documento.numero)).up();
149
- lote.ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up();
150
- lote.ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
151
- lote.ele('QuantidadeRps').txt('1').up();
152
- const lista = lote.ele('ListaRps').ele('Rps');
153
- appendInfRps(lista, documento, 'InfRps');
154
- return doc.end({ prettyPrint: false, headless: false });
155
- },
156
- },
157
-
158
- [NFSE_LAYOUTS.BETHA]: {
159
- nome: 'Betha',
160
- build(documento) {
161
- validarDocumento(documento);
162
- const doc = create({ version: '1.0', encoding: 'UTF-8' })
163
- .ele('GerarNfseEnvio', { xmlns: BETHA_NAMESPACE });
164
- const rps = doc.ele('Rps');
165
- appendInfRps(rps, documento, 'InfDeclaracaoPrestacaoServico');
166
- return doc.end({ prettyPrint: false, headless: false });
167
- },
168
- },
169
-
170
- [NFSE_LAYOUTS.ISSNET]: {
171
- nome: 'ISSNet',
172
- build(documento) {
173
- validarDocumento(documento);
174
- const doc = create({ version: '1.0', encoding: 'UTF-8' })
175
- .ele('EnviarLoteRpsEnvio', { xmlns: ISSNET_NAMESPACE });
176
- const lote = doc.ele('LoteRps', { Id: `Lote${documento.numero}`, versao: '2.04' });
177
- lote.ele('NumeroLote').txt(String(documento.numero)).up();
178
- lote.ele('CpfCnpj').ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up().up();
179
- lote.ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
180
- lote.ele('QuantidadeRps').txt('1').up();
181
- const lista = lote.ele('ListaRps').ele('Rps');
182
- appendInfRps(lista, documento, 'InfDeclaracaoPrestacaoServico');
183
- return doc.end({ prettyPrint: false, headless: false });
184
- },
185
- },
186
- };
187
-
188
- /**
189
- * @param {string} layout
190
- * @returns {typeof NFSeLayoutAdapters[string]}
191
- */
192
- export function obterAdapter(layout) {
193
- const key = (layout ?? NFSE_LAYOUTS.ABRASF).toLowerCase();
194
- const adapter = NFSeLayoutAdapters[key];
195
- if (!adapter) {
196
- throw new GhinfeError(
197
- `Layout NFS-e não suportado: ${layout}. Use: ${Object.keys(NFSE_LAYOUTS).join(', ')}`,
198
- 'NFSE_LAYOUT_UNSUPPORTED'
199
- );
200
- }
201
- return adapter;
202
- }
1
+ import { create } from 'xmlbuilder2';
2
+ import {
3
+ NFSE_NAMESPACE,
4
+ GINFES_NAMESPACE,
5
+ BETHA_NAMESPACE,
6
+ ISSNET_NAMESPACE,
7
+ NFSE_LAYOUTS,
8
+ } from '../constants/municipios.js';
9
+ import { formatSefazDateTime } from '../../utils/date.utils.js';
10
+ import { GhinfeError } from '../../errors/GhinfeError.js';
11
+
12
+ /**
13
+ * Monta o bloco InfRps / InfDeclaracaoPrestacaoServico comum aos layouts.
14
+ * @param {import('xmlbuilder2').XMLBuilder} parent
15
+ * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
16
+ * @param {string} idAttr
17
+ */
18
+ function appendInfRps(parent, documento, idAttr = 'InfRps') {
19
+ const dataEmissao = formatSefazDateTime();
20
+ const idRps = `RPS${documento.numero}`;
21
+ const valorServicos = documento.servico.valorServicos;
22
+ const valorIss = documento.servico.valorIss ?? 0;
23
+ const baseCalculo = valorServicos - (documento.servico.valorDeducoes ?? 0);
24
+ const valorLiquido =
25
+ valorServicos -
26
+ (documento.servico.descontoIncondicionado ?? 0) -
27
+ (documento.servico.descontoCondicionado ?? 0);
28
+
29
+ const inf = parent.ele(idAttr, { Id: idRps });
30
+
31
+ const idRpsNode = inf.ele('IdentificacaoRps');
32
+ idRpsNode.ele('Numero').txt(String(documento.numero)).up();
33
+ idRpsNode.ele('Serie').txt(documento.serie ?? 'NF').up();
34
+ idRpsNode.ele('Tipo').txt(String(documento.tipo ?? 1)).up();
35
+ idRpsNode.up();
36
+
37
+ inf
38
+ .ele('DataEmissao').txt(dataEmissao).up()
39
+ .ele('NaturezaOperacao').txt(String(documento.naturezaOperacao ?? 1)).up()
40
+ .ele('OptanteSimplesNacional').txt(String(documento.optanteSimplesNacional ?? 1)).up()
41
+ .ele('IncentivadorCultural').txt(String(documento.incentivadorCultural ?? 2)).up()
42
+ .ele('Status').txt('1').up();
43
+
44
+ const servico = inf.ele('Servico');
45
+ const valores = servico.ele('Valores');
46
+ valores
47
+ .ele('ValorServicos').txt(dec(valorServicos)).up()
48
+ .ele('ValorDeducoes').txt(dec(documento.servico.valorDeducoes ?? 0)).up()
49
+ .ele('ValorPis').txt(dec(documento.servico.valorPis ?? 0)).up()
50
+ .ele('ValorCofins').txt(dec(documento.servico.valorCofins ?? 0)).up()
51
+ .ele('ValorInss').txt(dec(documento.servico.valorInss ?? 0)).up()
52
+ .ele('ValorIr').txt(dec(documento.servico.valorIr ?? 0)).up()
53
+ .ele('ValorCsll').txt(dec(documento.servico.valorCsll ?? 0)).up()
54
+ .ele('IssRetido').txt(String(documento.servico.issRetido ?? 2)).up()
55
+ .ele('ValorIss').txt(dec(valorIss)).up()
56
+ .ele('BaseCalculo').txt(dec(baseCalculo)).up()
57
+ .ele('Aliquota').txt(dec(documento.servico.aliquotaIss ?? 0, 4)).up()
58
+ .ele('ValorLiquidoNfse').txt(dec(valorLiquido)).up()
59
+ .ele('DescontoIncondicionado').txt(dec(documento.servico.descontoIncondicionado ?? 0)).up()
60
+ .ele('DescontoCondicionado').txt(dec(documento.servico.descontoCondicionado ?? 0)).up();
61
+ valores.up();
62
+
63
+ servico
64
+ .ele('ItemListaServico').txt(documento.servico.itemListaServico).up()
65
+ .ele('Discriminacao').txt(documento.servico.discriminacao).up()
66
+ .ele('CodigoMunicipio').txt(documento.servico.codigoMunicipio).up();
67
+ servico.up();
68
+
69
+ const prestador = inf.ele('Prestador');
70
+ prestador
71
+ .ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up()
72
+ .ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
73
+ prestador.up();
74
+
75
+ const tomador = inf.ele('Tomador');
76
+ const identTomador = tomador.ele('IdentificacaoTomador').ele('CpfCnpj');
77
+ const docTomador = (documento.tomador.cnpj ?? documento.tomador.cpf ?? '').replace(/\D/g, '');
78
+ if (docTomador.length === 14) identTomador.ele('Cnpj').txt(docTomador).up();
79
+ else if (docTomador.length === 11) identTomador.ele('Cpf').txt(docTomador).up();
80
+ identTomador.up().up();
81
+ tomador.ele('RazaoSocial').txt(documento.tomador.razaoSocial).up();
82
+
83
+ if (documento.tomador.endereco) {
84
+ const end = tomador.ele('Endereco');
85
+ const e = documento.tomador.endereco;
86
+ end.ele('Endereco').txt(e.logradouro).up();
87
+ end.ele('Numero').txt(e.numero).up();
88
+ if (e.complemento) end.ele('Complemento').txt(e.complemento).up();
89
+ end.ele('Bairro').txt(e.bairro).up();
90
+ end.ele('CodigoMunicipio').txt(e.codigoMunicipio).up();
91
+ end.ele('Uf').txt(e.uf).up();
92
+ end.ele('Cep').txt(e.cep.replace(/\D/g, '')).up();
93
+ end.up();
94
+ }
95
+
96
+ if (documento.tomador.email) {
97
+ tomador.ele('Contato').ele('Email').txt(documento.tomador.email).up().up();
98
+ }
99
+ tomador.up();
100
+
101
+ if (documento.informacoesComplementares) {
102
+ inf.ele('Observacao').txt(documento.informacoesComplementares).up();
103
+ }
104
+
105
+ return inf;
106
+ }
107
+
108
+ /** @param {number} v @param {number} [d] */
109
+ function dec(v, d = 2) {
110
+ return Number(v).toFixed(d);
111
+ }
112
+
113
+ /**
114
+ * @param {import('../types/NFSeDocument.js').NFSeDocumento} documento
115
+ */
116
+ function validarDocumento(documento) {
117
+ if (!documento.numero) throw new GhinfeError('numero do RPS é obrigatório', 'NFSE_NUMERO_REQUIRED');
118
+ if (!documento.cnpjPrestador) throw new GhinfeError('cnpjPrestador é obrigatório', 'NFSE_CNPJ_REQUIRED');
119
+ if (!documento.inscricaoMunicipal) throw new GhinfeError('inscricaoMunicipal é obrigatória', 'NFSE_IM_REQUIRED');
120
+ if (!documento.servico) throw new GhinfeError('servico é obrigatório', 'NFSE_SERVICO_REQUIRED');
121
+ if (!documento.tomador) throw new GhinfeError('tomador é obrigatório', 'NFSE_TOMADOR_REQUIRED');
122
+ }
123
+
124
+ /**
125
+ * Adapters de layout municipal.
126
+ * Mantêm o mesmo objeto de domínio e trocam o wrapper/namespace XML.
127
+ */
128
+ export const NFSeLayoutAdapters = {
129
+ [NFSE_LAYOUTS.ABRASF]: {
130
+ nome: 'ABRASF 2.04',
131
+ build(documento) {
132
+ validarDocumento(documento);
133
+ const doc = create({ version: '1.0', encoding: 'UTF-8' })
134
+ .ele('GerarNfseEnvio', { xmlns: NFSE_NAMESPACE });
135
+ const rps = doc.ele('Rps');
136
+ appendInfRps(rps, documento, 'InfRps');
137
+ return doc.end({ prettyPrint: false, headless: false });
138
+ },
139
+ },
140
+
141
+ [NFSE_LAYOUTS.GINFES]: {
142
+ nome: 'GINFES',
143
+ build(documento) {
144
+ validarDocumento(documento);
145
+ const doc = create({ version: '1.0', encoding: 'UTF-8' })
146
+ .ele('EnviarLoteRpsEnvio', { xmlns: GINFES_NAMESPACE });
147
+ const lote = doc.ele('LoteRps', { Id: `Lote${documento.numero}`, versao: '3.00' });
148
+ lote.ele('NumeroLote').txt(String(documento.numero)).up();
149
+ lote.ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up();
150
+ lote.ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
151
+ lote.ele('QuantidadeRps').txt('1').up();
152
+ const lista = lote.ele('ListaRps').ele('Rps');
153
+ appendInfRps(lista, documento, 'InfRps');
154
+ return doc.end({ prettyPrint: false, headless: false });
155
+ },
156
+ },
157
+
158
+ [NFSE_LAYOUTS.BETHA]: {
159
+ nome: 'Betha',
160
+ build(documento) {
161
+ validarDocumento(documento);
162
+ const doc = create({ version: '1.0', encoding: 'UTF-8' })
163
+ .ele('GerarNfseEnvio', { xmlns: BETHA_NAMESPACE });
164
+ const rps = doc.ele('Rps');
165
+ appendInfRps(rps, documento, 'InfDeclaracaoPrestacaoServico');
166
+ return doc.end({ prettyPrint: false, headless: false });
167
+ },
168
+ },
169
+
170
+ [NFSE_LAYOUTS.ISSNET]: {
171
+ nome: 'ISSNet',
172
+ build(documento) {
173
+ validarDocumento(documento);
174
+ const doc = create({ version: '1.0', encoding: 'UTF-8' })
175
+ .ele('EnviarLoteRpsEnvio', { xmlns: ISSNET_NAMESPACE });
176
+ const lote = doc.ele('LoteRps', { Id: `Lote${documento.numero}`, versao: '2.04' });
177
+ lote.ele('NumeroLote').txt(String(documento.numero)).up();
178
+ lote.ele('CpfCnpj').ele('Cnpj').txt(documento.cnpjPrestador.replace(/\D/g, '')).up().up();
179
+ lote.ele('InscricaoMunicipal').txt(documento.inscricaoMunicipal).up();
180
+ lote.ele('QuantidadeRps').txt('1').up();
181
+ const lista = lote.ele('ListaRps').ele('Rps');
182
+ appendInfRps(lista, documento, 'InfDeclaracaoPrestacaoServico');
183
+ return doc.end({ prettyPrint: false, headless: false });
184
+ },
185
+ },
186
+ };
187
+
188
+ /**
189
+ * @param {string} layout
190
+ * @returns {typeof NFSeLayoutAdapters[string]}
191
+ */
192
+ export function obterAdapter(layout) {
193
+ const key = (layout ?? NFSE_LAYOUTS.ABRASF).toLowerCase();
194
+ const adapter = NFSeLayoutAdapters[key];
195
+ if (!adapter) {
196
+ throw new GhinfeError(
197
+ `Layout NFS-e não suportado: ${layout}. Use: ${Object.keys(NFSE_LAYOUTS).join(', ')}`,
198
+ 'NFSE_LAYOUT_UNSUPPORTED'
199
+ );
200
+ }
201
+ return adapter;
202
+ }