@sinete/nfe 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +11 -0
  3. package/README.md +148 -1
  4. package/dist/build/build.d.ts +127 -0
  5. package/dist/build/build.d.ts.map +1 -0
  6. package/dist/build/destinatario.d.ts +19 -0
  7. package/dist/build/destinatario.d.ts.map +1 -0
  8. package/dist/build/ibscbs.d.ts +27 -0
  9. package/dist/build/ibscbs.d.ts.map +1 -0
  10. package/dist/build/icms.d.ts +42 -0
  11. package/dist/build/icms.d.ts.map +1 -0
  12. package/dist/build/nfce.d.ts +122 -0
  13. package/dist/build/nfce.d.ts.map +1 -0
  14. package/dist/build/pl.d.ts +19 -0
  15. package/dist/build/pl.d.ts.map +1 -0
  16. package/dist/build/rejeicoes.d.ts +52 -0
  17. package/dist/build/rejeicoes.d.ts.map +1 -0
  18. package/dist/build/tributos.d.ts +45 -0
  19. package/dist/build/tributos.d.ts.map +1 -0
  20. package/dist/build/values.d.ts +48 -0
  21. package/dist/build/values.d.ts.map +1 -0
  22. package/dist/decimal.d.ts +66 -0
  23. package/dist/decimal.d.ts.map +1 -0
  24. package/dist/format.d.ts +48 -0
  25. package/dist/format.d.ts.map +1 -0
  26. package/dist/ibs-cbs.d.ts +14 -0
  27. package/dist/ibs-cbs.d.ts.map +1 -0
  28. package/dist/ibs-cbs.js +43 -0
  29. package/dist/ibs-cbs.js.map +10 -0
  30. package/dist/index.d.ts +37 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +4399 -0
  33. package/dist/index.js.map +33 -0
  34. package/dist/issues.d.ts +24 -0
  35. package/dist/issues.d.ts.map +1 -0
  36. package/dist/model.d.ts +861 -0
  37. package/dist/model.d.ts.map +1 -0
  38. package/dist/ports.d.ts +109 -0
  39. package/dist/ports.d.ts.map +1 -0
  40. package/dist/rotulo.d.ts +12 -0
  41. package/dist/rotulo.d.ts.map +1 -0
  42. package/dist/rtc.d.ts +65 -0
  43. package/dist/rtc.d.ts.map +1 -0
  44. package/dist/services/client.d.ts +277 -0
  45. package/dist/services/client.d.ts.map +1 -0
  46. package/dist/services/gzip.d.ts +7 -0
  47. package/dist/services/gzip.d.ts.map +1 -0
  48. package/dist/services/index.d.ts +14 -0
  49. package/dist/services/index.d.ts.map +1 -0
  50. package/dist/services/outcome.d.ts +15 -0
  51. package/dist/services/outcome.d.ts.map +1 -0
  52. package/dist/services/proc.d.ts +41 -0
  53. package/dist/services/proc.d.ts.map +1 -0
  54. package/dist/services/recuperar.d.ts +28 -0
  55. package/dist/services/recuperar.d.ts.map +1 -0
  56. package/dist/services/resolver.d.ts +88 -0
  57. package/dist/services/resolver.d.ts.map +1 -0
  58. package/dist/services/soap.d.ts +43 -0
  59. package/dist/services/soap.d.ts.map +1 -0
  60. package/dist/time.d.ts +12 -0
  61. package/dist/time.d.ts.map +1 -0
  62. package/dist/versao-gerada.d.ts +3 -0
  63. package/dist/versao-gerada.d.ts.map +1 -0
  64. package/package.json +58 -3
  65. package/src/build/build.ts +1503 -0
  66. package/src/build/destinatario.ts +212 -0
  67. package/src/build/ibscbs.ts +135 -0
  68. package/src/build/icms.ts +645 -0
  69. package/src/build/nfce.ts +425 -0
  70. package/src/build/pl.ts +73 -0
  71. package/src/build/rejeicoes.ts +142 -0
  72. package/src/build/tributos.ts +217 -0
  73. package/src/build/values.ts +126 -0
  74. package/src/data/arredondamento.json +30 -0
  75. package/src/data/cstat.json +36 -0
  76. package/src/data/fusos.json +17 -0
  77. package/src/data/nfce-urls.json +170 -0
  78. package/src/data/produtor-rural.json +17 -0
  79. package/src/data/reforma.json +6 -0
  80. package/src/data/resp-tec.json +13 -0
  81. package/src/data/servicos.json +44 -0
  82. package/src/data/suframa.json +7 -0
  83. package/src/decimal.ts +232 -0
  84. package/src/format.ts +65 -0
  85. package/src/ibs-cbs.ts +89 -0
  86. package/src/index.ts +155 -0
  87. package/src/issues.ts +80 -0
  88. package/src/model.ts +1033 -0
  89. package/src/ports.ts +96 -0
  90. package/src/rotulo.ts +137 -0
  91. package/src/rtc.ts +305 -0
  92. package/src/services/client.ts +1116 -0
  93. package/src/services/gzip.ts +26 -0
  94. package/src/services/index.ts +45 -0
  95. package/src/services/outcome.ts +50 -0
  96. package/src/services/proc.ts +165 -0
  97. package/src/services/recuperar.ts +93 -0
  98. package/src/services/resolver.ts +127 -0
  99. package/src/services/soap.ts +133 -0
  100. package/src/time.ts +23 -0
  101. package/src/versao-gerada.ts +3 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Regras do grupo E (destinatário) do MOC 7.0 Anexo I que dependem só do documento e são obrigatórias no modelo 55 ou
