@sinete/nfe 0.0.0 → 0.1.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 +147 -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 +4370 -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 +273 -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 +1486 -0
  66. package/src/build/destinatario.ts +212 -0
  67. package/src/build/ibscbs.ts +131 -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 +231 -0
  84. package/src/format.ts +64 -0
  85. package/src/ibs-cbs.ts +89 -0
  86. package/src/index.ts +153 -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 +1085 -0
  93. package/src/services/gzip.ts +26 -0
  94. package/src/services/index.ts +43 -0
  95. package/src/services/outcome.ts +50 -0
  96. package/src/services/proc.ts +164 -0
  97. package/src/services/recuperar.ts +91 -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,645 @@
1
+ /**
2
+ * Grupo ICMS do item (N01 a N10h). Cada CST/CSOSN do modelo vira o grupo do leiaute correspondente; os valores
3
+ * derivados são calculados com as fórmulas das regras de validação do MOC 7.0 Anexo I, citadas em cada conta.
4
+ */
5
+
6
+ import type { TNFe_infNFe_det_imposto_ICMS } from '@sinete/schemas/nfe/PL_010f';
7
+ import type { DecimalInput } from '../decimal.ts';
8
+ import { Decimal } from '../decimal.ts';
9
+ import type { DecimalFormat } from '../format.ts';
10
+ import { D0302A04, D0302A04_OPC, D1104V, D1302 } from '../format.ts';
11
+ import type {
12
+ Desoneracao,
13
+ DesoneracaoSt,
14
+ Icms,
15
+ IcmsFcp,
16
+ IcmsSt,
17
+ IcmsStRetido,
18
+ MotivoDesoneracaoIcms,
19
+ } from '../model.ts';
20
+ import type { Ctx } from './values.ts';
21
+ import { clean } from './values.ts';
22
+
23
+ /** O que o grupo ICMS do item soma nos totais (W02 a W06a e os monofásicos). */
24
+ export interface IcmsTotais {
25
+ vBC: Decimal;
26
+ vICMS: Decimal;
27
+ vICMSDeson: Decimal;
28
+ /** Parte do desonerado que deduz do valor do item e do total (indDeduzDeson=1). */
29
+ vICMSDesonDeduz: Decimal;
30
+ vFCP: Decimal;
31
+ vBCST: Decimal;
32
+ vST: Decimal;
33
+ vFCPST: Decimal;
34
+ vFCPSTRet: Decimal;
35
+ qBCMono: Decimal;
36
+ vICMSMono: Decimal;
37
+ qBCMonoReten: Decimal;
38
+ vICMSMonoReten: Decimal;
39
+ qBCMonoRet: Decimal;
40
+ vICMSMonoRet: Decimal;
41
+ /** O item tem algum grupo monofásico (os totais monofásicos só vão para o XML nesse caso). */
42
+ mono: boolean;
43
+ }
44
+
45
+ export function zeroIcmsTotais(): IcmsTotais {
46
+ const z = Decimal.ZERO;
47
+ return {
48
+ vBC: z,
49
+ vICMS: z,
50
+ vICMSDeson: z,
51
+ vICMSDesonDeduz: z,
52
+ vFCP: z,
53
+ vBCST: z,
54
+ vST: z,
55
+ vFCPST: z,
56
+ vFCPSTRet: z,
57
+ qBCMono: z,
58
+ vICMSMono: z,
59
+ qBCMonoReten: z,
60
+ vICMSMonoReten: z,
61
+ qBCMonoRet: z,
62
+ vICMSMonoRet: z,
63
+ mono: false,
64
+ };
65
+ }
66
+
67
+ /** Dados do item que as contas do ICMS usam. */
68
+ export interface IcmsItemBase {
69
+ /** Valor da operação: vProd + vFrete + vSeg + vOutro - vDesc. */
70
+ readonly vOp: Decimal;
71
+ /** IPI do item (entra na base do ST por MVA). */
72
+ readonly vIPI: Decimal;
73
+ }
74
+
75
+ type Out = Record<string, string | undefined>;
76
+
77
+ const M: DecimalFormat = D1302;
78
+ const P: DecimalFormat = D0302A04;
79
+ const PO: DecimalFormat = D0302A04_OPC;
80
+
81
+ function nonNeg(d: Decimal): Decimal {
82
+ return d.isNegative() ? Decimal.ZERO : d;
83
+ }
84
+
85
+ export function buildIcms(
86
+ ctx: Ctx,
87
+ input: Icms,
88
+ base: IcmsItemBase,
89
+ path: string,
90
+ ): { grupo: TNFe_infNFe_det_imposto_ICMS; totais: IcmsTotais } {
91
+ const t = zeroIcmsTotais();
92
+ const S = (d: Decimal): string => ctx.s(d, M);
93
+
94
+ /** Parte própria: modBC, vBC (reduzida por pRedBC quando houver), pICMS, vICMS. MOC N15, N16, N17 (RV N17, nota *4). */
95
+ const proprio = (
96
+ i: { modBC?: string; vBC?: DecimalInput; pICMS?: DecimalInput; vICMS?: DecimalInput },
97
+ pRedBC: Decimal | undefined,
98
+ required: boolean,
99
+ ): { out: Out; vBC: Decimal; vICMS: Decimal } | undefined => {
100
+ const pICMS = required ? ctx.req(i.pICMS, `${path}.pICMS`, P) : ctx.opt(i.pICMS, `${path}.pICMS`, P);
101
+ if (pICMS === undefined && i.vBC === undefined && i.vICMS === undefined) return undefined;
102
+ const reduzida =
103
+ pRedBC === undefined ? base.vOp : base.vOp.times(Decimal.HUNDRED.minus(pRedBC)).dividedBy(100, 10, 'HALF_EVEN');
104
+ const vBC = ctx.base(i.vBC, reduzida, `${path}.vBC`, M, 'icms');
105
+ const aliq = pICMS ?? Decimal.ZERO;
106
+ const vICMS = ctx.calc(i.vICMS, vBC.percent(aliq), `${path}.vICMS`, M, 'icms');
107
+ t.vBC = t.vBC.plus(vBC);
108
+ t.vICMS = t.vICMS.plus(vICMS);
109
+ return {
110
+ out: { modBC: i.modBC ?? '3', vBC: S(vBC), pICMS: ctx.s(aliq, P), vICMS: S(vICMS) },
111
+ vBC,
112
+ vICMS,
113
+ };
114
+ };
115
+
116
+ /**
117
+ * Valor informado cujo grupo depende de outro campo ausente: vira ocorrência no campo que falta, nunca some do XML
118
+ * em silêncio.
119
+ */
120
+ const orfao = (
121
+ valor: DecimalInput | undefined,
122
+ presente: boolean,
123
+ campo: string,
124
+ exige: string,
125
+ base = path,
126
+ ): void => {
127
+ if (valor !== undefined && !presente) {
128
+ ctx.issues.add(`${base}.${exige}`, 'campo_obrigatorio', `${campo} informado exige ${exige}`);
129
+ }
130
+ };
131
+
132
+ /** FCP próprio (N17a a N17c). `vBCFCP` só vai para o XML nos grupos que o têm. */
133
+ const fcp = (i: IcmsFcp & { pFCP?: DecimalInput; vFCP?: DecimalInput }, vBC: Decimal, withBase: boolean): Out => {
134
+ const pFCP = ctx.opt(i.pFCP, `${path}.pFCP`, PO);
135
+ orfao(i.vBCFCP, i.pFCP !== undefined || i.vFCP !== undefined, 'vBCFCP', 'pFCP');
136
+ if (pFCP === undefined && i.vFCP === undefined) return {};
137
+ const vBCFCP = ctx.base(i.vBCFCP, vBC, `${path}.vBCFCP`, M, 'icms');
138
+ const vFCP = ctx.calc(i.vFCP, vBCFCP.percent(pFCP ?? Decimal.ZERO), `${path}.vFCP`, M, 'icms');
139
+ t.vFCP = t.vFCP.plus(vFCP);
140
+ return { ...(withBase ? { vBCFCP: S(vBCFCP) } : {}), pFCP: ctx.so(pFCP, PO), vFCP: S(vFCP) };
141
+ };
142
+
143
+ /**
144
+ * ICMS-ST (N18 a N23d). Base por MVA (modBCST 4) quando `vBCST` não vem: (vOp + vIPI) × (1 + pMVAST) × (1 - pRedBCST).
145
+ * `vICMSST = vBCST × pICMSST - ICMS próprio` (MOC N23); `vFCPST = vBCFCPST × pFCPST - vFCP` (RV N23d-10).
146
+ */
147
+ const st = (i: IcmsSt, vICMSProprio: Decimal, vFCPProprio: Decimal): Out => {
148
+ const sp = `${path}.st`;
149
+ const pMVAST = ctx.opt(i.pMVAST, `${sp}.pMVAST`, PO);
150
+ const pRedBCST = ctx.opt(i.pRedBCST, `${sp}.pRedBCST`, PO);
151
+ const pICMSST = ctx.req(i.pICMSST, `${sp}.pICMSST`, P);
152
+ if (i.modBCST === '4' && pMVAST === undefined) {
153
+ // RV N19-10 (rejeição 932): MVA como modalidade exige pMVAST.
154
+ ctx.issues.add(`${sp}.pMVAST`, 'campo_obrigatorio', 'modBCST 4 (MVA) exige pMVAST');
155
+ }
156
+ if (i.modBCST !== '4' && pMVAST !== undefined) {
157
+ // RV N19-20 (rejeição 933): pMVAST só com modalidade MVA.
158
+ ctx.issues.add(`${sp}.pMVAST`, 'combinacao_invalida', 'pMVAST só pode ser informado com modBCST 4 (MVA)');
159
+ }
160
+ let vBCST: Decimal;
161
+ if (i.vBCST === undefined && i.modBCST === '4') {
162
+ const bruta = base.vOp
163
+ .plus(base.vIPI)
164
+ .times(Decimal.HUNDRED.plus(pMVAST ?? Decimal.ZERO))
165
+ .dividedBy(100, 12, 'HALF_EVEN');
166
+ const reduzida =
167
+ pRedBCST === undefined ? bruta : bruta.times(Decimal.HUNDRED.minus(pRedBCST)).dividedBy(100, 12, 'HALF_EVEN');
168
+ vBCST = ctx.round(reduzida, M, 'icms');
169
+ } else {
170
+ vBCST = ctx.req(i.vBCST, `${sp}.vBCST`, M);
171
+ }
172
+ const deducao = ctx.opt(i.vICMSDeducaoST, `${sp}.vICMSDeducaoST`, M) ?? vICMSProprio;
173
+ const vICMSST = ctx.calc(
174
+ i.vICMSST,
175
+ nonNeg(ctx.round(vBCST.percent(pICMSST), M, 'icms').minus(deducao)),
176
+ `${sp}.vICMSST`,
177
+ M,
178
+ 'icms',
179
+ );
180
+ t.vBCST = t.vBCST.plus(vBCST);
181
+ t.vST = t.vST.plus(vICMSST);
182
+ const out: Out = {
183
+ modBCST: i.modBCST,
184
+ pMVAST: ctx.so(pMVAST, PO),
185
+ pRedBCST: ctx.so(pRedBCST, PO),
186
+ vBCST: S(vBCST),
187
+ pICMSST: ctx.s(pICMSST, P),
188
+ vICMSST: S(vICMSST),
189
+ };
190
+ const pFCPST = ctx.opt(i.pFCPST, `${sp}.pFCPST`, PO);
191
+ orfao(i.vBCFCPST, i.pFCPST !== undefined || i.vFCPST !== undefined, 'vBCFCPST', 'pFCPST', sp);
192
+ if (pFCPST !== undefined || i.vFCPST !== undefined) {
193
+ const vBCFCPST = ctx.base(i.vBCFCPST, vBCST, `${sp}.vBCFCPST`, M, 'icms');
194
+ const vFCPST = ctx.calc(
195
+ i.vFCPST,
196
+ nonNeg(ctx.round(vBCFCPST.percent(pFCPST ?? Decimal.ZERO), M, 'icms').minus(vFCPProprio)),
197
+ `${sp}.vFCPST`,
198
+ M,
199
+ 'icms',
200
+ );
201
+ t.vFCPST = t.vFCPST.plus(vFCPST);
202
+ Object.assign(out, { vBCFCPST: S(vBCFCPST), pFCPST: ctx.so(pFCPST, PO), vFCPST: S(vFCPST) });
203
+ }
204
+ return out;
205
+ };
206
+
207
+ /** Desoneração (N27a, N28, N28b): valor e motivo juntos. */
208
+ const deson = <K extends MotivoDesoneracaoIcms>(d: Desoneracao<K> | undefined): Out => {
209
+ if (d === undefined) return {};
210
+ const v = ctx.req(d.vICMSDeson, `${path}.desoneracao.vICMSDeson`, M);
211
+ t.vICMSDeson = t.vICMSDeson.plus(v);
212
+ if (d.indDeduzDeson === '1') t.vICMSDesonDeduz = t.vICMSDesonDeduz.plus(v);
213
+ return { vICMSDeson: S(v), motDesICMS: d.motDesICMS, indDeduzDeson: d.indDeduzDeson };
214
+ };
215
+
216
+ const desonSt = (d: DesoneracaoSt | undefined): Out => {
217
+ if (d === undefined) return {};
218
+ const v = ctx.req(d.vICMSSTDeson, `${path}.desoneracaoSt.vICMSSTDeson`, M);
219
+ return { vICMSSTDeson: S(v), motDesICMSST: d.motDesICMSST };
220
+ };
221
+
222
+ /** Retido anteriormente (N26 a N26b, N27a a N27c, N34 a N37): informativo, só o FCP retido entra no total. */
223
+ const retido = (i: IcmsStRetido): Out => {
224
+ const o = (k: keyof IcmsStRetido, f: DecimalFormat): string | undefined =>
225
+ ctx.so(ctx.opt(i[k], `${path}.${k}`, f), f);
226
+ const vFCPSTRet = ctx.opt(i.vFCPSTRet, `${path}.vFCPSTRet`, M);
227
+ if (vFCPSTRet !== undefined) t.vFCPSTRet = t.vFCPSTRet.plus(vFCPSTRet);
228
+ return {
229
+ vBCSTRet: o('vBCSTRet', M),
230
+ pST: o('pST', PO),
231
+ vICMSSubstituto: o('vICMSSubstituto', M),
232
+ vICMSSTRet: o('vICMSSTRet', M),
233
+ vBCFCPSTRet: o('vBCFCPSTRet', M),
234
+ pFCPSTRet: o('pFCPSTRet', PO),
235
+ vFCPSTRet: ctx.so(vFCPSTRet, M),
236
+ pRedBCEfet: o('pRedBCEfet', PO),
237
+ vBCEfet: o('vBCEfet', M),
238
+ pICMSEfet: o('pICMSEfet', PO),
239
+ vICMSEfet: o('vICMSEfet', M),
240
+ };
241
+ };
242
+
243
+ /** Diferimento (CST 51 e 90): vICMSOp = vBC × pICMS; vICMSDif = vICMSOp × pDif; vICMS = vICMSOp - vICMSDif (RV N16a, N16c). */
244
+ const diferimento = (
245
+ i: {
246
+ modBC?: string;
247
+ vBC?: DecimalInput;
248
+ pRedBC?: DecimalInput;
249
+ cBenefRBC?: string;
250
+ pICMS?: DecimalInput;
251
+ vICMSOp?: DecimalInput;
252
+ pDif?: DecimalInput;
253
+ vICMSDif?: DecimalInput;
254
+ vICMS?: DecimalInput;
255
+ pFCP?: DecimalInput;
256
+ vBCFCP?: DecimalInput;
257
+ vFCP?: DecimalInput;
258
+ pFCPDif?: DecimalInput;
259
+ vFCPDif?: DecimalInput;
260
+ vFCPEfet?: DecimalInput;
261
+ },
262
+ redFormat: DecimalFormat,
263
+ triade: boolean,
264
+ ): Out => {
265
+ const pRedBC = ctx.opt(i.pRedBC, `${path}.pRedBC`, redFormat);
266
+ const pICMS = ctx.opt(i.pICMS, `${path}.pICMS`, P);
267
+ const out: Out = {};
268
+ let vBC: Decimal | undefined;
269
+ if (pICMS !== undefined || i.vBC !== undefined) {
270
+ const reduzida =
271
+ pRedBC === undefined ? base.vOp : base.vOp.times(Decimal.HUNDRED.minus(pRedBC)).dividedBy(100, 10, 'HALF_EVEN');
272
+ vBC = ctx.base(i.vBC, reduzida, `${path}.vBC`, M, 'icms');
273
+ out.modBC = i.modBC ?? '3';
274
+ out.vBC = S(vBC);
275
+ }
276
+ out.pRedBC = ctx.so(pRedBC, redFormat);
277
+ out.cBenefRBC = i.cBenefRBC;
278
+ if (pICMS !== undefined && vBC !== undefined) {
279
+ out.pICMS = ctx.s(pICMS, P);
280
+ const vICMSOp = ctx.calc(i.vICMSOp, vBC.percent(pICMS), `${path}.vICMSOp`, M, 'icms');
281
+ const pDif = ctx.opt(i.pDif, `${path}.pDif`, P);
282
+ const vICMSDif = ctx.calc(i.vICMSDif, vICMSOp.percent(pDif ?? Decimal.ZERO), `${path}.vICMSDif`, M, 'icms');
283
+ const vICMS = ctx.calc(i.vICMS, vICMSOp.minus(vICMSDif), `${path}.vICMS`, M, 'icms');
284
+ const temDif = pDif !== undefined || i.vICMSDif !== undefined || i.vICMSOp !== undefined;
285
+ if (triade) {
286
+ // No CST 90, vICMSOp, pDif e vICMSDif são uma sequência opcional do XSD: vão os três ou nenhum.
287
+ if (temDif)
288
+ Object.assign(out, { vICMSOp: S(vICMSOp), pDif: ctx.s(pDif ?? Decimal.ZERO, P), vICMSDif: S(vICMSDif) });
289
+ } else {
290
+ Object.assign(out, {
291
+ vICMSOp: S(vICMSOp),
292
+ pDif: ctx.so(pDif, P),
293
+ vICMSDif: pDif === undefined && i.vICMSDif === undefined ? undefined : S(vICMSDif),
294
+ });
295
+ }
296
+ Object.assign(out, {
297
+ vICMS: S(vICMS),
298
+ });
299
+ t.vBC = t.vBC.plus(vBC);
300
+ t.vICMS = t.vICMS.plus(vICMS);
301
+ } else {
302
+ const informados = [i.vBC, i.vICMS, i.vICMSOp, i.pDif, i.vICMSDif, i.pRedBC].some((x) => x !== undefined);
303
+ if (triade && informados) {
304
+ // No CST 90 o ICMS próprio é uma sequência do XSD (modBC, vBC, pICMS, vICMS e a tríade do diferimento): sem
305
+ // pICMS nada dela pode ir, e o que veio não pode sumir em silêncio.
306
+ ctx.issues.add(
307
+ `${path}.pICMS`,
308
+ 'campo_obrigatorio',
309
+ 'o ICMS próprio do CST 90 (vBC, vICMS, diferimento) exige pICMS',
310
+ );
311
+ }
312
+ if (!triade) {
313
+ // CST 51 sem alíquota: cada campo do XSD é opcional e vai como veio (há diferimento informado só com pDif).
314
+ Object.assign(out, {
315
+ modBC: out.modBC ?? i.modBC,
316
+ vICMSOp: ctx.so(ctx.opt(i.vICMSOp, `${path}.vICMSOp`, M), M),
317
+ pDif: ctx.so(ctx.opt(i.pDif, `${path}.pDif`, P), P),
318
+ vICMSDif: ctx.so(ctx.opt(i.vICMSDif, `${path}.vICMSDif`, M), M),
319
+ });
320
+ }
321
+ const vICMS = ctx.opt(i.vICMS, `${path}.vICMS`, M);
322
+ if (vICMS !== undefined) {
323
+ out.vICMS = S(vICMS);
324
+ t.vICMS = t.vICMS.plus(vICMS);
325
+ }
326
+ if (vBC !== undefined) t.vBC = t.vBC.plus(vBC);
327
+ }
328
+ const pFCP = ctx.opt(i.pFCP, `${path}.pFCP`, PO);
329
+ const temFcp = i.pFCP !== undefined || i.vFCP !== undefined;
330
+ for (const k of ['vBCFCP', 'pFCPDif', 'vFCPDif', 'vFCPEfet'] as const) orfao(i[k], temFcp, k, 'pFCP');
331
+ orfao(i.vFCPEfet, !temFcp || i.pFCPDif !== undefined || i.vFCPDif !== undefined, 'vFCPEfet', 'pFCPDif');
332
+ if (pFCP !== undefined || i.vFCP !== undefined) {
333
+ const vBCFCP = ctx.base(i.vBCFCP, vBC ?? Decimal.ZERO, `${path}.vBCFCP`, M, 'icms');
334
+ const vFCP = ctx.calc(i.vFCP, vBCFCP.percent(pFCP ?? Decimal.ZERO), `${path}.vFCP`, M, 'icms');
335
+ const pFCPDif = ctx.opt(i.pFCPDif, `${path}.pFCPDif`, PO);
336
+ const vFCPDif = ctx.calc(i.vFCPDif, vFCP.percent(pFCPDif ?? Decimal.ZERO), `${path}.vFCPDif`, M, 'icms');
337
+ const vFCPEfet = ctx.calc(i.vFCPEfet, vFCP.minus(vFCPDif), `${path}.vFCPEfet`, M, 'icms');
338
+ // W04b-10 (rejeição 861): o total soma o vFCP declarado no item (N17c), não o efetivo depois do diferimento.
339
+ t.vFCP = t.vFCP.plus(vFCP);
340
+ const temDif = pFCPDif !== undefined || i.vFCPDif !== undefined;
341
+ Object.assign(out, {
342
+ vBCFCP: S(vBCFCP),
343
+ pFCP: ctx.so(pFCP, PO),
344
+ vFCP: S(vFCP),
345
+ pFCPDif: ctx.so(pFCPDif, PO),
346
+ vFCPDif: temDif ? S(vFCPDif) : undefined,
347
+ vFCPEfet: temDif ? S(vFCPEfet) : undefined,
348
+ });
349
+ }
350
+ return out;
351
+ };
352
+
353
+ const q = (v: DecimalInput | undefined, k: string): Decimal | undefined => ctx.opt(v, `${path}.${k}`, D1104V);
354
+ /**
355
+ * Valor monofásico (NT 2023.001): padrão quantidade × ad rem em 2 casas. O informado prevalece sem conferência: há
356
+ * notas autorizadas cujo valor não é o produto exato (corpus local, `test/golden/golden.ts`).
357
+ */
358
+ const mono = (
359
+ qtd: Decimal | undefined,
360
+ adRem: Decimal | undefined,
361
+ given: DecimalInput | undefined,
362
+ k: string,
363
+ ): Decimal => ctx.base(given, (qtd ?? Decimal.ZERO).times(adRem ?? Decimal.ZERO), `${path}.${k}`, M, 'icms');
364
+
365
+ let grupo: Record<string, Out>;
366
+ if ('CSOSN' in input) {
367
+ const orig = input.orig;
368
+ switch (input.CSOSN) {
369
+ case '101': {
370
+ const pCredSN = ctx.req(input.pCredSN, `${path}.pCredSN`, P);
371
+ const v = ctx.calc(input.vCredICMSSN, base.vOp.percent(pCredSN), `${path}.vCredICMSSN`, M, 'icms');
372
+ grupo = { ICMSSN101: { orig, CSOSN: '101', pCredSN: ctx.s(pCredSN, P), vCredICMSSN: S(v) } };
373
+ break;
374
+ }
375
+ case '102':
376
+ case '103':
377
+ case '300':
378
+ case '400':
379
+ grupo = { ICMSSN102: { orig, CSOSN: input.CSOSN } };
380
+ break;
381
+ case '201': {
382
+ const stOut = st(input.st, Decimal.ZERO, Decimal.ZERO);
383
+ const pCredSN = ctx.req(input.pCredSN, `${path}.pCredSN`, P);
384
+ const v = ctx.calc(input.vCredICMSSN, base.vOp.percent(pCredSN), `${path}.vCredICMSSN`, M, 'icms');
385
+ grupo = { ICMSSN201: { orig, CSOSN: '201', ...stOut, pCredSN: ctx.s(pCredSN, P), vCredICMSSN: S(v) } };
386
+ break;
387
+ }
388
+ case '202':
389
+ case '203':
390
+ grupo = { ICMSSN202: { orig, CSOSN: input.CSOSN, ...st(input.st, Decimal.ZERO, Decimal.ZERO) } };
391
+ break;
392
+ case '500':
393
+ grupo = { ICMSSN500: { orig, CSOSN: '500', ...retido(input) } };
394
+ break;
395
+ case '900': {
396
+ const pRedBC = ctx.opt(input.pRedBC, `${path}.pRedBC`, PO);
397
+ const p = proprio(input, pRedBC, false);
398
+ const out: Out = { orig, CSOSN: '900' };
399
+ if (p)
400
+ Object.assign(out, {
401
+ modBC: p.out.modBC,
402
+ vBC: p.out.vBC,
403
+ pRedBC: ctx.so(pRedBC, PO),
404
+ pICMS: p.out.pICMS,
405
+ vICMS: p.out.vICMS,
406
+ });
407
+ // Com ICMS próprio destacado, o ST abate o próprio, como nos grupos do regime normal (MOC N23).
408
+ if (input.st) Object.assign(out, st(input.st, p?.vICMS ?? Decimal.ZERO, Decimal.ZERO));
409
+ const pCredSN = ctx.opt(input.pCredSN, `${path}.pCredSN`, P);
410
+ orfao(input.vCredICMSSN, input.pCredSN !== undefined, 'vCredICMSSN', 'pCredSN');
411
+ if (pCredSN !== undefined) {
412
+ const v = ctx.calc(input.vCredICMSSN, base.vOp.percent(pCredSN), `${path}.vCredICMSSN`, M, 'icms');
413
+ Object.assign(out, { pCredSN: ctx.s(pCredSN, P), vCredICMSSN: S(v) });
414
+ }
415
+ grupo = { ICMSSN900: out };
416
+ break;
417
+ }
418
+ }
419
+ } else if (input.grupo === 'Part') {
420
+ const pRedBC = ctx.opt(input.pRedBC, `${path}.pRedBC`, PO);
421
+ const p = proprio(input, pRedBC, true) as { out: Out; vICMS: Decimal };
422
+ const pBCOp = ctx.req(input.pBCOp, `${path}.pBCOp`, PO);
423
+ grupo = {
424
+ ICMSPart: {
425
+ orig: input.orig,
426
+ CST: input.CST,
427
+ modBC: input.modBC,
428
+ vBC: p.out.vBC,
429
+ pRedBC: ctx.so(pRedBC, PO),
430
+ pICMS: p.out.pICMS,
431
+ vICMS: p.out.vICMS,
432
+ ...st(input.st, p.vICMS, Decimal.ZERO),
433
+ pBCOp: ctx.s(pBCOp, PO),
434
+ UFST: input.UFST,
435
+ ...deson(input.desoneracao),
436
+ },
437
+ };
438
+ } else if (input.grupo === 'ST') {
439
+ grupo = {
440
+ ICMSST: {
441
+ orig: input.orig,
442
+ CST: input.CST,
443
+ ...retido(input),
444
+ vBCSTRet: S(ctx.req(input.vBCSTRet, `${path}.vBCSTRet`, M)),
445
+ vICMSSTRet: S(ctx.req(input.vICMSSTRet, `${path}.vICMSSTRet`, M)),
446
+ vBCSTDest: S(ctx.req(input.vBCSTDest, `${path}.vBCSTDest`, M)),
447
+ vICMSSTDest: S(ctx.req(input.vICMSSTDest, `${path}.vICMSSTDest`, M)),
448
+ },
449
+ };
450
+ } else {
451
+ const orig = input.orig;
452
+ switch (input.CST) {
453
+ case '00': {
454
+ const p = proprio(input, undefined, true) as { out: Out; vBC: Decimal };
455
+ grupo = { ICMS00: { orig, CST: '00', ...p.out, ...fcp(input, p.vBC, false) } };
456
+ break;
457
+ }
458
+ case '02': {
459
+ const qBCMono = q(input.qBCMono, 'qBCMono');
460
+ const adRem = ctx.req(input.adRemICMS, `${path}.adRemICMS`, P);
461
+ const v = mono(qBCMono, adRem, input.vICMSMono, 'vICMSMono');
462
+ t.mono = true;
463
+ t.qBCMono = t.qBCMono.plus(qBCMono ?? Decimal.ZERO);
464
+ t.vICMSMono = t.vICMSMono.plus(v);
465
+ grupo = {
466
+ ICMS02: {
467
+ orig,
468
+ CST: '02',
469
+ qBCMono: ctx.so(qBCMono, D1104V),
470
+ adRemICMS: ctx.s(adRem, P),
471
+ vICMSMono: S(v),
472
+ },
473
+ };
474
+ break;
475
+ }
476
+ case '10': {
477
+ const p = proprio(input, undefined, true) as { out: Out; vBC: Decimal; vICMS: Decimal };
478
+ const f = fcp(input, p.vBC, true);
479
+ const vFCP = f.vFCP === undefined ? Decimal.ZERO : Decimal.of(f.vFCP);
480
+ grupo = {
481
+ ICMS10: { orig, CST: '10', ...p.out, ...f, ...st(input.st, p.vICMS, vFCP), ...desonSt(input.desoneracaoSt) },
482
+ };
483
+ break;
484
+ }
485
+ case '15': {
486
+ const qBCMono = q(input.qBCMono, 'qBCMono');
487
+ const adRem = ctx.req(input.adRemICMS, `${path}.adRemICMS`, P);
488
+ const v = mono(qBCMono, adRem, input.vICMSMono, 'vICMSMono');
489
+ const qReten = q(input.qBCMonoReten, 'qBCMonoReten');
490
+ const adRemReten = ctx.req(input.adRemICMSReten, `${path}.adRemICMSReten`, P);
491
+ if (input.pRedAdRem !== undefined) {
492
+ // Com redução da ad rem (pRedAdRem, motRedAdRem) a conta de cada valor não está nas fontes que este pacote
493
+ // cita (NT 2023.001 não versionada aqui): os valores vêm informados em vez de derivados sem a redução.
494
+ if (input.vICMSMono === undefined)
495
+ ctx.issues.add(`${path}.vICMSMono`, 'campo_obrigatorio', 'com pRedAdRem, informe vICMSMono');
496
+ if (input.vICMSMonoReten === undefined) {
497
+ ctx.issues.add(`${path}.vICMSMonoReten`, 'campo_obrigatorio', 'com pRedAdRem, informe vICMSMonoReten');
498
+ }
499
+ }
500
+ const vReten = mono(qReten, adRemReten, input.vICMSMonoReten, 'vICMSMonoReten');
501
+ t.mono = true;
502
+ t.qBCMono = t.qBCMono.plus(qBCMono ?? Decimal.ZERO);
503
+ t.vICMSMono = t.vICMSMono.plus(v);
504
+ t.qBCMonoReten = t.qBCMonoReten.plus(qReten ?? Decimal.ZERO);
505
+ t.vICMSMonoReten = t.vICMSMonoReten.plus(vReten);
506
+ grupo = {
507
+ ICMS15: {
508
+ orig,
509
+ CST: '15',
510
+ qBCMono: ctx.so(qBCMono, D1104V),
511
+ adRemICMS: ctx.s(adRem, P),
512
+ vICMSMono: S(v),
513
+ qBCMonoReten: ctx.so(qReten, D1104V),
514
+ adRemICMSReten: ctx.s(adRemReten, P),
515
+ vICMSMonoReten: S(vReten),
516
+ pRedAdRem: ctx.so(ctx.opt(input.pRedAdRem, `${path}.pRedAdRem`, D0302A04), D0302A04),
517
+ motRedAdRem: input.motRedAdRem,
518
+ },
519
+ };
520
+ break;
521
+ }
522
+ case '20': {
523
+ const pRedBC = ctx.req(input.pRedBC, `${path}.pRedBC`, P);
524
+ const p = proprio(input, pRedBC, true) as { out: Out; vBC: Decimal };
525
+ grupo = {
526
+ ICMS20: {
527
+ orig,
528
+ CST: '20',
529
+ modBC: p.out.modBC,
530
+ pRedBC: ctx.s(pRedBC, P),
531
+ vBC: p.out.vBC,
532
+ pICMS: p.out.pICMS,
533
+ vICMS: p.out.vICMS,
534
+ ...fcp(input, p.vBC, true),
535
+ ...deson(input.desoneracao),
536
+ },
537
+ };
538
+ break;
539
+ }
540
+ case '30':
541
+ grupo = {
542
+ ICMS30: { orig, CST: '30', ...st(input.st, Decimal.ZERO, Decimal.ZERO), ...deson(input.desoneracao) },
543
+ };
544
+ break;
545
+ case '40':
546
+ case '41':
547
+ case '50':
548
+ grupo = { ICMS40: { orig, CST: input.CST, ...deson(input.desoneracao) } };
549
+ break;
550
+ case '51':
551
+ grupo = { ICMS51: { orig, CST: '51', ...diferimento(input, P, false) } };
552
+ break;
553
+ case '53': {
554
+ const qBCMono = q(input.qBCMono, 'qBCMono');
555
+ const adRem = ctx.opt(input.adRemICMS, `${path}.adRemICMS`, P);
556
+ const vOp = mono(qBCMono, adRem, input.vICMSMonoOp, 'vICMSMonoOp');
557
+ const pDif = ctx.opt(input.pDif, `${path}.pDif`, P);
558
+ const vDif = ctx.calc(input.vICMSMonoDif, vOp.percent(pDif ?? Decimal.ZERO), `${path}.vICMSMonoDif`, M, 'icms');
559
+ const v = ctx.calc(input.vICMSMono, vOp.minus(vDif), `${path}.vICMSMono`, M, 'icms');
560
+ const qDif = q(input.qBCMonoDif, 'qBCMonoDif');
561
+ const adRemDif = ctx.opt(input.adRemICMSDif, `${path}.adRemICMSDif`, P);
562
+ t.mono = true;
563
+ t.qBCMono = t.qBCMono.plus(qBCMono ?? Decimal.ZERO);
564
+ t.vICMSMono = t.vICMSMono.plus(v);
565
+ grupo = {
566
+ ICMS53: {
567
+ orig,
568
+ CST: '53',
569
+ qBCMono: ctx.so(qBCMono, D1104V),
570
+ adRemICMS: ctx.so(adRem, P),
571
+ vICMSMonoOp: adRem === undefined && input.vICMSMonoOp === undefined ? undefined : S(vOp),
572
+ pDif: ctx.so(pDif, P),
573
+ vICMSMonoDif: pDif === undefined && input.vICMSMonoDif === undefined ? undefined : S(vDif),
574
+ vICMSMono: adRem === undefined && input.vICMSMono === undefined ? undefined : S(v),
575
+ qBCMonoDif: ctx.so(qDif, D1104V),
576
+ adRemICMSDif: ctx.so(adRemDif, P),
577
+ },
578
+ };
579
+ break;
580
+ }
581
+ case '60':
582
+ grupo = { ICMS60: { orig, CST: '60', ...retido(input) } };
583
+ break;
584
+ case '61': {
585
+ const qRet = q(input.qBCMonoRet, 'qBCMonoRet');
586
+ const adRem = ctx.req(input.adRemICMSRet, `${path}.adRemICMSRet`, P);
587
+ const v = mono(qRet, adRem, input.vICMSMonoRet, 'vICMSMonoRet');
588
+ t.mono = true;
589
+ t.qBCMonoRet = t.qBCMonoRet.plus(qRet ?? Decimal.ZERO);
590
+ t.vICMSMonoRet = t.vICMSMonoRet.plus(v);
591
+ grupo = {
592
+ ICMS61: {
593
+ orig,
594
+ CST: '61',
595
+ qBCMonoRet: ctx.so(qRet, D1104V),
596
+ adRemICMSRet: ctx.s(adRem, P),
597
+ vICMSMonoRet: S(v),
598
+ },
599
+ };
600
+ break;
601
+ }
602
+ case '70': {
603
+ const pRedBC = ctx.req(input.pRedBC, `${path}.pRedBC`, P);
604
+ const p = proprio(input, pRedBC, true) as { out: Out; vBC: Decimal; vICMS: Decimal };
605
+ const f = fcp(input, p.vBC, true);
606
+ const vFCP = f.vFCP === undefined ? Decimal.ZERO : Decimal.of(f.vFCP);
607
+ grupo = {
608
+ ICMS70: {
609
+ orig,
610
+ CST: '70',
611
+ modBC: p.out.modBC,
612
+ pRedBC: ctx.s(pRedBC, P),
613
+ vBC: p.out.vBC,
614
+ pICMS: p.out.pICMS,
615
+ vICMS: p.out.vICMS,
616
+ ...f,
617
+ ...st(input.st, p.vICMS, vFCP),
618
+ ...deson(input.desoneracao),
619
+ ...desonSt(input.desoneracaoSt),
620
+ },
621
+ };
622
+ break;
623
+ }
624
+ case '90': {
625
+ const d = diferimento(input, PO, true);
626
+ const vICMS = d.vICMS === undefined ? Decimal.ZERO : Decimal.of(d.vICMS);
627
+ // RV N23d-10: vFCPST = vBCFCPST × pFCPST - vFCP (o vFCP declarado, N17c).
628
+ const vFCP = d.vFCP;
629
+ grupo = {
630
+ ICMS90: {
631
+ orig,
632
+ CST: '90',
633
+ ...d,
634
+ ...(input.st ? st(input.st, vICMS, vFCP === undefined ? Decimal.ZERO : Decimal.of(vFCP)) : {}),
635
+ ...deson(input.desoneracao),
636
+ ...desonSt(input.desoneracaoSt),
637
+ },
638
+ };
639
+ break;
640
+ }
641
+ }
642
+ }
643
+ const [name, body] = Object.entries(grupo)[0] as [string, Out];
644
+ return { grupo: { [name]: clean(body) } as unknown as TNFe_infNFe_det_imposto_ICMS, totais: t };
645
+ }