@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,44 @@
1
+ {
2
+ "descricao": "Web services SOAP 1.2 da NF-e 4.00: namespace do WSDL e operação (a action do Content-Type é <namespace>/<operação>). Na NF-e 4.00 não existe cabeçalho nfeCabecMsg; a mensagem vai em nfeDadosMsg no namespace do WSDL, e a resposta volta em nfeResultMsg. A Distribuição DF-e usa o envelope do WSDL próprio, com nfeDadosMsg dentro de nfeDistDFeInteresse.",
3
+ "fonte": "MOC 7.0, Visão Geral, item 3 (padrão de comunicação e WSDL dos serviços) e WSDLs do portal da NF-e; NT 2014.002 (Distribuição DF-e)",
4
+ "atualizadoEm": "2026-09-28",
5
+ "servicos": {
6
+ "NfeStatusServico": {
7
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeStatusServico4",
8
+ "operacao": "nfeStatusServicoNF"
9
+ },
10
+ "NFeAutorizacao": {
11
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeAutorizacao4",
12
+ "operacao": "nfeAutorizacaoLote"
13
+ },
14
+ "NFeRetAutorizacao": {
15
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeRetAutorizacao4",
16
+ "operacao": "nfeRetAutorizacaoLote"
17
+ },
18
+ "NfeConsultaProtocolo": {
19
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4",
20
+ "operacao": "nfeConsultaNF"
21
+ },
22
+ "NfeInutilizacao": {
23
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeInutilizacao4",
24
+ "operacao": "nfeInutilizacaoNF"
25
+ },
26
+ "RecepcaoEvento": {
27
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeRecepcaoEvento4",
28
+ "operacao": "nfeRecepcaoEvento"
29
+ },
30
+ "NfeConsultaCadastro": {
31
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/CadConsultaCadastro4",
32
+ "operacao": "consultaCadastro",
33
+ "envelopeNoAutorizador": {
34
+ "MT": "operacao"
35
+ },
36
+ "fonteEnvelope": "Resposta da SEFAZ-MT em homologação em 28/09/2026: com a mensagem só em nfeDadosMsg, o MT responde 215 (falha no schema) e devolve o retorno dentro de consultaCadastroResult; com nfeDadosMsg dentro de consultaCadastro (o elemento da operação do WSDL), responde a consulta (259)."
37
+ },
38
+ "NFeDistribuicaoDFe": {
39
+ "namespace": "http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe",
40
+ "operacao": "nfeDistDFeInteresse",
41
+ "envelope": "distDFeInteresse"
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "descricao": "Onde a inscrição na Suframa do destinatário (ISUF) é aceita na NF-e: UFs inteiras e, no Amapá, só os municípios listados. Fora delas, rejeição 251.",
3
+ "atualizadoEm": "2026-09-28",
4
+ "fonte": "MOC 7.0 Anexo I, RV E18-30 (rejeição 251, modelo 55, obrigatória)",
5
+ "ufs": ["AC", "AM", "RO", "RR"],
6
+ "municipios": { "AP": ["1600303", "1600600"] }
7
+ }
package/src/decimal.ts ADDED
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Decimal exato para os valores da NF-e. Nada de `number` nas contas: um valor é `coef × 10^-scale` com `coef` em
3
+ * `bigint`, então soma, subtração e multiplicação são exatas e só o arredondamento, feito de propósito e com o modo
4
+ * escolhido, descarta dígitos.
5
+ *
6
+ * Os modos são os que os leiautes usam:
7
+ * - `HALF_EVEN` (arredondamento bancário, NBR 5891): o que a Calculadora da RFB aplica ao IBS e à CBS (ADR 0007).
8
+ * - `HALF_UP` (metade para longe do zero): o arredondamento comercial usual nos demais tributos. O MOC 7.0 Anexo I,
9
+ * nota (*4) das regras de valor, só exige duas casas e aceita tolerância de R$ 0,01, sem fixar o modo.
10
+ * - `DOWN` (trunca em direção ao zero), para quem precisa reproduzir um sistema legado.
11
+ *
12
+ * Qual modo vale para qual campo é dado (`data/arredondamento.json`), não regra espalhada no código.
13
+ */
14
+
15
+ import { ErroDeConfiguracao } from '@sinete/core';
16
+
17
+ export type RoundingMode = 'HALF_EVEN' | 'HALF_UP' | 'DOWN';
18
+
19
+ /** O que as APIs de entrada aceitam como número. Prefira `string` (`'12.34'`): `number` perde dígitos acima de 15 algarismos. */
20
+ export type DecimalInput = string | number | bigint | Decimal;
21
+
22
+ const DECIMAL_TEXT = /^([+-])?(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$|^([+-])?\.(\d+)(?:[eE]([+-]?\d+))?$/;
23
+ const MAX_SCALE = 64;
24
+
25
+ function pow10(n: number): bigint {
26
+ return 10n ** BigInt(n);
27
+ }
28
+
29
+ /** Valor decimal imutável: `coef × 10^-scale`. */
30
+ export class Decimal {
31
+ /** Coeficiente inteiro (com sinal). */
32
+ readonly coef: bigint;
33
+ /** Casas decimais do coeficiente (0 ou mais). */
34
+ readonly scale: number;
35
+
36
+ private constructor(coef: bigint, scale: number) {
37
+ this.coef = coef;
38
+ this.scale = scale;
39
+ }
40
+
41
+ static readonly ZERO: Decimal = new Decimal(0n, 0);
42
+ static readonly ONE: Decimal = new Decimal(1n, 0);
43
+ static readonly HUNDRED: Decimal = new Decimal(100n, 0);
44
+
45
+ /** Constrói a partir do coeficiente e da escala (`fromParts(1234n, 2)` = 12.34). */
46
+ static fromParts(coef: bigint, scale: number): Decimal {
47
+ if (!Number.isInteger(scale) || scale < 0 || scale > MAX_SCALE)
48
+ throw new ErroDeConfiguracao(`escala inválida: ${scale}`);
49
+ return new Decimal(coef, scale);
50
+ }
51
+
52
+ /**
53
+ * Converte a entrada. Aceita texto com ponto decimal e expoente opcional (`'12.34'`, `'1e-3'`), `number` finito e
54
+ * `bigint`. Vírgula, separador de milhar e espaço são recusados: o texto é a forma do XML, não a da tela.
55
+ */
56
+ static of(input: DecimalInput): Decimal {
57
+ const d = Decimal.tryOf(input);
58
+ if (d === undefined) throw new ErroDeConfiguracao(`número decimal inválido: ${JSON.stringify(String(input))}`);
59
+ return d;
60
+ }
61
+
62
+ /** Como `of`, mas devolve `undefined` em vez de lançar. */
63
+ static tryOf(input: DecimalInput): Decimal | undefined {
64
+ if (input instanceof Decimal) return input;
65
+ if (typeof input === 'bigint') return new Decimal(input, 0);
66
+ if (typeof input === 'number') {
67
+ if (!Number.isFinite(input)) return undefined;
68
+ // String(n) é a representação mais curta que volta ao mesmo double (ECMA-262 Number::toString).
69
+ return Decimal.tryOf(String(input));
70
+ }
71
+ if (typeof input !== 'string') return undefined;
72
+ const m = DECIMAL_TEXT.exec(input);
73
+ if (!m) return undefined;
74
+ const sign = (m[1] ?? m[5]) === '-' ? -1n : 1n;
75
+ const intPart = m[2] ?? '';
76
+ const frac = m[3] ?? m[6] ?? '';
77
+ const exp = Number(m[4] ?? m[7] ?? '0');
78
+ if (!Number.isSafeInteger(exp) || Math.abs(exp) > MAX_SCALE) return undefined;
79
+ let coef = BigInt(`${intPart}${frac}` || '0') * sign;
80
+ let scale = frac.length - exp;
81
+ if (scale < 0) {
82
+ coef *= pow10(-scale);
83
+ scale = 0;
84
+ }
85
+ if (scale > MAX_SCALE) return undefined;
86
+ return new Decimal(coef, scale);
87
+ }
88
+
89
+ private aligned(other: Decimal): [bigint, bigint, number] {
90
+ if (this.scale === other.scale) return [this.coef, other.coef, this.scale];
91
+ if (this.scale > other.scale) return [this.coef, other.coef * pow10(this.scale - other.scale), this.scale];
92
+ return [this.coef * pow10(other.scale - this.scale), other.coef, other.scale];
93
+ }
94
+
95
+ plus(other: DecimalInput): Decimal {
96
+ const [a, b, s] = this.aligned(Decimal.of(other));
97
+ return new Decimal(a + b, s);
98
+ }
99
+
100
+ minus(other: DecimalInput): Decimal {
101
+ const [a, b, s] = this.aligned(Decimal.of(other));
102
+ return new Decimal(a - b, s);
103
+ }
104
+
105
+ times(other: DecimalInput): Decimal {
106
+ const o = Decimal.of(other);
107
+ const scale = this.scale + o.scale;
108
+ if (scale > MAX_SCALE) {
109
+ // Produto de muitas casas: arredonda (HALF_EVEN) para caber, com folga muito acima de qualquer campo do leiaute.
110
+ return new Decimal(this.coef * o.coef, scale).round(MAX_SCALE, 'HALF_EVEN');
111
+ }
112
+ return new Decimal(this.coef * o.coef, scale);
113
+ }
114
+
115
+ /** Divisão com o resultado arredondado em `scale` casas pelo modo dado. */
116
+ dividedBy(other: DecimalInput, scale: number, mode: RoundingMode): Decimal {
117
+ const o = Decimal.of(other);
118
+ if (o.coef === 0n) throw new ErroDeConfiguracao('divisão por zero');
119
+ // (a / 10^sa) / (b / 10^sb) = a * 10^(sb + scale + 1 - sa) / b, com uma casa de guarda para o arredondamento.
120
+ const shift = o.scale + scale + 1 - this.scale;
121
+ const num = shift >= 0 ? this.coef * pow10(shift) : this.coef;
122
+ const den = shift >= 0 ? o.coef : o.coef * pow10(-shift);
123
+ const q = num / den;
124
+ const exact = q * den === num;
125
+ return roundCoef(q, scale + 1, scale, mode, !exact);
126
+ }
127
+
128
+ /** Percentual: `this × rate / 100`, sem arredondar. */
129
+ percent(rate: DecimalInput): Decimal {
130
+ const product = this.times(rate);
131
+ return new Decimal(product.coef, product.scale + 2);
132
+ }
133
+
134
+ negate(): Decimal {
135
+ return new Decimal(-this.coef, this.scale);
136
+ }
137
+
138
+ abs(): Decimal {
139
+ return this.coef < 0n ? this.negate() : this;
140
+ }
141
+
142
+ /** Arredonda para `scale` casas. Com `scale` maior que a atual, só completa com zeros. */
143
+ round(scale: number, mode: RoundingMode): Decimal {
144
+ if (!Number.isInteger(scale) || scale < 0) throw new ErroDeConfiguracao(`casas decimais inválidas: ${scale}`);
145
+ if (scale >= this.scale) return new Decimal(this.coef * pow10(scale - this.scale), scale);
146
+ return roundCoef(this.coef, this.scale, scale, mode, false);
147
+ }
148
+
149
+ compare(other: DecimalInput): -1 | 0 | 1 {
150
+ const [a, b] = this.aligned(Decimal.of(other));
151
+ return a < b ? -1 : a > b ? 1 : 0;
152
+ }
153
+
154
+ eq(other: DecimalInput): boolean {
155
+ return this.compare(other) === 0;
156
+ }
157
+
158
+ lt(other: DecimalInput): boolean {
159
+ return this.compare(other) < 0;
160
+ }
161
+
162
+ gt(other: DecimalInput): boolean {
163
+ return this.compare(other) > 0;
164
+ }
165
+
166
+ isZero(): boolean {
167
+ return this.coef === 0n;
168
+ }
169
+
170
+ isNegative(): boolean {
171
+ return this.coef < 0n;
172
+ }
173
+
174
+ /** Quantas casas decimais o valor precisa (sem os zeros à direita). */
175
+ significantScale(): number {
176
+ if (this.coef === 0n) return 0;
177
+ let c = this.coef;
178
+ let s = this.scale;
179
+ while (s > 0 && c % 10n === 0n) {
180
+ c /= 10n;
181
+ s--;
182
+ }
183
+ return s;
184
+ }
185
+
186
+ /** Texto com exatamente `scale` casas (arredonda pelo modo dado quando precisa). */
187
+ toFixed(scale: number, mode: RoundingMode = 'HALF_UP'): string {
188
+ const r = this.round(scale, mode);
189
+ const neg = r.coef < 0n;
190
+ const digits = (neg ? -r.coef : r.coef).toString().padStart(scale + 1, '0');
191
+ const int = digits.slice(0, digits.length - scale);
192
+ const frac = digits.slice(digits.length - scale);
193
+ return `${neg ? '-' : ''}${int}${scale > 0 ? `.${frac}` : ''}`;
194
+ }
195
+
196
+ /** Forma mínima, sem zeros à direita (`'12.3'`, `'0'`). */
197
+ toString(): string {
198
+ return this.toFixed(this.significantScale());
199
+ }
200
+
201
+ toJSON(): string {
202
+ return this.toString();
203
+ }
204
+ }
205
+
206
+ /** Reduz `coef × 10^-from` para `to` casas (`to < from`). `sticky` diz se há resto não nulo além dos dígitos dados. */
207
+ function roundCoef(coef: bigint, from: number, to: number, mode: RoundingMode, sticky: boolean): Decimal {
208
+ const div = pow10(from - to);
209
+ const neg = coef < 0n;
210
+ const abs = neg ? -coef : coef;
211
+ let q = abs / div;
212
+ const r = abs % div;
213
+ if (mode !== 'DOWN' && (r !== 0n || sticky)) {
214
+ const twice = r * 2n;
215
+ const above = twice > div || (twice === div && sticky);
216
+ const tie = twice === div && !sticky;
217
+ if (above || (tie && (mode === 'HALF_UP' || (mode === 'HALF_EVEN' && q % 2n === 1n)))) q += 1n;
218
+ }
219
+ return Decimal.fromParts(neg ? -q : q, to);
220
+ }
221
+
222
+ /** Atalho para `Decimal.of`. */
223
+ export function dec(valor: DecimalInput): Decimal {
224
+ return Decimal.of(valor);
225
+ }
226
+
227
+ /** Soma uma lista (vazia = zero). */
228
+ export function sum(valores: Iterable<Decimal>): Decimal {
229
+ let acc = Decimal.ZERO;
230
+ for (const v of valores) acc = acc.plus(v);
231
+ return acc;
232
+ }
package/src/format.ts ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Formatação dos decimais na forma lexical que cada tipo do leiaute aceita (ADR 0002: o número de casas vem do
3
+ * pattern do XSD, nunca do serializer). Cada formato abaixo cita os tipos `TDec_*` que ele cobre.
4
+ */
5
+
6
+ import type { Decimal, RoundingMode } from './decimal.ts';
7
+
8
+ export interface FormatoDecimal {
9
+ /** Nome curto, para mensagens. */
10
+ readonly nome: string;
11
+ /** Casas mínimas (completa com zeros até aqui). */
12
+ readonly min: number;
13
+ /** Casas máximas aceitas pelo pattern. */
14
+ readonly max: number;
15
+ /** Casas exigidas quando a parte inteira é zero e o valor não é zero (`TDec_0803v`: `0\.[0-9]{3}`). */
16
+ readonly minimoAbaixoDeUm?: number;
17
+ /** O pattern recusa zero (`TDec_1302Opc`, `TDec_0302a04Opc`): o campo zerado deve ser omitido. */
18
+ readonly naoNulo?: boolean;
19
+ /** Maior quantidade de dígitos inteiros aceita. */
20
+ readonly digitosInteiros: number;
21
+ }
22
+
23
+ /** `TDec_1302`, `TDec1302RTC`: 13 inteiros e exatamente 2 casas. */
24
+ export const D1302: FormatoDecimal = { nome: 'TDec_1302', min: 2, max: 2, digitosInteiros: 13 };
25
+ /** `TDec_1302Opc`: como `TDec_1302`, sem zero. */
26
+ export const D1302_OPC: FormatoDecimal = { nome: 'TDec_1302Opc', min: 2, max: 2, digitosInteiros: 13, naoNulo: true };
27
+ /** `TDec_0302a04`, `TDec_0302_04RTC`, `TDec_0302a04Max100`: 3 inteiros e 2 a 4 casas. */
28
+ export const D0302A04: FormatoDecimal = { nome: 'TDec_0302a04', min: 2, max: 4, digitosInteiros: 3 };
29
+ /** `TDec_0302a04Opc`: o pattern (`0\.[0-9]{2,4}|...`) aceita zero, ao contrário de `TDec_1302Opc`. */
30
+ export const D0302A04_OPC: FormatoDecimal = { nome: 'TDec_0302a04Opc', min: 2, max: 4, digitosInteiros: 3 };
31
+ /** `TDec_0302Max100`: 2 casas exatas. */
32
+ export const D0302: FormatoDecimal = { nome: 'TDec_0302Max100', min: 2, max: 2, digitosInteiros: 3 };
33
+ /** `TDec_1104v`: 11 inteiros e 0 a 4 casas. */
34
+ export const D1104V: FormatoDecimal = { nome: 'TDec_1104v', min: 0, max: 4, digitosInteiros: 11 };
35
+ /** `TDec_1104`, `TDec1104RTC`: 11 inteiros e 4 casas. */
36
+ export const D1104: FormatoDecimal = { nome: 'TDec_1104', min: 4, max: 4, digitosInteiros: 11 };
37
+ /** `TDec_1110v`: 11 inteiros e 0 a 10 casas. */
38
+ export const D1110V: FormatoDecimal = { nome: 'TDec_1110v', min: 0, max: 10, digitosInteiros: 11 };
39
+ /** `TDec_1204v`: 12 inteiros e 0 a 4 casas. */
40
+ export const D1204V: FormatoDecimal = { nome: 'TDec_1204v', min: 0, max: 4, digitosInteiros: 12 };
41
+ /** `TDec_1204`: 12 inteiros e 4 casas quando há fração (4 fixas aqui, que o pattern aceita sempre). */
42
+ export const D1204: FormatoDecimal = { nome: 'TDec_1204', min: 4, max: 4, digitosInteiros: 12 };
43
+ /** `TDec_1203`: 12 inteiros e 3 casas. */
44
+ export const D1203: FormatoDecimal = { nome: 'TDec_1203', min: 3, max: 3, digitosInteiros: 12 };
45
+ /** `TDec_0803v`: 8 inteiros e até 3 casas; abaixo de 1, exatamente 3. */
46
+ export const D0803V: FormatoDecimal = { nome: 'TDec_0803v', min: 0, max: 3, digitosInteiros: 8, minimoAbaixoDeUm: 3 };
47
+
48
+ /** Texto do valor já arredondado no formato (arredonda em `max` casas pelo modo dado). */
49
+ export function formatarDecimal(valor: Decimal, formato: FormatoDecimal, modo: RoundingMode = 'HALF_UP'): string {
50
+ const r = valor.round(formato.max, modo);
51
+ let places = Math.max(formato.min, Math.min(formato.max, r.significantScale()));
52
+ if (formato.minimoAbaixoDeUm !== undefined && !r.isZero() && r.abs().lt(1))
53
+ places = Math.max(places, formato.minimoAbaixoDeUm);
54
+ return r.toFixed(places, modo);
55
+ }
56
+
57
+ /** Por que o valor não cabe no formato, ou `undefined` se cabe sem perder dígitos. */
58
+ export function problemaDeFormato(valor: Decimal, formato: FormatoDecimal): string | undefined {
59
+ if (valor.isNegative()) return 'valor negativo';
60
+ if (formato.naoNulo && valor.isZero()) return 'valor zero não é aceito neste campo';
61
+ if (valor.significantScale() > formato.max) return `mais de ${formato.max} casas decimais`;
62
+ const intDigits = valor.round(0, 'DOWN').abs().toString().replace(/^0$/, '').length;
63
+ if (intDigits > formato.digitosInteiros) return `mais de ${formato.digitosInteiros} dígitos inteiros`;
64
+ return undefined;
65
+ }
package/src/ibs-cbs.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `@sinete/nfe/ibs-cbs`: tudo o que quem emite NF-e precisa do IBS/CBS, sem importar `@sinete/ibs-cbs` nem
3
+ * `@sinete/ibs-cbs-dados` diretamente.
4
+ *
5
+ * Reexporta o motor inteiro (`@sinete/ibs-cbs`: alíquotas, cálculo, regras da NT 2025.002 e determinação de CST e
6
+ * cClassTrib) e o leitor do dataset (`@sinete/ibs-cbs-dados`: `carregarDataset`, `conferirDataset`, diff, tipos). O dataset
7
+ * embarcado não entra aqui, para não ir para o bundle de quem não o usa: `carregarDatasetEmbarcado()`, na raiz do
8
+ * `@sinete/nfe`, o importa sob demanda. `Dec`, `DataIso` e `Vigencia` vêm do motor (os de `Dec` e `DataIso` são os
9
+ * mesmos; a `Vigencia` dos dados, com os campos do dataset, fica acessível pelos tipos que a usam).
10
+ */
11
+
12
+ // biome-ignore lint/performance/noReExportAll: o subpath existe para reexportar o motor inteiro, e as duas pontas são do mesmo repo.
13
+ export * from '@sinete/ibs-cbs';
14
+ export type {
15
+ AliquotasCredPres,
16
+ Aplicabilidade,
17
+ BaseLegal,
18
+ BaseLegalClassTrib,
19
+ BundleDoDataset,
20
+ CalculoCredPres,
21
+ CodigoErroDadosIbsCbs,
22
+ ConteudoTributario,
23
+ CreditoClassTrib,
24
+ CredPresVigente,
25
+ DatasetIbsCbs,
26
+ DiferencaDeDatasets,
27
+ DiferencaDeTabela,
28
+ ExcecaoDePrefixo,
29
+ ExpressoesDoTratamento,
30
+ Familia,
31
+ FiltroClassTrib,
32
+ FiltroDeAtores,
33
+ FonteDoDataset,
34
+ GruposClassTrib,
35
+ GruposCredPres,
36
+ GruposCst,
37
+ IdDaFonte,
38
+ Indicador,
39
+ IndicadoresDoTratamento,
40
+ ManifestoDaTabela,
41
+ ManifestoDoDataset,
42
+ MudancaDeCampo,
43
+ MudancaDeRegistro,
44
+ NomeDaTabela,
45
+ Nomenclatura,
46
+ PapelDoAtor,
47
+ PorTributo,
48
+ RegistroAliquotaFixa,
49
+ RegistroAnexo,
50
+ RegistroAplicabilidade,
51
+ RegistroAtor,
52
+ RegistroAtorClassTrib,
53
+ RegistroClassTrib,
54
+ RegistroCredPres,
55
+ RegistroCst,
56
+ RegistroGrupoDeAtores,
57
+ RegistroNfseNbs,
58
+ RegistroReducao,
59
+ RegistroRedutorCompraGov,
60
+ RegistroTipoDfe,
61
+ RegistroTransferenciaCbs,
62
+ RegistroTratamento,
63
+ ResultadoAplicabilidade,
64
+ TabelasDoDataset,
65
+ TipoDeAliquota,
66
+ TipoDeMudanca,
67
+ Tributo,
68
+ VinculoDfe,
69
+ VinculoTratamento,
70
+ } from '@sinete/ibs-cbs-dados';
71
+ export {
72
+ aplicabilidade,
73
+ carregarDataset,
74
+ compararDatasets,
75
+ conferirDataset,
76
+ DESLOCAMENTO_BRASILIA_MIN,
77
+ dataCivil,
78
+ ErroDadosIbsCbs,
79
+ ehDataIso,
80
+ exigirDataIso,
81
+ formatarDiferenca,
82
+ jsonCanonico,
83
+ NOMES_DAS_TABELAS,
84
+ tabelaCanonica,
85
+ tipoDeMudanca,
86
+ VERSAO_DO_FORMATO_DOS_DADOS,
87
+ versaoDoConteudo,
88
+ vigente,
89
+ } from '@sinete/ibs-cbs-dados';
package/src/index.ts ADDED
@@ -0,0 +1,155 @@
1
+ /**
2
+ * `@sinete/nfe`: NF-e modelo 55 e NFC-e modelo 65. Entrada do domínio (`DadosNfe`), montagem com totais em decimal exato e validação
3
+ * estrita (`montarNfe`), assinatura por splice (`assinarNfe`) e os serviços da SEFAZ sobre `@sinete/transport`
4
+ * (`criarClienteNfe`). IBS/CBS pelo motor do sinete por padrão (`calculadoraIbsCbs`), com o dataset carregado sob
5
+ * demanda. O emissor (bytes gravados antes do envio, trava, retomada, cancelamento com recuperação) está em
6
+ * `@sinete/emissor/nfe` (ADR 0010).
7
+ */
8
+
9
+ export type {
10
+ ExigenciaRespTec,
11
+ MontarNfeOpcoes,
12
+ NfeMontada,
13
+ ResultadoMontagemNfe,
14
+ } from './build/build.ts';
15
+ export {
16
+ assinarNfe,
17
+ assinaturaQrCode,
18
+ comQrCode,
19
+ exigenciaRespTec,
20
+ hashCsrt,
21
+ montarNfe,
22
+ NFE_NS,
23
+ XNOME_HOMOLOGACAO,
24
+ XPROD_HOMOLOGACAO_NFCE,
25
+ } from './build/build.ts';
26
+ export type { NfceSupl, QrCodeNfceOpcoes } from './build/nfce.ts';
27
+ export { NFCE_LIMITE_SEM_DESTINATARIO, urlsNfce } from './build/nfce.ts';
28
+ export { conferirEmitenteDoCertificado } from './build/rejeicoes.ts';
29
+ export type { Familia } from './build/values.ts';
30
+ export type { DecimalInput, RoundingMode } from './decimal.ts';
31
+ export { Decimal, dec, sum } from './decimal.ts';
32
+ export type { FormatoDecimal } from './format.ts';
33
+ export { formatarDecimal, problemaDeFormato } from './format.ts';
34
+ export type { CodigoOcorrenciaNfe } from './issues.ts';
35
+ export { CODIGOS_OCORRENCIA_NFE } from './issues.ts';
36
+ export type {
37
+ ClassificacaoIbsCbs,
38
+ Cobranca,
39
+ Contingencia,
40
+ Crt,
41
+ CstPisCofinsOutras,
42
+ DadosNfe,
43
+ Desoneracao,
44
+ DesoneracaoSt,
45
+ Destinatario,
46
+ DetalhePagamento,
47
+ DocumentoPessoa,
48
+ Emitente,
49
+ Endereco,
50
+ EnderecoExterior,
51
+ FinNFe,
52
+ IbsCbsItem,
53
+ Icms,
54
+ Icms00,
55
+ Icms02,
56
+ Icms10,
57
+ Icms15,
58
+ Icms20,
59
+ Icms30,
60
+ Icms40,
61
+ Icms51,
62
+ Icms53,
63
+ Icms60,
64
+ Icms61,
65
+ Icms70,
66
+ Icms90,
67
+ IcmsFcp,
68
+ IcmsPartilha,
69
+ IcmsProprio,
70
+ IcmsRepasseSt,
71
+ IcmsSn101,
72
+ IcmsSn102,
73
+ IcmsSn201,
74
+ IcmsSn202,
75
+ IcmsSn500,
76
+ IcmsSn900,
77
+ IcmsSt,
78
+ IcmsStRetido,
79
+ IcmsUfDest,
80
+ ImpostoImportacao,
81
+ ImpostosItem,
82
+ IndIEDest,
83
+ InformacoesAdicionais,
84
+ Ipi,
85
+ IpiNaoTributado,
86
+ IpiTributado,
87
+ Issqn,
88
+ Item,
89
+ Local,
90
+ ModBC,
91
+ ModBCST,
92
+ ModFrete,
93
+ Origem,
94
+ Pagamento,
95
+ PisCofins,
96
+ PisCofinsSt,
97
+ Produto,
98
+ ProdutoEspecifico,
99
+ Referenciada,
100
+ RefNfp,
101
+ ResponsavelTecnico,
102
+ TCIBS_NFe,
103
+ TMonofasia,
104
+ Transportador,
105
+ Transporte,
106
+ TTribNFe,
107
+ Volume,
108
+ } from './model.ts';
109
+ export { MotivoDesoneracaoIcms, TipoPagamento } from './model.ts';
110
+ export type { CalculadoraIbsCbs, PedidoIbsCbsItem, PedidoIbsCbsNota, RespostaIbsCbs } from './ports.ts';
111
+ export { rotuloDoCaminho } from './rotulo.ts';
112
+ export type { CalculadoraIbsCbsOpcoes, GrupoIbsCbs } from './rtc.ts';
113
+ export { calculadoraIbsCbs, carregarDatasetEmbarcado, localDaOperacao } from './rtc.ts';
114
+ export type {
115
+ AutorDocumento,
116
+ AutorizarOpcoes,
117
+ Cadastro,
118
+ CadastroPedido,
119
+ CancelamentoPedido,
120
+ CancelamentoSubstituicaoPedido,
121
+ CartaCorrecaoPedido,
122
+ ClienteNfe,
123
+ ClienteNfeOpcoes,
124
+ ConsultaNfe,
125
+ ConsultaReciboOpcoes,
126
+ Distribuicao,
127
+ DistribuicaoConsulta,
128
+ DistribuicaoOpcoes,
129
+ DocumentoDistribuido,
130
+ EnvioOpcoes,
131
+ Espera,
132
+ EventoRegistrado,
133
+ Inutilizacao,
134
+ InutilizacaoPedido,
135
+ ManifestacaoPedido,
136
+ ManifestacaoTipo,
137
+ PoliticaRecibo,
138
+ ProtocoloNfe,
139
+ ResultadoAutorizacao,
140
+ ResultadoConsulta,
141
+ ResultadoEvento,
142
+ ResultadoInutilizacao,
143
+ StatusServico,
144
+ StatusServicoOpcoes,
145
+ } from './services/client.ts';
146
+ export { autorizadorContingencia, criarClienteNfe } from './services/client.ts';
147
+ export { descomprimirGzipBase64 } from './services/gzip.ts';
148
+ export type { DocumentoAssinado } from './services/proc.ts';
149
+ export { documentoAssinado, nfeAssinadaDoProc, recortarElemento } from './services/proc.ts';
150
+ export type { RecuperacaoEvento } from './services/recuperar.ts';
151
+ export { recuperarEventoRegistrado } from './services/recuperar.ts';
152
+ export type { ConteudoDoProtocolo, ResolucaoEnvio } from './services/resolver.ts';
153
+ export { chaveDaDuplicidade, resolverEnvioSemResposta } from './services/resolver.ts';
154
+ export type { Instante } from './time.ts';
155
+ export { deslocamentoDaUf, formatarDh } from './time.ts';
package/src/issues.ts ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Coletor de ocorrências de validação (`Ocorrencia` do core). O builder junta todas as ocorrências antes de
3
+ * decidir, em vez de parar na primeira. Os códigos são API pública (snake_case, português, sem acento) e estão listados
4
+ * em `CODIGOS_OCORRENCIA_NFE`.
5
+ */
6
+
7
+ import type { Ocorrencia, OrigemOcorrencia } from '@sinete/core';
8
+
9
+ export const CODIGOS_OCORRENCIA_NFE = [
10
+ 'campo_obrigatorio',
11
+ 'campo_invalido',
12
+ 'campo_fora_do_pl',
13
+ 'decimal_invalido',
14
+ 'valor_divergente',
15
+ 'combinacao_invalida',
16
+ 'modelo_nao_suportado',
17
+ 'serie_invalida',
18
+ 'documento_invalido',
19
+ 'ie_invalida',
20
+ 'chave_invalida',
21
+ 'referencia_vedada',
22
+ 'resp_tec_obrigatorio',
23
+ 'csrt_obrigatorio',
24
+ 'ibscbs_calculo',
25
+ 'ibscbs_base_ausente',
26
+ 'ibscbs_nao_suportado',
27
+ 'ibscbs_redutor_divergente',
28
+ 'ibscbs_regra_nt',
29
+ 'totais_divergentes',
30
+ 'itens_limite',
31
+ 'contingencia_invalida',
32
+ 'pagamento_igual_total',
33
+ 'emitente_difere_do_certificado',
34
+ 'grupo_vedado',
35
+ 'pagamento_invalido',
36
+ 'qrcode_invalido',
37
+ 'schema',
38
+ ] as const;
39
+
40
+ export type CodigoOcorrenciaNfe = (typeof CODIGOS_OCORRENCIA_NFE)[number];
41
+
42
+ export class Issues {
43
+ readonly list: Ocorrencia[];
44
+
45
+ constructor() {
46
+ this.list = [];
47
+ }
48
+
49
+ /** Ocorrência sobre a entrada, a não ser que `origem` diga outra coisa (ADR 0011). */
50
+ add(path: string, code: CodigoOcorrenciaNfe | string, message: string, origem: OrigemOcorrencia = 'entrada'): void {
51
+ this.list.push({ caminho: path, code, mensagem: message, origem });
52
+ }
53
+
54
+ /** Ocorrência sobre o que o sinete montou a partir da entrada (XML, schema, PL, chave gerada, calculadora). */
55
+ montagem(path: string, code: CodigoOcorrenciaNfe | string, message: string): void {
56
+ this.add(path, code, message, 'montagem');
57
+ }
58
+
59
+ /** As ocorrências com a `origem` preenchida: a que veio sem (a de um validador avulso) é da entrada. */
60
+ get classificadas(): readonly Ocorrencia[] {
61
+ return this.list.map((i) => (i.origem === undefined ? { ...i, origem: 'entrada' } : i));
62
+ }
63
+
64
+ /** Junta ocorrências de outra fonte; a que vier sem `origem` recebe a informada. */
65
+ addAll(issues: readonly Ocorrencia[], origem: OrigemOcorrencia = 'entrada'): void {
66
+ this.list.push(...issues.map((i) => (i.origem === undefined ? { ...i, origem } : i)));
67
+ }
68
+
69
+ /** Troca a `origem` das ocorrências a partir da posição `inicio` (as que uma conferência acabou de acrescentar). */
70
+ reclassificarDesde(inicio: number, origem: OrigemOcorrencia): void {
71
+ for (let k = inicio; k < this.list.length; k++) {
72
+ const i = this.list[k];
73
+ if (i !== undefined) this.list[k] = { ...i, origem };
74
+ }
75
+ }
76
+
77
+ get empty(): boolean {
78
+ return this.list.length === 0;
79
+ }
80
+ }