@sinete/nfe 0.1.0 → 0.3.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.
- package/README.md +55 -50
- package/dist/build/build.d.ts +23 -23
- package/dist/build/build.d.ts.map +1 -1
- package/dist/build/destinatario.d.ts +2 -2
- package/dist/build/ibscbs.d.ts.map +1 -1
- package/dist/build/nfce.d.ts +5 -5
- package/dist/build/nfce.d.ts.map +1 -1
- package/dist/build/pl.d.ts +4 -4
- package/dist/build/pl.d.ts.map +1 -1
- package/dist/build/rejeicoes.d.ts +7 -7
- package/dist/build/rejeicoes.d.ts.map +1 -1
- package/dist/build/textos.d.ts +26 -0
- package/dist/build/textos.d.ts.map +1 -0
- package/dist/build/values.d.ts +8 -8
- package/dist/build/values.d.ts.map +1 -1
- package/dist/decimal.d.ts +2 -2
- package/dist/decimal.d.ts.map +1 -1
- package/dist/format.d.ts +19 -19
- package/dist/format.d.ts.map +1 -1
- package/dist/ibs-cbs.d.ts +10 -5
- package/dist/ibs-cbs.d.ts.map +1 -1
- package/dist/ibs-cbs.js +35 -35
- package/dist/ibs-cbs.js.map +3 -3
- package/dist/index.d.ts +18 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +796 -588
- package/dist/index.js.map +27 -26
- package/dist/issues.d.ts +10 -10
- package/dist/issues.d.ts.map +1 -1
- package/dist/model.d.ts +4 -4
- package/dist/ports.d.ts +15 -15
- package/dist/ports.d.ts.map +1 -1
- package/dist/rotulo.d.ts +2 -2
- package/dist/rotulo.d.ts.map +1 -1
- package/dist/rtc.d.ts +23 -23
- package/dist/rtc.d.ts.map +1 -1
- package/dist/services/client.d.ts +44 -40
- package/dist/services/client.d.ts.map +1 -1
- package/dist/services/gzip.d.ts +1 -1
- package/dist/services/gzip.d.ts.map +1 -1
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/outcome.d.ts +3 -3
- package/dist/services/outcome.d.ts.map +1 -1
- package/dist/services/proc.d.ts +6 -6
- package/dist/services/proc.d.ts.map +1 -1
- package/dist/services/recuperar.d.ts +8 -7
- package/dist/services/recuperar.d.ts.map +1 -1
- package/dist/services/resolver.d.ts +12 -11
- package/dist/services/resolver.d.ts.map +1 -1
- package/dist/services/soap.d.ts +8 -8
- package/dist/services/soap.d.ts.map +1 -1
- package/dist/time.d.ts +4 -4
- package/dist/time.d.ts.map +1 -1
- package/dist/versao-gerada.d.ts +1 -1
- package/package.json +9 -9
- package/src/build/build.ts +213 -203
- package/src/build/destinatario.ts +8 -8
- package/src/build/ibscbs.ts +10 -6
- package/src/build/icms.ts +6 -6
- package/src/build/nfce.ts +19 -19
- package/src/build/pl.ts +12 -12
- package/src/build/rejeicoes.ts +13 -13
- package/src/build/textos.ts +228 -0
- package/src/build/values.ts +14 -14
- package/src/data/arredondamento.json +1 -1
- package/src/data/cstat.json +6 -6
- package/src/data/fusos.json +1 -1
- package/src/data/nfce-urls.json +2 -2
- package/src/data/produtor-rural.json +1 -1
- package/src/data/resp-tec.json +1 -1
- package/src/decimal.ts +10 -9
- package/src/format.ts +29 -28
- package/src/ibs-cbs.ts +79 -74
- package/src/index.ts +29 -27
- package/src/issues.ts +11 -11
- package/src/model.ts +4 -4
- package/src/ports.ts +15 -15
- package/src/rotulo.ts +4 -4
- package/src/rtc.ts +91 -91
- package/src/services/client.ts +248 -217
- package/src/services/gzip.ts +7 -7
- package/src/services/index.ts +12 -10
- package/src/services/outcome.ts +9 -9
- package/src/services/proc.ts +50 -49
- package/src/services/recuperar.ts +29 -25
- package/src/services/resolver.ts +25 -23
- package/src/services/soap.ts +35 -35
- package/src/time.ts +6 -6
- package/src/versao-gerada.ts +1 -1
package/src/issues.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Coletor de ocorrências de validação (`
|
|
2
|
+
* Coletor de ocorrências de validação (`Ocorrencia` do core). O builder junta todas as ocorrências antes de
|
|
3
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 `
|
|
4
|
+
* em `CODIGOS_OCORRENCIA_NFE`.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type {
|
|
7
|
+
import type { Ocorrencia, OrigemOcorrencia } from '@sinete/core';
|
|
8
8
|
|
|
9
|
-
export const
|
|
9
|
+
export const CODIGOS_OCORRENCIA_NFE = [
|
|
10
10
|
'campo_obrigatorio',
|
|
11
11
|
'campo_invalido',
|
|
12
12
|
'campo_fora_do_pl',
|
|
@@ -37,32 +37,32 @@ export const NFE_ISSUE_CODES = [
|
|
|
37
37
|
'schema',
|
|
38
38
|
] as const;
|
|
39
39
|
|
|
40
|
-
export type
|
|
40
|
+
export type CodigoOcorrenciaNfe = (typeof CODIGOS_OCORRENCIA_NFE)[number];
|
|
41
41
|
|
|
42
42
|
export class Issues {
|
|
43
|
-
readonly list:
|
|
43
|
+
readonly list: Ocorrencia[];
|
|
44
44
|
|
|
45
45
|
constructor() {
|
|
46
46
|
this.list = [];
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/** Ocorrência sobre a entrada, a não ser que `origem` diga outra coisa (ADR 0011). */
|
|
50
|
-
add(path: string, code:
|
|
51
|
-
this.list.push({ path, code, message, origem });
|
|
50
|
+
add(path: string, code: CodigoOcorrenciaNfe | string, message: string, origem: OrigemOcorrencia = 'entrada'): void {
|
|
51
|
+
this.list.push({ caminho: path, code, mensagem: message, origem });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** Ocorrência sobre o que o sinete montou a partir da entrada (XML, schema, PL, chave gerada, calculadora). */
|
|
55
|
-
montagem(path: string, code:
|
|
55
|
+
montagem(path: string, code: CodigoOcorrenciaNfe | string, message: string): void {
|
|
56
56
|
this.add(path, code, message, 'montagem');
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/** As ocorrências com a `origem` preenchida: a que veio sem (a de um validador avulso) é da entrada. */
|
|
60
|
-
get classificadas(): readonly
|
|
60
|
+
get classificadas(): readonly Ocorrencia[] {
|
|
61
61
|
return this.list.map((i) => (i.origem === undefined ? { ...i, origem: 'entrada' } : i));
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/** Junta ocorrências de outra fonte; a que vier sem `origem` recebe a informada. */
|
|
65
|
-
addAll(issues: readonly
|
|
65
|
+
addAll(issues: readonly Ocorrencia[], origem: OrigemOcorrencia = 'entrada'): void {
|
|
66
66
|
this.list.push(...issues.map((i) => (i.origem === undefined ? { ...i, origem } : i)));
|
|
67
67
|
}
|
|
68
68
|
|
package/src/model.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Modelo de entrada da NF-e: o que quem emite descreve. O builder (`
|
|
2
|
+
* Modelo de entrada da NF-e: o que quem emite descreve. O builder (`montarNfe`) transforma isto no objeto tipado do
|
|
3
3
|
* `@sinete/schemas` do pacote de liberação vigente, calcula os valores derivados e os totais em decimal exato e
|
|
4
4
|
* confere as regras antes de qualquer serialização.
|
|
5
5
|
*
|
|
@@ -727,7 +727,7 @@ export type PisCofinsSt = {
|
|
|
727
727
|
// ---------------------------------------------------------------------------------------------------------------
|
|
728
728
|
|
|
729
729
|
/**
|
|
730
|
-
* Classificação do item para IBS/CBS (NT 2025.002): o que o `
|
|
730
|
+
* Classificação do item para IBS/CBS (NT 2025.002): o que o `CalculadoraIbsCbs` recebe. `CST` e `cClassTrib` vêm do
|
|
731
731
|
* cadastro do item (tabela de classificação tributária); o cálculo, as alíquotas e as reduções são da calculadora.
|
|
732
732
|
*/
|
|
733
733
|
export interface ClassificacaoIbsCbs {
|
|
@@ -955,7 +955,7 @@ export type FinNFe = '1' | '2' | '3' | '4' | '5' | '6';
|
|
|
955
955
|
*/
|
|
956
956
|
export interface Contingencia {
|
|
957
957
|
/**
|
|
958
|
-
* 6 SVC-AN, 7 SVC-RS; 2 FS-IA; 4 EPEC; 5 FS-DA; 9 off-line, só NFC-e. Para SVC, `tpEmisSvc` do `
|
|
958
|
+
* 6 SVC-AN, 7 SVC-RS; 2 FS-IA; 4 EPEC; 5 FS-DA; 9 off-line, só NFC-e. Para SVC, `tpEmisSvc` do `ClienteNfe` escolhe pelo
|
|
959
959
|
* dado da UF.
|
|
960
960
|
*/
|
|
961
961
|
readonly tpEmis: '2' | '4' | '5' | '6' | '7' | '9';
|
|
@@ -966,7 +966,7 @@ export interface Contingencia {
|
|
|
966
966
|
}
|
|
967
967
|
|
|
968
968
|
/** Entrada completa de uma NF-e. */
|
|
969
|
-
export interface
|
|
969
|
+
export interface DadosNfe {
|
|
970
970
|
/**
|
|
971
971
|
* 55 (NF-e, padrão) ou 65 (NFC-e). Na NFC-e mudam os padrões (`indPres` 1, `indFinal` 1, `tpImp` 4), o destinatário
|
|
972
972
|
* fica opcional, o pagamento passa a ser obrigatório e a montagem acrescenta o `infNFeSupl` (QR Code).
|
package/src/ports.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Portas do `@sinete/nfe` para o que pode vir de fora. A montagem só conhece o contrato estreito declarado aqui; a
|
|
3
|
-
* implementação padrão do IBS/CBS é o `
|
|
4
|
-
* lugar (ou testa com alíquotas fixas) injeta a sua em `
|
|
3
|
+
* implementação padrão do IBS/CBS é o `calculadoraIbsCbs` (`rtc.ts`, sobre o `@sinete/ibs-cbs`), e quem calcula em outro
|
|
4
|
+
* lugar (ou testa com alíquotas fixas) injeta a sua em `MontarNfeOpcoes.ibsCbs`.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { Ambiente,
|
|
7
|
+
import type { Ambiente, Ocorrencia, Uf } from '@sinete/core';
|
|
8
8
|
import type { TTribNFe } from '@sinete/schemas/nfe/PL_010f';
|
|
9
9
|
import type { Decimal } from './decimal.ts';
|
|
10
10
|
import type { Instante } from './time.ts';
|
|
11
11
|
|
|
12
12
|
/** Um item classificado, com os valores que a calculadora pode precisar para a base do IBS/CBS. */
|
|
13
|
-
export interface
|
|
13
|
+
export interface PedidoIbsCbsItem {
|
|
14
14
|
/** Número do item na nota (1 a 990). */
|
|
15
15
|
readonly nItem: number;
|
|
16
16
|
/** CST do IBS/CBS (3 dígitos). */
|
|
@@ -54,8 +54,8 @@ export interface IbsCbsItemRequest {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/** Dados da nota que decidem a regra aplicável (local da operação, vigência, compra governamental). */
|
|
57
|
-
export interface
|
|
58
|
-
/** Instante do fato gerador (relógio `fatoGerador` do `
|
|
57
|
+
export interface PedidoIbsCbsNota {
|
|
58
|
+
/** Instante do fato gerador (relógio `fatoGerador` do `ContextoDeTempo`): decide a vigência das alíquotas. */
|
|
59
59
|
readonly fatoGerador: Instante;
|
|
60
60
|
/** Instante da emissão (o do `dhEmi`): decide quais regras de validação da NT já estão implantadas no ambiente. */
|
|
61
61
|
readonly emissao: Instante;
|
|
@@ -75,22 +75,22 @@ export interface IbsCbsNotaRequest {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
/** Resultado da calculadora: o grupo `IBSCBS` de cada item pedido, já na forma lexical do leiaute. */
|
|
78
|
-
export interface
|
|
78
|
+
export interface RespostaIbsCbs {
|
|
79
79
|
readonly itens: readonly { readonly nItem: number; readonly IBSCBS: TTribNFe }[];
|
|
80
80
|
/**
|
|
81
|
-
* Problemas de classificação ou de dado (`
|
|
81
|
+
* Problemas de classificação ou de dado (`caminho` relativo ao item, como `itens[2].impostos.ibsCbs`). A ocorrência sem
|
|
82
82
|
* `origem` entra como `montagem` (ADR 0011); marque `entrada` a que aponta um valor da nota.
|
|
83
83
|
*/
|
|
84
|
-
readonly
|
|
84
|
+
readonly ocorrencias?: readonly Ocorrencia[];
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Calcula o IBS e a CBS dos itens classificados. O padrão é o `
|
|
88
|
+
* Calcula o IBS e a CBS dos itens classificados. O padrão é o `calculadoraIbsCbs`, sobre o `@sinete/ibs-cbs/calcular`; nos
|
|
89
89
|
* testes, um dublê com alíquotas fixas. A calculadora não vê o XML nem o resto da nota além do que está no pedido.
|
|
90
90
|
*/
|
|
91
|
-
export interface
|
|
92
|
-
calcular(
|
|
93
|
-
readonly nota:
|
|
94
|
-
readonly itens: readonly
|
|
95
|
-
}):
|
|
91
|
+
export interface CalculadoraIbsCbs {
|
|
92
|
+
calcular(pedido: {
|
|
93
|
+
readonly nota: PedidoIbsCbsNota;
|
|
94
|
+
readonly itens: readonly PedidoIbsCbsItem[];
|
|
95
|
+
}): RespostaIbsCbs | Promise<RespostaIbsCbs>;
|
|
96
96
|
}
|
package/src/rotulo.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rótulo em português do caminho de uma ocorrência da NF-e (ADR 0011), para mostrar a quem preencheu a nota: `Item 2,
|
|
3
|
-
* Descrição do produto` em vez de `itens[1].produto.xProd`. Aceita os caminhos da entrada (`
|
|
3
|
+
* Descrição do produto` em vez de `itens[1].produto.xProd`. Aceita os caminhos da entrada (`DadosNfe`) e os do
|
|
4
4
|
* documento montado, tanto os das conferências do montador (`infNFe.det[1].prod.xProd`) quanto os do validador de XSD
|
|
5
5
|
* (`/infNFe/det[2]/prod/xProd`).
|
|
6
6
|
*/
|
|
@@ -15,7 +15,7 @@ const item =
|
|
|
15
15
|
|
|
16
16
|
/** Do mais específico ao mais geral. Os índices chegam somados de um. */
|
|
17
17
|
const GRUPOS: readonly GrupoDeCaminho[] = [
|
|
18
|
-
// Entrada (
|
|
18
|
+
// Entrada (DadosNfe)
|
|
19
19
|
{ padrao: /^emitente\b/, rotulo: 'Emitente' },
|
|
20
20
|
{ padrao: /^destinatario\b/, rotulo: 'Destinatário' },
|
|
21
21
|
{ padrao: /^retirada\b/, rotulo: 'Local de retirada' },
|
|
@@ -132,6 +132,6 @@ const rotular = criarRotuloDoCaminho({ grupos: GRUPOS, campos: CAMPOS, padrao: '
|
|
|
132
132
|
* Rótulo em português do caminho de uma ocorrência da NF-e: `Grupo, Campo` quando os dois são conhecidos (`Emitente,
|
|
133
133
|
* Inscrição estadual`), só um deles quando falta o outro, e `Dados da NF-e` quando nenhum é.
|
|
134
134
|
*/
|
|
135
|
-
export function rotuloDoCaminho(
|
|
136
|
-
return rotular(
|
|
135
|
+
export function rotuloDoCaminho(caminho: string): string {
|
|
136
|
+
return rotular(caminho);
|
|
137
137
|
}
|
package/src/rtc.ts
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A calculadora padrão de IBS/CBS do `
|
|
2
|
+
* A calculadora padrão de IBS/CBS do `montarNfe`: a porta `CalculadoraIbsCbs` implementada sobre o motor do sinete.
|
|
3
3
|
*
|
|
4
4
|
* Para cada item classificado, monta a operação do `@sinete/ibs-cbs/calcular` (CST, cClassTrib, base, local da operação,
|
|
5
5
|
* compra governamental), calcula com o dataset do `@sinete/ibs-cbs-dados` e as alíquotas do `@sinete/ibs-cbs/aliquotas`, confere o
|
|
6
6
|
* resultado pelas regras da NT 2025.002 do `@sinete/ibs-cbs/validar` e devolve o grupo `IBSCBS` de cada item na forma
|
|
7
7
|
* lexical do leiaute. Erro de classificação, regime não suportado, alíquota desconhecida e violação de regra voltam
|
|
8
|
-
* como ocorrências (`
|
|
8
|
+
* como ocorrências (`Ocorrencia`) no caminho do item: a nota não é montada, e nunca sai valor zerado no lugar.
|
|
9
9
|
*
|
|
10
10
|
* O dataset embarcado (~2 MB de JSON) só é importado na primeira nota com item classificado, por `import()` dinâmico:
|
|
11
11
|
* quem usa o pacote para ler XML, eventos ou Distribuição DF-e não o carrega, e um bundler com code splitting o põe num
|
|
12
12
|
* chunk à parte.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type {
|
|
16
|
-
import {
|
|
17
|
-
import type {
|
|
18
|
-
import {
|
|
15
|
+
import type { Ocorrencia } from '@sinete/core';
|
|
16
|
+
import { contextoDeTempo, ehUf, relogioFixo, ufPorCUf } from '@sinete/core';
|
|
17
|
+
import type { ProvedorDeAliquotas } from '@sinete/ibs-cbs/aliquotas';
|
|
18
|
+
import { aliquotasOficiais, ErroAliquotaDesconhecida } from '@sinete/ibs-cbs/aliquotas';
|
|
19
19
|
import type {
|
|
20
|
-
ClassifiedItem,
|
|
21
|
-
ClassifiedOperation,
|
|
22
20
|
IBSCBS,
|
|
23
|
-
|
|
21
|
+
ItemClassificado,
|
|
22
|
+
LocalDaOperacao,
|
|
23
|
+
OperacaoClassificada,
|
|
24
24
|
Roc,
|
|
25
25
|
TpEnteGov,
|
|
26
26
|
} from '@sinete/ibs-cbs/calcular';
|
|
27
|
-
import {
|
|
28
|
-
import type {
|
|
29
|
-
import {
|
|
30
|
-
import type {
|
|
31
|
-
import type {
|
|
27
|
+
import { calcular, ErroClassificacao, ErroRegimeNaoSuportado } from '@sinete/ibs-cbs/calcular';
|
|
28
|
+
import type { Regra } from '@sinete/ibs-cbs/validar';
|
|
29
|
+
import { documentoDoRoc, validar } from '@sinete/ibs-cbs/validar';
|
|
30
|
+
import type { DatasetIbsCbs } from '@sinete/ibs-cbs-dados';
|
|
31
|
+
import type { CalculadoraIbsCbs, PedidoIbsCbsItem, PedidoIbsCbsNota, RespostaIbsCbs } from './ports.ts';
|
|
32
32
|
|
|
33
33
|
/** Grupo `IBSCBS` do item, como o `@sinete/nfe` o recebe. */
|
|
34
|
-
export type GrupoIbsCbs =
|
|
34
|
+
export type GrupoIbsCbs = RespostaIbsCbs['itens'][number]['IBSCBS'];
|
|
35
35
|
|
|
36
|
-
export interface
|
|
36
|
+
export interface CalculadoraIbsCbsOpcoes {
|
|
37
37
|
/**
|
|
38
38
|
* Dataset do IBS/CBS. Padrão: o embarcado no `@sinete/ibs-cbs-dados`, importado sob demanda na primeira nota
|
|
39
|
-
* (`carregarDatasetEmbarcado`). Informe um bundle verificado em runtime (`
|
|
40
|
-
* origem, ou o `
|
|
39
|
+
* (`carregarDatasetEmbarcado`). Informe um bundle verificado em runtime (`conferirDataset`) para usar dados de outra
|
|
40
|
+
* origem, ou o `datasetEmbarcado()` já carregado para o cálculo ser síncrono.
|
|
41
41
|
*/
|
|
42
|
-
readonly dataset?:
|
|
43
|
-
/** Alíquotas. Padrão: `
|
|
44
|
-
readonly
|
|
42
|
+
readonly dataset?: DatasetIbsCbs;
|
|
43
|
+
/** Alíquotas. Padrão: `aliquotasOficiais()` do `@sinete/ibs-cbs/aliquotas`; troque por um provedor com alíquotas informadas. */
|
|
44
|
+
readonly aliquotas?: ProvedorDeAliquotas;
|
|
45
45
|
/**
|
|
46
46
|
* Base do IBS/CBS do item que não trouxe `vBC`, em texto com até 2 casas. A composição da base (NT 2025.002, UB16-10)
|
|
47
47
|
* ainda é "implementação futura, aguardando orientação normativa": sem esta função, item sem `vBC` vira ocorrência
|
|
48
48
|
* `ibscbs_base_ausente` em vez de uma base presumida.
|
|
49
49
|
*/
|
|
50
|
-
readonly base?: (item:
|
|
50
|
+
readonly base?: (item: PedidoIbsCbsItem, nota: PedidoIbsCbsNota) => string;
|
|
51
51
|
/**
|
|
52
52
|
* Regras da NT 2025.002 conferidas sobre os grupos produzidos (`@sinete/ibs-cbs/validar`). Padrão: as implantadas na data
|
|
53
53
|
* de emissão e no ambiente. `false` desliga; `{ rules }` troca a lista.
|
|
54
54
|
*/
|
|
55
|
-
readonly regras?: false | { readonly
|
|
55
|
+
readonly regras?: false | { readonly regras?: readonly Regra[]; readonly ignorarAtivacao?: boolean };
|
|
56
56
|
/** Fuso do local da operação para a data civil do fato gerador, em minutos. Padrão: Brasília (-180). */
|
|
57
|
-
readonly
|
|
57
|
+
readonly deslocamentoMin?: number;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const BASE = /^\d{1,13}(\.\d{1,2})?$/;
|
|
@@ -71,7 +71,7 @@ const caminho = (nItem: number): string => `itens[${nItem - 1}].impostos.ibsCbs`
|
|
|
71
71
|
|
|
72
72
|
/** UF do município pelo código IBGE (os dois primeiros dígitos são o cUF). */
|
|
73
73
|
function ufDoMunicipio(cMun: string): string | undefined {
|
|
74
|
-
return
|
|
74
|
+
return ufPorCUf(cMun.slice(0, 2))?.sigla;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
/**
|
|
@@ -79,13 +79,13 @@ function ufDoMunicipio(cMun: string): string | undefined {
|
|
|
79
79
|
* 2025.002, município de ocorrência do fato gerador do IBS/CBS), senão o destino da mercadoria (entrega ou
|
|
80
80
|
* destinatário, pela LC 214/2025, art. 11, o local da entrega), senão o emitente. Destino no exterior cai no emitente.
|
|
81
81
|
*/
|
|
82
|
-
export function localDaOperacao(nota:
|
|
82
|
+
export function localDaOperacao(nota: PedidoIbsCbsNota): LocalDaOperacao {
|
|
83
83
|
if (nota.cMunFGIBS !== undefined) {
|
|
84
84
|
const uf = ufDoMunicipio(nota.cMunFGIBS);
|
|
85
85
|
if (uf !== undefined) return { uf, cMun: nota.cMunFGIBS };
|
|
86
86
|
}
|
|
87
87
|
const d = nota.destino;
|
|
88
|
-
if (d !== undefined && d.UF !== 'EX' &&
|
|
88
|
+
if (d !== undefined && d.UF !== 'EX' && ehUf(d.UF)) return { uf: d.UF, cMun: d.cMun };
|
|
89
89
|
return { uf: nota.emitente.UF, cMun: nota.emitente.cMun };
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -110,27 +110,27 @@ function grupoDoLeiaute(g: IBSCBS, indDoacao: '1' | undefined): GrupoIbsCbs {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/** Erro do motor ou das alíquotas como ocorrência no item (ou na nota, quando o erro não diz o item). */
|
|
113
|
-
function ocorrenciaDoMotor(e: unknown, itens: readonly
|
|
114
|
-
if (e instanceof
|
|
113
|
+
function ocorrenciaDoMotor(e: unknown, itens: readonly PedidoIbsCbsItem[]): Ocorrencia | undefined {
|
|
114
|
+
if (e instanceof ErroClassificacao || e instanceof ErroRegimeNaoSuportado) {
|
|
115
115
|
const path = e.item !== undefined ? caminho(e.item) : caminho(itens[0]?.nItem ?? 1);
|
|
116
|
-
return { path, code: e.code,
|
|
116
|
+
return { caminho: path, code: e.code, mensagem: e.message, origem: 'entrada' };
|
|
117
117
|
}
|
|
118
118
|
// Alíquota que o sinete não conhece para a data: falta de dado do pacote, não da nota.
|
|
119
|
-
if (e instanceof
|
|
120
|
-
return {
|
|
119
|
+
if (e instanceof ErroAliquotaDesconhecida)
|
|
120
|
+
return { caminho: 'impostos.ibsCbs', code: e.code, mensagem: e.message, origem: 'montagem' };
|
|
121
121
|
return undefined;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
let embarcado: Promise<
|
|
124
|
+
let embarcado: Promise<DatasetIbsCbs> | undefined;
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
127
|
* O dataset embarcado no `@sinete/ibs-cbs-dados`, importado sob demanda (`import()` dinâmico) e carregado uma vez por
|
|
128
128
|
* processo. É o que a calculadora padrão usa quando `dataset` não é informado; chamar antes só adianta a carga. Se o
|
|
129
129
|
* import falhar, a próxima chamada tenta de novo.
|
|
130
130
|
*/
|
|
131
|
-
export function carregarDatasetEmbarcado(): Promise<
|
|
132
|
-
embarcado ??= import('@sinete/ibs-cbs-dados/
|
|
133
|
-
(m) => m.
|
|
131
|
+
export function carregarDatasetEmbarcado(): Promise<DatasetIbsCbs> {
|
|
132
|
+
embarcado ??= import('@sinete/ibs-cbs-dados/embarcado').then(
|
|
133
|
+
(m) => m.datasetEmbarcado(),
|
|
134
134
|
(e: unknown) => {
|
|
135
135
|
embarcado = undefined;
|
|
136
136
|
throw e;
|
|
@@ -140,45 +140,45 @@ export function carregarDatasetEmbarcado(): Promise<IbsCbsDataset> {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
|
-
* Cria a calculadora de IBS/CBS sobre o motor do sinete. O `
|
|
144
|
-
* `
|
|
143
|
+
* Cria a calculadora de IBS/CBS sobre o motor do sinete. O `montarNfe` usa uma com as opções padrão quando
|
|
144
|
+
* `opcoes.ibsCbs` não é informado; crie a sua para trocar dataset, alíquotas, base ou regras. Com `dataset` informado
|
|
145
145
|
* o cálculo é síncrono; sem ele, a primeira chamada espera o import do dataset embarcado.
|
|
146
146
|
*/
|
|
147
|
-
export function
|
|
148
|
-
const rates =
|
|
149
|
-
const dataset =
|
|
147
|
+
export function calculadoraIbsCbs(opcoes: CalculadoraIbsCbsOpcoes = {}): CalculadoraIbsCbs {
|
|
148
|
+
const rates = opcoes.aliquotas ?? aliquotasOficiais();
|
|
149
|
+
const dataset = opcoes.dataset;
|
|
150
150
|
return {
|
|
151
151
|
calcular(request: {
|
|
152
|
-
readonly nota:
|
|
153
|
-
readonly itens: readonly
|
|
154
|
-
}):
|
|
155
|
-
if (dataset !== undefined) return calcularCom(dataset, rates,
|
|
156
|
-
return carregarDatasetEmbarcado().then((ds) => calcularCom(ds, rates,
|
|
152
|
+
readonly nota: PedidoIbsCbsNota;
|
|
153
|
+
readonly itens: readonly PedidoIbsCbsItem[];
|
|
154
|
+
}): RespostaIbsCbs | Promise<RespostaIbsCbs> {
|
|
155
|
+
if (dataset !== undefined) return calcularCom(dataset, rates, opcoes, request);
|
|
156
|
+
return carregarDatasetEmbarcado().then((ds) => calcularCom(ds, rates, opcoes, request));
|
|
157
157
|
},
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
function calcularCom(
|
|
162
|
-
dataset:
|
|
163
|
-
rates:
|
|
164
|
-
options:
|
|
162
|
+
dataset: DatasetIbsCbs,
|
|
163
|
+
rates: ProvedorDeAliquotas,
|
|
164
|
+
options: CalculadoraIbsCbsOpcoes,
|
|
165
165
|
{
|
|
166
166
|
nota,
|
|
167
167
|
itens,
|
|
168
168
|
}: {
|
|
169
|
-
readonly nota:
|
|
170
|
-
readonly itens: readonly
|
|
169
|
+
readonly nota: PedidoIbsCbsNota;
|
|
170
|
+
readonly itens: readonly PedidoIbsCbsItem[];
|
|
171
171
|
},
|
|
172
|
-
):
|
|
173
|
-
const issues:
|
|
174
|
-
const classificados:
|
|
172
|
+
): RespostaIbsCbs {
|
|
173
|
+
const issues: Ocorrencia[] = [];
|
|
174
|
+
const classificados: ItemClassificado[] = [];
|
|
175
175
|
for (const it of itens) {
|
|
176
176
|
if (it.cCredPres !== undefined) {
|
|
177
177
|
// O crédito presumido pede os percentuais por tributo (pCredPres), que a porta não traz.
|
|
178
178
|
issues.push({
|
|
179
|
-
|
|
179
|
+
caminho: caminho(it.nItem),
|
|
180
180
|
code: 'ibscbs_nao_suportado',
|
|
181
|
-
|
|
181
|
+
mensagem: 'crédito presumido (cCredPres) precisa do grupo gCredPresOper pronto (ibsCbs.grupo)',
|
|
182
182
|
origem: 'entrada',
|
|
183
183
|
});
|
|
184
184
|
continue;
|
|
@@ -186,10 +186,10 @@ function calcularCom(
|
|
|
186
186
|
const base = it.vBC !== undefined ? it.vBC.toFixed(2) : options.base?.(it, nota);
|
|
187
187
|
if (base === undefined) {
|
|
188
188
|
issues.push({
|
|
189
|
-
|
|
189
|
+
caminho: `${caminho(it.nItem)}.classificacao.vBC`,
|
|
190
190
|
code: 'ibscbs_base_ausente',
|
|
191
|
-
|
|
192
|
-
'informe vBC do IBS/CBS ou
|
|
191
|
+
mensagem:
|
|
192
|
+
'informe vBC do IBS/CBS ou CalculadoraIbsCbsOpcoes.base: a composição da base (UB16-10) ainda não tem regra publicada',
|
|
193
193
|
origem: 'entrada',
|
|
194
194
|
});
|
|
195
195
|
continue;
|
|
@@ -197,9 +197,9 @@ function calcularCom(
|
|
|
197
197
|
if (!BASE.test(base)) {
|
|
198
198
|
// Da entrada quando é o vBC do item; da montagem quando veio da função `base` das opções.
|
|
199
199
|
issues.push({
|
|
200
|
-
|
|
200
|
+
caminho: `${caminho(it.nItem)}.classificacao.vBC`,
|
|
201
201
|
code: 'decimal_invalido',
|
|
202
|
-
|
|
202
|
+
mensagem: base,
|
|
203
203
|
origem: it.vBC !== undefined ? 'entrada' : 'montagem',
|
|
204
204
|
});
|
|
205
205
|
continue;
|
|
@@ -209,43 +209,43 @@ function calcularCom(
|
|
|
209
209
|
cst: it.CST,
|
|
210
210
|
cClassTrib: it.cClassTrib,
|
|
211
211
|
base,
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
quantidade: it.qTrib.toString(),
|
|
213
|
+
unidade: it.uTrib,
|
|
214
214
|
...(it.gTribRegular === undefined
|
|
215
215
|
? {}
|
|
216
216
|
: { regular: { cst: it.gTribRegular.CSTReg, cClassTrib: it.gTribRegular.cClassTribReg } }),
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
|
-
if (issues.length > 0) return { itens: [], issues };
|
|
219
|
+
if (issues.length > 0) return { itens: [], ocorrencias: issues };
|
|
220
220
|
|
|
221
|
-
const op:
|
|
221
|
+
const op: OperacaoClassificada = {
|
|
222
222
|
modelo: Number(nota.mod),
|
|
223
|
-
|
|
223
|
+
local: localDaOperacao(nota),
|
|
224
224
|
...(nota.compraGov === undefined
|
|
225
225
|
? {}
|
|
226
226
|
: {
|
|
227
|
-
|
|
227
|
+
compraGovernamental: {
|
|
228
228
|
tpEnteGov: Number(nota.compraGov.tpEnteGov) as TpEnteGov,
|
|
229
229
|
...(nota.compraGov.tpOperGov === '1' || nota.compraGov.tpOperGov === '2'
|
|
230
230
|
? { tpOperGov: Number(nota.compraGov.tpOperGov) as 1 | 2 }
|
|
231
231
|
: {}),
|
|
232
232
|
},
|
|
233
233
|
}),
|
|
234
|
-
|
|
234
|
+
itens: classificados,
|
|
235
235
|
};
|
|
236
|
-
const time =
|
|
236
|
+
const time = contextoDeTempo({ emissao: relogioFixo(nota.emissao), fatoGerador: relogioFixo(nota.fatoGerador) });
|
|
237
237
|
let roc: Roc;
|
|
238
238
|
try {
|
|
239
|
-
roc =
|
|
239
|
+
roc = calcular(op, {
|
|
240
240
|
dataset,
|
|
241
|
-
rates,
|
|
242
|
-
time,
|
|
243
|
-
...(options.
|
|
241
|
+
aliquotas: rates,
|
|
242
|
+
tempo: time,
|
|
243
|
+
...(options.deslocamentoMin === undefined ? {} : { deslocamentoMin: options.deslocamentoMin }),
|
|
244
244
|
});
|
|
245
245
|
} catch (e) {
|
|
246
246
|
const issue = ocorrenciaDoMotor(e, itens);
|
|
247
247
|
if (issue === undefined) throw e;
|
|
248
|
-
return { itens: [],
|
|
248
|
+
return { itens: [], ocorrencias: [issue] };
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
// O redutor da compra governamental vai no ide.gCompraGov como a nota informou, mas o motor calcula com o do
|
|
@@ -257,38 +257,38 @@ function calcularCom(
|
|
|
257
257
|
normalizado(nota.compraGov.pRedutor.toString()) !== normalizado(redutor)
|
|
258
258
|
) {
|
|
259
259
|
issues.push({
|
|
260
|
-
|
|
260
|
+
caminho: 'gCompraGov.pRedutor',
|
|
261
261
|
code: 'ibscbs_redutor_divergente',
|
|
262
|
-
|
|
262
|
+
mensagem: `pRedutor informado (${nota.compraGov.pRedutor.toString()}) difere do vigente no fato gerador (${redutor})`,
|
|
263
263
|
origem: 'entrada',
|
|
264
264
|
});
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
if (options.regras !== false) {
|
|
268
|
-
const doc =
|
|
268
|
+
const doc = documentoDoRoc(roc, {
|
|
269
269
|
modelo: op.modelo as 55 | 65,
|
|
270
270
|
crt: Number(nota.emitente.CRT) as 1 | 2 | 3 | 4,
|
|
271
271
|
finNFe: Number(nota.finNFe) as 1 | 2 | 3 | 4 | 5 | 6,
|
|
272
272
|
...(nota.tpNFDebito === undefined ? {} : { tpNFDebito: nota.tpNFDebito }),
|
|
273
273
|
...(nota.tpNFCredito === undefined ? {} : { tpNFCredito: nota.tpNFCredito }),
|
|
274
|
-
|
|
275
|
-
...(nota.destino === undefined ? {} : {
|
|
276
|
-
|
|
274
|
+
munEmitente: nota.emitente.cMun,
|
|
275
|
+
...(nota.destino === undefined ? {} : { munDestinatario: nota.destino.cMun }),
|
|
276
|
+
itens: itens.map((it) => ({ nItem: it.nItem, ncm: it.NCM, vProd: it.vProd.toFixed(2) })),
|
|
277
277
|
});
|
|
278
|
-
const report =
|
|
278
|
+
const report = validar(doc, {
|
|
279
279
|
dataset,
|
|
280
|
-
time,
|
|
280
|
+
tempo: time,
|
|
281
281
|
ambiente: nota.ambiente,
|
|
282
|
-
rates,
|
|
283
|
-
...(options.
|
|
284
|
-
...(options.regras?.
|
|
285
|
-
...(options.regras?.
|
|
282
|
+
aliquotas: rates,
|
|
283
|
+
...(options.deslocamentoMin === undefined ? {} : { deslocamentoMin: options.deslocamentoMin }),
|
|
284
|
+
...(options.regras?.regras === undefined ? {} : { regras: options.regras.regras }),
|
|
285
|
+
...(options.regras?.ignorarAtivacao === undefined ? {} : { ignorarAtivacao: options.regras.ignorarAtivacao }),
|
|
286
286
|
});
|
|
287
|
-
for (const v of report.
|
|
287
|
+
for (const v of report.violacoes) {
|
|
288
288
|
issues.push({
|
|
289
|
-
|
|
289
|
+
caminho: v.item === undefined ? 'total.IBSCBSTot' : caminho(v.item),
|
|
290
290
|
code: 'ibscbs_regra_nt',
|
|
291
|
-
|
|
291
|
+
mensagem: `${v.regra} (rejeição ${v.cStat}): ${v.message} [${v.fonte}]`,
|
|
292
292
|
origem: 'montagem',
|
|
293
293
|
});
|
|
294
294
|
}
|
|
@@ -296,10 +296,10 @@ function calcularCom(
|
|
|
296
296
|
|
|
297
297
|
const porItem = new Map(itens.map((it) => [it.nItem, it]));
|
|
298
298
|
return {
|
|
299
|
-
itens: roc.
|
|
299
|
+
itens: roc.itens.map((r) => ({
|
|
300
300
|
nItem: r.nItem,
|
|
301
301
|
IBSCBS: grupoDoLeiaute(r.IBSCBS, porItem.get(r.nItem)?.indDoacao),
|
|
302
302
|
})),
|
|
303
|
-
...(issues.length === 0 ? {} : { issues }),
|
|
303
|
+
...(issues.length === 0 ? {} : { ocorrencias: issues }),
|
|
304
304
|
};
|
|
305
305
|
}
|