3
+ * 65, conferidas antes de assinar com o caminho da entrada (ADR 0012, seção "Destinatário"). Ficam de fora as que
4
+ * dependem de tabela externa (municípios do IBGE, E10-10; países do BACEN, E14-04), do cadastro da SEFAZ (5E17) ou do
5
+ * critério da UF (E16a-30 e E16a-35, E14-10 e E14-20, facultativas). As regras só da NFC-e estão em `nfce.ts`.
6
+ */
7
+
8
+ import { ufPorSigla } from '@sinete/core';
9
+ import { lerCnpj } from '@sinete/validators';
10
+ import suframa from '../data/suframa.json' with { type: 'json' };
11
+ import type { Issues } from '../issues.ts';
12
+ import type { DadosNfe } from '../model.ts';
13
+
14
+ /** Identificação já resolvida pelo montador (com os padrões aplicados). */
15
+ export interface IdeDestinatario {
16
+ readonly mod: '55' | '65';
17
+ readonly tpNF: string;
18
+ readonly idDest: string;
19
+ readonly idDestInformado: boolean;
20
+ readonly indFinal: string;
21
+ readonly producao: boolean;
22
+ }
23
+
24
+ /** Caracteres do idEstrangeiro (E03a-60): algarismos, letras e `:.+-/()`. */
25
+ const ID_ESTRANGEIRO = /^[0-9A-Za-z:.+\-/()]*$/;
26
+
27
+ const digitos = (s: string): string => s.replace(/\D/g, '');
28
+
29
+ export function conferirDestinatario(input: DadosNfe, ide: IdeDestinatario, issues: Issues): void {
30
+ const d = input.destinatario;
31
+ if (d === undefined) return;
32
+ const nfe = ide.mod === '55';
33
+ const emitUf = input.emitente.endereco.UF;
34
+ const end = d.endereco;
35
+ const exterior = end !== undefined && 'exterior' in end && end.exterior === true;
36
+ const destUf = end === undefined ? undefined : exterior ? 'EX' : (end as { UF: string }).UF;
37
+ const idEstrangeiro = 'idEstrangeiro' in d ? d.idEstrangeiro : undefined;
38
+
39
+ // E03a: destinatário estrangeiro.
40
+ if (nfe && ide.idDest === '3' && idEstrangeiro === undefined) {
41
+ issues.add(
42
+ 'destinatario',
43
+ 'campo_obrigatorio',
44
+ 'na operação com o exterior (idDest 3) o destinatário é identificado por idEstrangeiro, mesmo vazio (E03a-10, rejeição 720)',
45
+ );
46
+ }
47
+ if (nfe && idEstrangeiro !== undefined && ide.idDest !== '3' && ide.indFinal !== '1') {
48
+ issues.add(
49
+ 'destinatario.idEstrangeiro',
50
+ 'combinacao_invalida',
51
+ 'idEstrangeiro fora da operação com o exterior só com consumidor final, indFinal 1 (E03a-20, rejeição 721)',
52
+ );
53
+ }
54
+ if (idEstrangeiro !== undefined && d.IE !== undefined) {
55
+ issues.add(
56
+ 'destinatario.IE',
57
+ 'combinacao_invalida',
58
+ 'destinatário estrangeiro (idEstrangeiro) não informa IE (E03a-30, rejeição 925)',
59
+ );
60
+ }
61
+ if (idEstrangeiro !== undefined && !ID_ESTRANGEIRO.test(idEstrangeiro)) {
62
+ issues.add(
63
+ 'destinatario.idEstrangeiro',
64
+ 'campo_invalido',
65
+ 'idEstrangeiro só com algarismos, letras e os caracteres : . + - / ( ) (E03a-60, rejeição 372)',
66
+ );
67
+ }
68
+
69
+ // E04 e E05: nome e endereço na NF-e. Em homologação o nome é o literal da E04-20, posto pelo montador.
70
+ if (nfe && ide.producao && (d.xNome === undefined || d.xNome.trim() === '')) {
71
+ issues.add(
72
+ 'destinatario.xNome',
73
+ 'campo_obrigatorio',
74
+ 'a NF-e informa o nome do destinatário (E04-10, rejeição 724)',
75
+ );
76
+ }
77
+ if (nfe && end === undefined) {
78
+ issues.add(
79
+ 'destinatario.endereco',
80
+ 'campo_obrigatorio',
81
+ 'a NF-e informa o endereço do destinatário (E05-10, rejeição 726)',
82
+ );
83
+ }
84
+
85
+ // E10-20: o município do destinatário é da UF dele (as duas primeiras posições do código são o código da UF).
86
+ if (end !== undefined && !exterior) {
87
+ const e = end as { UF: string; cMun: string };
88
+ const cUF = ufPorSigla(e.UF)?.cUF;
89
+ if (cUF !== undefined && digitos(e.cMun).slice(0, 2) !== cUF) {
90
+ issues.add(
91
+ 'destinatario.endereco.cMun',
92
+ 'combinacao_invalida',
93
+ `município ${e.cMun} não é da UF ${e.UF} do destinatário (E10-20, rejeição 275)`,
94
+ );
95
+ }
96
+ }
97
+
98
+ // E12-30 a E12-60: idDest contra as UFs do emitente e do destinatário, com as exceções da própria regra.
99
+ if (nfe && destUf !== undefined && destUf !== 'EX') {
100
+ const caminho = ide.idDestInformado ? 'idDest' : 'destinatario.endereco.UF';
101
+ const ufsCons = input.itens.flatMap((it) => {
102
+ const esp = it.produto.especifico;
103
+ return esp !== undefined && 'comb' in esp ? [String(esp.comb.UFCons)] : [];
104
+ });
105
+ const entrega = input.entrega?.UF;
106
+ const retirada = input.retirada?.UF;
107
+ const saida = ide.tpNF === '1';
108
+ // Na saída a entrega vale contra o emitente e a retirada contra o destinatário; na entrada, ao contrário.
109
+ const [ufEntrega, ufRetirada] = saida ? [emitUf, destUf] : [destUf, emitUf];
110
+ if (ide.idDest === '2' && destUf === emitUf) {
111
+ // CNPJ alfanumérico: as letras contam; só a máscara sai (a mesma normalização do lerCnpj).
112
+ const cnpj = (v: string | undefined): string | undefined => {
113
+ if (v === undefined) return undefined;
114
+ const r = lerCnpj(v);
115
+ return r.ok ? r.valor : undefined;
116
+ };
117
+ const cnpjDest = 'CNPJ' in d ? cnpj(d.CNPJ) : undefined;
118
+ const mesmoCnpj = cnpjDest !== undefined && cnpjDest === cnpj(input.emitente.CNPJ);
119
+ const excecao =
120
+ ufsCons.some((u) => u !== emitUf) ||
121
+ (entrega !== undefined && retirada === undefined && entrega !== ufEntrega) ||
122
+ (retirada !== undefined && entrega === undefined && retirada !== ufRetirada) ||
123
+ (entrega !== undefined && retirada !== undefined && entrega !== retirada);
124
+ if (!mesmoCnpj && !excecao) {
125
+ issues.add(
126
+ caminho,
127
+ 'combinacao_invalida',
128
+ `operação interestadual (idDest 2) com o destinatário na UF do emitente (${emitUf}) (${saida ? 'E12-30' : 'E12-50'}, rejeição 772)`,
129
+ );
130
+ }
131
+ }
132
+ if (ide.idDest === '1' && destUf !== emitUf && ide.indFinal !== '1') {
133
+ const excecao =
134
+ ufsCons.some((u) => u === emitUf) ||
135
+ (entrega !== undefined && retirada === undefined && entrega === ufEntrega) ||
136
+ (retirada !== undefined && entrega === undefined && retirada === ufRetirada) ||
137
+ (entrega !== undefined && retirada !== undefined && entrega === retirada);
138
+ if (!excecao) {
139
+ issues.add(
140
+ caminho,
141
+ 'combinacao_invalida',
142
+ `operação interna (idDest 1) com o destinatário em ${destUf}, fora da UF do emitente (${emitUf}) (${saida ? 'E12-40' : 'E12-60'}, rejeição 773)`,
143
+ );
144
+ }
145
+ }
146
+ }
147
+
148
+ // E14-30: no exterior, o país não é o Brasil (o código pode vir com zeros à esquerda).
149
+ if (exterior && Number(digitos((end as { cPais: string }).cPais)) === 1058) {
150
+ issues.add(
151
+ 'destinatario.endereco.cPais',
152
+ 'campo_invalido',
153
+ 'destinatário no exterior com o país Brasil, 1058 (E14-30, rejeição 926)',
154
+ );
155
+ }
156
+
157
+ if (!nfe) return;
158
+
159
+ // E16a: indicador da IE.
160
+ if (ide.idDest === '3' && d.indIEDest !== '9') {
161
+ issues.add(
162
+ 'destinatario.indIEDest',
163
+ 'combinacao_invalida',
164
+ 'na operação com o exterior o destinatário é não contribuinte, indIEDest 9 (E16a-20, rejeição 790)',
165
+ );
166
+ }
167
+ if (d.indIEDest === '9' && ide.indFinal !== '1' && ide.tpNF === '1' && ide.idDest !== '3') {
168
+ issues.add(
169
+ 'indFinal',
170
+ 'combinacao_invalida',
171
+ 'saída para não contribuinte (indIEDest 9) é operação com consumidor final, indFinal 1 (E16a-40, rejeição 696)',
172
+ );
173
+ }
174
+
175
+ // E17: a IE do destinatário.
176
+ if (d.indIEDest === '1' && d.IE === undefined) {
177
+ issues.add(
178
+ 'destinatario.IE',
179
+ 'campo_obrigatorio',
180
+ 'destinatário contribuinte (indIEDest 1) informa a IE (E17-20, rejeição 728)',
181
+ );
182
+ }
183
+ if (d.indIEDest === '2' && d.IE !== undefined) {
184
+ issues.add(
185
+ 'destinatario.IE',
186
+ 'combinacao_invalida',
187
+ 'destinatário contribuinte isento (indIEDest 2) não informa a IE (E17-30, rejeição 791)',
188
+ );
189
+ }
190
+ if (exterior && d.IE !== undefined) {
191
+ issues.add(
192
+ 'destinatario.IE',
193
+ 'combinacao_invalida',
194
+ 'destinatário no exterior não informa a IE (E17-40, rejeição 792)',
195
+ );
196
+ }
197
+
198
+ // E18-30: a inscrição na Suframa só vale nas UFs e municípios da área incentivada; no exterior (UF EX), nunca.
199
+ if (d.ISUF !== undefined && destUf !== undefined) {
200
+ const cMun = exterior ? '' : digitos((end as { cMun: string }).cMun);
201
+ const municipios = (suframa.municipios as Record<string, readonly string[]>)[destUf];
202
+ const aceita = suframa.ufs.includes(destUf) || (municipios?.includes(cMun) ?? false);
203
+ if (!aceita) {
204
+ const onde = exterior ? 'no exterior' : `${destUf}, município ${(end as { cMun: string }).cMun}`;
205
+ issues.add(
206
+ 'destinatario.ISUF',
207
+ 'combinacao_invalida',
208
+ `inscrição na Suframa com o destinatário fora da área incentivada (${onde}) (E18-30, rejeição 251)`,
209
+ );
210
+ }
211
+ }
212
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * IBS/CBS (grupo UB, NT 2025.002): chama a calculadora injetada para os itens classificados e totaliza o grupo
3
+ * `IBSCBSTot` (W34 a W59g) somando exatamente os valores dos itens.
4
+ */
5
+
6
+ import { lerXml, primeiroFilho } from '@sinete/core/xml';
7
+ import type { ComplexType } from '@sinete/schemas';
8
+ import { serializar, validar } from '@sinete/schemas';
9
+ import type { TIBSCBSMonoTot, TTribNFe } from '@sinete/schemas/nfe/PL_010f';
10
+ import { Decimal } from '../decimal.ts';
11
+ import type { Issues } from '../issues.ts';
12
+
13
+ const NFE_NS = 'http://www.portalfiscal.inf.br/nfe';
14
+
15
+ /**
16
+ * Valida contra o schema um grupo repassado (IBSCBS pronto ou da calculadora, IS) antes de qualquer soma: grupo
17
+ * incompleto vira ocorrência `schema` com o caminho do item, nunca exceção no meio dos totais.
18
+ */
19
+ export function grupoInvalido(ct: ComplexType, nome: string, value: unknown, path: string, issues: Issues): boolean {
20
+ if (value === undefined) return false;
21
+ try {
22
+ const doc = lerXml(`<w xmlns="${NFE_NS}">${serializar(ct, nome, value as never, NFE_NS)}</w>`);
23
+ const el = primeiroFilho(doc.raiz, nome, NFE_NS);
24
+ const erros =
25
+ el === undefined ? [{ caminho: '', code: 'modelo_de_conteudo', mensagem: 'grupo vazio' }] : validar(ct, el);
26
+ for (const e of erros)
27
+ issues.add(
28
+ `${path}${e.caminho.replace(/^\/[^/]+/, '').replace(/\//g, '.')}`,
29
+ 'schema',
30
+ `${e.code}: ${e.mensagem}`,
31
+ );
32
+ return erros.length > 0;
33
+ } catch (e) {
34
+ issues.add(path, 'schema', `grupo malformado: ${(e as Error).message}`);
35
+ return true;
36
+ }
37
+ }
38
+
39
+ /** Campos numéricos dos grupos do leiaute: valores, percentuais, quantidades e ad rem (`vBC`, `pIBSUF`, `qBCMono`...). */
40
+ const NUMERICO = /^(v|p|q|adRem)[A-Z]/;
41
+
42
+ /** Aponta cada campo numérico que não é um decimal válido, em qualquer profundidade de um grupo repassado. */
43
+ export function decimaisInvalidos(value: unknown, path: string, issues: Issues): void {
44
+ if (typeof value !== 'object' || value === null) return;
45
+ for (const [k, v] of Object.entries(value)) {
46
+ const p = `${path}.${k}`;
47
+ if (typeof v === 'string' && NUMERICO.test(k) && Decimal.tryOf(v) === undefined) {
48
+ issues.add(p, 'decimal_invalido', 'número decimal inválido');
49
+ } else if (typeof v === 'object') decimaisInvalidos(v, p, issues);
50
+ }
51
+ }
52
+
53
+ /** Soma todos os campos `name` em qualquer profundidade do objeto (valores lexicais do leiaute). */
54
+ export function somaCampo(value: unknown, name: string): Decimal {
55
+ if (typeof value !== 'object' || value === null) return Decimal.ZERO;
56
+ let acc = Decimal.ZERO;
57
+ for (const [k, v] of Object.entries(value)) {
58
+ if (k === name && typeof v === 'string') acc = acc.plus(Decimal.of(v));
59
+ else if (typeof v === 'object') acc = acc.plus(somaCampo(v, name));
60
+ }
61
+ return acc;
62
+ }
63
+
64
+ /** Valores do grupo do item que entram no vItem (VB01-10): vIBS, vCBS e os totais monofásicos. */
65
+ export function ibsCbsDoItem(g: TTribNFe): {
66
+ vIBS: Decimal;
67
+ vCBS: Decimal;
68
+ vTotIBSMonoItem: Decimal;
69
+ vTotCBSMonoItem: Decimal;
70
+ } {
71
+ const s = (x: string | undefined): Decimal => (x === undefined ? Decimal.ZERO : Decimal.of(x));
72
+ return {
73
+ vIBS: s(g.gIBSCBS?.vIBS),
74
+ vCBS: s(g.gIBSCBS?.gCBS.vCBS),
75
+ vTotIBSMonoItem: s(g.gIBSCBSMono?.vTotIBSMonoItem),
76
+ vTotCBSMonoItem: s(g.gIBSCBSMono?.vTotCBSMonoItem),
77
+ };
78
+ }
79
+
80
+ /** `IBSCBSTot` a partir dos grupos dos itens (NT 2025.002, W35-10 a W59g-10). */
81
+ export function totalIbsCbs(grupos: readonly TTribNFe[]): TIBSCBSMonoTot {
82
+ const f = (d: Decimal): string => d.toFixed(2);
83
+ const sum = (pick: (g: TTribNFe) => unknown, name: string): Decimal =>
84
+ grupos.reduce((acc, g) => acc.plus(somaCampo(pick(g), name)), Decimal.ZERO);
85
+ // gIBS e gCBS entram quando há tributação regular ou crédito presumido em algum item: o crédito pode vir sem o
86
+ // gIBSCBS e não pode sumir do total.
87
+ const regulares = grupos.filter((g) => g.gIBSCBS !== undefined || g.gCredPresOper !== undefined);
88
+ const total: Record<string, unknown> = {
89
+ vBCIBSCBS: f(sum((g) => g.gIBSCBS && { vBC: g.gIBSCBS.vBC }, 'vBC')),
90
+ };
91
+ if (regulares.length > 0) {
92
+ const credIbs = (g: TTribNFe): unknown => g.gCredPresOper?.gIBSCredPres;
93
+ const credCbs = (g: TTribNFe): unknown => g.gCredPresOper?.gCBSCredPres;
94
+ total.gIBS = {
95
+ gIBSUF: {
96
+ vDif: f(sum((g) => g.gIBSCBS?.gIBSUF.gDif, 'vDif')),
97
+ vDevTrib: f(sum((g) => g.gIBSCBS?.gIBSUF.gDevTrib, 'vDevTrib')),
98
+ vIBSUF: f(sum((g) => g.gIBSCBS && { v: g.gIBSCBS.gIBSUF.vIBSUF }, 'v')),
99
+ },
100
+ gIBSMun: {
101
+ vDif: f(sum((g) => g.gIBSCBS?.gIBSMun.gDif, 'vDif')),
102
+ vDevTrib: f(sum((g) => g.gIBSCBS?.gIBSMun.gDevTrib, 'vDevTrib')),
103
+ vIBSMun: f(sum((g) => g.gIBSCBS && { v: g.gIBSCBS.gIBSMun.vIBSMun }, 'v')),
104
+ },
105
+ vIBS: f(sum((g) => g.gIBSCBS && { v: g.gIBSCBS.vIBS }, 'v')),
106
+ vCredPres: f(sum(credIbs, 'vCredPres')),
107
+ vCredPresCondSus: f(sum(credIbs, 'vCredPresCondSus')),
108
+ };
109
+ total.gCBS = {
110
+ vDif: f(sum((g) => g.gIBSCBS?.gCBS.gDif, 'vDif')),
111
+ vDevTrib: f(sum((g) => g.gIBSCBS?.gCBS.gDevTrib, 'vDevTrib')),
112
+ vCBS: f(sum((g) => g.gIBSCBS && { v: g.gIBSCBS.gCBS.vCBS }, 'v')),
113
+ vCredPres: f(sum(credCbs, 'vCredPres')),
114
+ vCredPresCondSus: f(sum(credCbs, 'vCredPresCondSus')),
115
+ };
116
+ }
117
+ if (grupos.some((g) => g.gIBSCBSMono !== undefined)) {
118
+ const mono = (n: string): string => f(sum((g) => g.gIBSCBSMono, n));
119
+ total.gMono = {
120
+ vIBSMono: mono('vIBSMono'),
121
+ vCBSMono: mono('vCBSMono'),
122
+ vIBSMonoReten: mono('vIBSMonoReten'),
123
+ vCBSMonoReten: mono('vCBSMonoReten'),
124
+ vIBSMonoRet: mono('vIBSMonoRet'),
125
+ vCBSMonoRet: mono('vCBSMonoRet'),
126
+ };
127
+ }
128
+ if (grupos.some((g) => g.gEstornoCred !== undefined)) {
129
+ total.gEstornoCred = {
130
+ vIBSEstCred: f(sum((g) => g.gEstornoCred, 'vIBSEstCred')),
131
+ vCBSEstCred: f(sum((g) => g.gEstornoCred, 'vCBSEstCred')),
132
+ };
133
+ }
134
+ return total as TIBSCBSMonoTot;
135
+ }