@useinvio/nfse-sdk 3.0.0 → 3.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.
- package/CHANGELOG.md +176 -0
- package/README.en.md +146 -0
- package/README.md +77 -518
- package/dist/agent.d.ts +131 -0
- package/dist/agent.js +551 -0
- package/dist/agent.js.map +1 -0
- package/dist/certificate.d.ts +96 -0
- package/dist/certificate.js +218 -0
- package/dist/certificate.js.map +1 -0
- package/dist/certificateValidation.d.ts +11 -6
- package/dist/certificateValidation.js +23 -12
- package/dist/certificateValidation.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +520 -0
- package/dist/cli.js.map +1 -0
- package/dist/cliBin.d.ts +2 -0
- package/dist/cliBin.js +6 -0
- package/dist/cliBin.js.map +1 -0
- package/dist/cliExample.d.ts +6 -0
- package/dist/cliExample.js +29 -0
- package/dist/cliExample.js.map +1 -0
- package/dist/client.d.ts +51 -4
- package/dist/client.js +41 -10
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/consultas.d.ts +34 -0
- package/dist/consultas.js +61 -0
- package/dist/consultas.js.map +1 -0
- package/dist/dpsJson.js +1 -41
- package/dist/dpsJson.js.map +1 -1
- package/dist/dpsJsonSchema.d.ts +17 -0
- package/dist/dpsJsonSchema.js +184 -0
- package/dist/dpsJsonSchema.js.map +1 -0
- package/dist/emissaoNota.d.ts +11 -6
- package/dist/emissaoNota.js +10 -6
- package/dist/emissaoNota.js.map +1 -1
- package/dist/eventoJson.d.ts +76 -0
- package/dist/eventoJson.js +128 -0
- package/dist/eventoJson.js.map +1 -0
- package/dist/eventosNfse.d.ts +38 -0
- package/dist/eventosNfse.js +73 -0
- package/dist/eventosNfse.js.map +1 -0
- package/dist/fiscalDomains.d.ts +22 -0
- package/dist/fiscalDomains.js +99 -0
- package/dist/fiscalDomains.js.map +1 -0
- package/dist/fiscalValidation.js +21 -53
- package/dist/fiscalValidation.js.map +1 -1
- package/dist/gzipB64.d.ts +5 -0
- package/dist/gzipB64.js +12 -0
- package/dist/gzipB64.js.map +1 -1
- package/dist/index.d.ts +22 -7
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/jsonSchemaCheck.d.ts +12 -0
- package/dist/jsonSchemaCheck.js +70 -0
- package/dist/jsonSchemaCheck.js.map +1 -0
- package/dist/loadPfx.d.ts +2 -0
- package/dist/loadPfx.js +2 -1
- package/dist/loadPfx.js.map +1 -1
- package/dist/mcpCli.d.ts +2 -0
- package/dist/mcpCli.js +7 -0
- package/dist/mcpCli.js.map +1 -0
- package/dist/mcpServer.d.ts +49 -0
- package/dist/mcpServer.js +159 -0
- package/dist/mcpServer.js.map +1 -0
- package/dist/nfseXml.d.ts +48 -0
- package/dist/nfseXml.js +86 -0
- package/dist/nfseXml.js.map +1 -0
- package/dist/rejeicoes.d.ts +50 -0
- package/dist/rejeicoes.js +62 -0
- package/dist/rejeicoes.js.map +1 -0
- package/dist/rejeicoesCatalog.d.ts +10 -0
- package/dist/rejeicoesCatalog.js +4449 -0
- package/dist/rejeicoesCatalog.js.map +1 -0
- package/dist/sefinClient.d.ts +107 -7
- package/dist/sefinClient.js +232 -22
- package/dist/sefinClient.js.map +1 -1
- package/dist/signXml.d.ts +3 -3
- package/dist/signXml.js +17 -7
- package/dist/signXml.js.map +1 -1
- package/dist/testing.d.ts +80 -0
- package/dist/testing.js +285 -0
- package/dist/testing.js.map +1 -0
- package/dist/xmlBuild.d.ts +11 -0
- package/dist/xmlBuild.js +44 -0
- package/dist/xmlBuild.js.map +1 -0
- package/dist/xmlInspection.d.ts +1 -1
- package/dist/xmlInspection.js +10 -9
- package/dist/xmlInspection.js.map +1 -1
- package/dist/xsdValidation.d.ts +24 -5
- package/dist/xsdValidation.js +97 -67
- package/dist/xsdValidation.js.map +1 -1
- package/docs/README.md +47 -0
- package/docs/REGRAS_NEGOCIO_EMISSAO.md +8 -8
- package/docs/conceitos/como-funciona.md +87 -0
- package/docs/guias/adn.md +51 -0
- package/docs/guias/agentes-ia.md +111 -0
- package/docs/guias/cancelar.md +70 -0
- package/docs/guias/certificado.md +88 -0
- package/docs/guias/cli.md +68 -0
- package/docs/guias/consultar.md +54 -0
- package/docs/guias/emitir.md +172 -0
- package/docs/guias/recuperar-emissao.md +33 -0
- package/docs/guias/rejeicoes.md +70 -0
- package/docs/guias/testes.md +79 -0
- package/docs/guias/timeouts.md +33 -0
- package/docs/referencia/ambientes.md +35 -0
- package/docs/referencia/api.md +137 -0
- package/docs/referencia/erros.md +55 -0
- package/docs/tutoriais/primeira-nfse.md +130 -0
- package/examples/README.md +3 -1
- package/examples/cancel-nfse.ts +29 -0
- package/examples/client-resource.ts +3 -5
- package/examples/emit-homologation.ts +3 -4
- package/examples/handle-errors.ts +3 -3
- package/examples/recover-emission.ts +29 -0
- package/llms.txt +97 -82
- package/package.json +31 -6
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Ambientes
|
|
2
|
+
|
|
3
|
+
| Chave | Alias no `NfseClient` | SEFIN (emissão, consulta, eventos) | ADN (DANFSe, distribuição, parâmetros) |
|
|
4
|
+
|---|---|---|---|
|
|
5
|
+
| `restrita` (padrão) | `sandbox` | `https://sefin.producaorestrita.nfse.gov.br/SefinNacional` | `https://adn.producaorestrita.nfse.gov.br` |
|
|
6
|
+
| `producao` | `production` | `https://sefin.nfse.gov.br/SefinNacional` | `https://adn.nfse.gov.br` |
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { resolveAdnBaseUrl, resolveSefinBaseUrl, TP_AMB } from '@useinvio/nfse-sdk';
|
|
10
|
+
|
|
11
|
+
resolveSefinBaseUrl('restrita'); // URL da SEFIN
|
|
12
|
+
resolveAdnBaseUrl('producao'); // URL do ADN
|
|
13
|
+
TP_AMB.restrita; // '2', valor de <tpAmb> no XML
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- `restrita` é a produção restrita oficial: as notas não têm validade jurídica,
|
|
17
|
+
mas passam pelas mesmas validações. Use-a para testes e homologação.
|
|
18
|
+
- O `tpAmb` dentro do XML precisa coincidir com o ambiente de envio; o SDK
|
|
19
|
+
recusa a divergência antes de transmitir.
|
|
20
|
+
- No `NfseClient`, o ambiente segue: opção da chamada → `defaults.ambiente` →
|
|
21
|
+
`environment` do construtor. O cliente não lembra o ambiente da última emissão.
|
|
22
|
+
|
|
23
|
+
## Endpoints usados
|
|
24
|
+
|
|
25
|
+
| Operação | Método e caminho | Serviço |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Emitir | `POST /nfse` | SEFIN |
|
|
28
|
+
| Consultar NFS-e | `GET /nfse/{chave}` | SEFIN |
|
|
29
|
+
| Consultar DPS | `GET /dps/{id}` | SEFIN |
|
|
30
|
+
| Registrar evento | `POST /nfse/{chave}/eventos` | SEFIN |
|
|
31
|
+
| Consultar evento | `GET /nfse/{chave}/eventos/{tpEvento}/{nSeqEvento}` | SEFIN |
|
|
32
|
+
| DANFSe | `GET /danfse/{chave}` | ADN |
|
|
33
|
+
| Distribuição | `GET /contribuintes/DFe/{nsu}` | ADN |
|
|
34
|
+
| Eventos por chave | `GET /contribuintes/NFSe/{chave}/Eventos` | ADN |
|
|
35
|
+
| Parâmetros municipais | `GET /parametrizacao/...` | ADN |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Referência da API
|
|
2
|
+
|
|
3
|
+
Tudo é importado da raiz do pacote, exceto as ferramentas de agente
|
|
4
|
+
(`@useinvio/nfse-sdk/agent`). `certificado` é um `NfseCertificate` (ou o legado
|
|
5
|
+
`PfxMaterial`); `ambiente` é `'restrita' | 'producao'` e o padrão é `restrita`;
|
|
6
|
+
`options` é [`SefinRequestOptions`](../guias/timeouts.md).
|
|
7
|
+
|
|
8
|
+
## Cliente
|
|
9
|
+
|
|
10
|
+
| API | Descrição |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `new NfseClient({ environment?, certificate, defaults?, request? })` | Configura certificado, ambiente, defaults do JSON e opções de transporte uma vez. |
|
|
13
|
+
| `client.invoices.create(input)` / `.buildDpsJson(input)` | Emite, ou só combina o JSON com os defaults. |
|
|
14
|
+
| `client.invoices.retrieve(chave)` / `.get(chave)` | Consulta tipada / crua. |
|
|
15
|
+
| `client.invoices.getByDpsId(dpsId)` / `.recover(dpsId)` | Consulta pela DPS / recuperação após timeout. |
|
|
16
|
+
| `client.invoices.cancel(input)` / `.cancelBySubstitution(input)` | Eventos e101101 / e105102. |
|
|
17
|
+
| `client.invoices.danfse(chave)` | PDF do DANFSe. |
|
|
18
|
+
| `client.events.get(chave, tpEvento, nSeq?)` / `.listByAccessKey(chave)` | Eventos (SEFIN / ADN). |
|
|
19
|
+
| `client.distribution.byNsu(nsu, opts?)` | Distribuição por NSU (ADN). |
|
|
20
|
+
| `client.municipalParameters.agreement/rate/rateHistory/specialRegimes/withholdings/benefit` | Parâmetros municipais (ADN). |
|
|
21
|
+
|
|
22
|
+
## Emissão
|
|
23
|
+
|
|
24
|
+
| Função | Descrição |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `emitirNfse(input, certificado, options?)` | Emite a partir de XML ou JSON. Retorna `ResultadoEmissaoNota`. |
|
|
27
|
+
| `prepararNota(input, certificado, options?)` | Valida, assina e verifica a assinatura, sem enviar. Retorna `NotaPreparada`. |
|
|
28
|
+
| `transmitirNotaPreparada(nota, certificado, options?)` | Envia uma `NotaPreparada`. |
|
|
29
|
+
| `buildDpsFromJson(nota)` / `buildDpsId(...)` | Monta o XML não assinado / o Id de 45 caracteres. |
|
|
30
|
+
| `validateDpsJsonRequest(nota)` / `assertValidDpsJsonRequest(nota)` | Valida o JSON, sem lançar / lançando `DpsFiscalValidationError`. |
|
|
31
|
+
| `validateDpsXmlAgainstXsd(xml)` | Valida a DPS contra o XSD oficial v1.01. |
|
|
32
|
+
| `DPS_JSON_REQUEST_SCHEMA` | JSON Schema 2020-12 do `DpsJsonRequest`. |
|
|
33
|
+
|
|
34
|
+
## Consulta
|
|
35
|
+
|
|
36
|
+
| Função | Descrição |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `obterNfse(chave, certificado, ambiente?, options?)` | `GET /nfse/{chave}` decodificado: `{ chaveAcesso, nfseXml, resumo }`. |
|
|
39
|
+
| `recuperarNfsePorDps(dpsId, certificado, ambiente?, options?)` | `GET /dps/{id}` + `GET /nfse/{chave}`; `null` se a DPS não existe. |
|
|
40
|
+
| `lerNfse(xml)` | Lê um XML de NFS-e autorizada em `NfseResumo`. |
|
|
41
|
+
| `decodificarRespostaNfse(status, body)` | Decodifica uma resposta crua de `GET /nfse/{chave}`. |
|
|
42
|
+
| `consultarNfse(...)` / `consultarDps(...)` | Respostas cruas `{ status, body }`. |
|
|
43
|
+
| `baixarDanfse(chave, certificado, ambiente?, options?)` | PDF do DANFSe (ADN). |
|
|
44
|
+
|
|
45
|
+
## Eventos
|
|
46
|
+
|
|
47
|
+
| Função | Descrição |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `cancelarNfse(input, certificado, options?)` | Cancelamento e101101. |
|
|
50
|
+
| `cancelarNfsePorSubstituicao(input, certificado, options?)` | Cancelamento por substituição e105102. |
|
|
51
|
+
| `buildCancelamentoFromJson(input)` / `buildCancelamentoPorSubstituicaoFromJson(input)` | Monta o pedido sem assinar. |
|
|
52
|
+
| `registrarEvento(built, certificado, options?)` | Valida, assina e envia um pedido montado. |
|
|
53
|
+
| `validatePedRegEventoXmlAgainstXsd(xml)` | Valida um pedido de evento contra o XSD. |
|
|
54
|
+
| `consultarEvento(chave, tpEvento, certificado, ambiente?, { nSeqEvento? })` | Consulta um evento (SEFIN). |
|
|
55
|
+
| `enviarEvento(xmlGZipB64, certificado, chave, ambiente?)` | Envia um pedido já assinado e compactado. |
|
|
56
|
+
| `TP_EVENTO`, `MOTIVO_CANCELAMENTO`, `MOTIVO_SUBSTITUICAO` | Códigos com nomes legíveis. |
|
|
57
|
+
|
|
58
|
+
## ADN
|
|
59
|
+
|
|
60
|
+
`distribuirDfePorNsu`, `consultarEventosPorChaveAdn`, `consultarConvenio`,
|
|
61
|
+
`consultarAliquota`, `consultarHistoricoAliquotas`, `consultarRegimesEspeciais`,
|
|
62
|
+
`consultarRetencoes`, `consultarBeneficio`. Assinaturas e endpoints em
|
|
63
|
+
[Distribuição e parâmetros municipais](../guias/adn.md).
|
|
64
|
+
|
|
65
|
+
## Linha de comando
|
|
66
|
+
|
|
67
|
+
`nfse` (bin): `init`, `doctor`, `cert`, `validate`, `xml`, `emit`, `get`, `danfse`,
|
|
68
|
+
`cancel`, `recover`, `explain`, `mcp`. Veja [Usar pelo terminal](../guias/cli.md).
|
|
69
|
+
|
|
70
|
+
## Rejeições
|
|
71
|
+
|
|
72
|
+
| Função | Descrição |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `explicarRejeicao(codigoOuErro)` | Mensagem, regra, campo e nível oficiais de um código, ou `conhecida: false`. |
|
|
75
|
+
| `explicarErros(erros)` | Explica todos os erros de uma rejeição. |
|
|
76
|
+
| `buscarRejeicao(codigo)` / `listarRejeicoes()` | Acesso direto ao catálogo oficial. |
|
|
77
|
+
| `REJEICOES_FONTES` | Anexos oficiais usados no catálogo, com URL. |
|
|
78
|
+
|
|
79
|
+
Uma página por código: [docs/rejeicoes](../rejeicoes/README.md).
|
|
80
|
+
|
|
81
|
+
## Testes (`@useinvio/nfse-sdk/testing`)
|
|
82
|
+
|
|
83
|
+
| Função | Descrição |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `createTestCertificate(opts?)` | Certificado A1 de teste com CNPJ/CPF nos campos ICP-Brasil. |
|
|
86
|
+
| `installMockSefin(opts?)` | SEFIN e ADN simulados no processo; `rejectNext`, `failNext`, `dropResponseNext`, `route`, `restore`. |
|
|
87
|
+
|
|
88
|
+
Guia: [Testar sem certificado](../guias/testes.md).
|
|
89
|
+
|
|
90
|
+
## Agentes e MCP
|
|
91
|
+
|
|
92
|
+
| API | Descrição |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `nfseAgentTools` (`/agent`) | Ferramentas só de leitura. |
|
|
95
|
+
| `createNfseAgentToolkit({ allowWrite?, confirmationTtlMs? })` (`/agent`) | Leitura + emissão e cancelamento em duas etapas. |
|
|
96
|
+
| `toAgentIssues(error)` (`/agent`) | Converte erros do SDK em issues para o modelo. |
|
|
97
|
+
| `createNfseMcpServer(opts)` / `runNfseMcpStdio(opts?)` (`/mcp`) | Servidor MCP sem dependências. |
|
|
98
|
+
| `nfse-mcp` (bin) | `npx -y @useinvio/nfse-mcp` ou `npx -y -p @useinvio/nfse-sdk nfse-mcp`. |
|
|
99
|
+
|
|
100
|
+
Guia: [Agentes de IA e MCP](../guias/agentes-ia.md).
|
|
101
|
+
|
|
102
|
+
## Certificado
|
|
103
|
+
|
|
104
|
+
| API | Descrição |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `NfseCertificate.fromEnv/fromFile/fromBase64/fromPfx/fromPem` | Carrega o A1 sem expor a chave privada. |
|
|
107
|
+
| `certificado.cnpj`, `.cpf`, `.notBefore`, `.notAfter`, `.fingerprintSha256` | Metadados públicos. |
|
|
108
|
+
| `certificado.isValidAt(data?)`, `.daysUntilExpiry()`, `.destroy()` | Vigência e descarte do agente mTLS. |
|
|
109
|
+
| `assertCertificateValidity(certificado, now?)` | Vigência; aplicada antes de assinar e de enviar. |
|
|
110
|
+
| `assertCertificateForProvider(certificado, documento, now?)` | Vigência e titular. |
|
|
111
|
+
| `NFSE_CERT_ENV` | Nomes das variáveis de ambiente lidas por `fromEnv`. |
|
|
112
|
+
| `loadPfx`, `loadPfxFromBuffer` | Legado: retornam a chave em PEM. |
|
|
113
|
+
|
|
114
|
+
## Baixo nível
|
|
115
|
+
|
|
116
|
+
| Função | Descrição |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `signDps(xml, dpsId, certificado)` / `signEnveloped(xml, id, elemento, certificado)` | Assinatura XMLDSIG. |
|
|
119
|
+
| `verifyDps(xml, certPem)` | Verifica uma assinatura. |
|
|
120
|
+
| `gzipBase64(xml)` / `gunzipBase64(b64)` / `gunzipBase64Flexivel(b64)` | Compactação. |
|
|
121
|
+
| `transmitirDpsCompactada(b64, certificado, ambiente?, options?)` | `POST /nfse` cru. |
|
|
122
|
+
| `extrairErros(body)` | Normaliza erros da SEFIN. |
|
|
123
|
+
| `assertChaveAcesso(chave)` / `assertDpsId(id)` | Validação de identificadores. |
|
|
124
|
+
| `resolveSefinBaseUrl(ambiente)` / `resolveAdnBaseUrl(ambiente)` | URLs base. |
|
|
125
|
+
| `setSefinRequestObserver(fn)` / `createSefinLatencyTracker(opts?)` | Métricas de latência ([METRICS.md](../METRICS.md)). |
|
|
126
|
+
|
|
127
|
+
## Constantes
|
|
128
|
+
|
|
129
|
+
`SEFIN_BASE_URL`, `ADN_BASE_URL`, `TP_AMB`, `DEFAULT_AMBIENTE`, `DPS_SCHEMA_VERSION`.
|
|
130
|
+
|
|
131
|
+
## Tipos
|
|
132
|
+
|
|
133
|
+
Os tipos públicos estão em [`index.ts`](../../index.ts). Os principais:
|
|
134
|
+
`DpsJsonRequest`, `ResultadoEmissaoNota`, `NotaPreparada`, `NfseConsultada`,
|
|
135
|
+
`NfseResumo`, `ResultadoEvento`, `CancelamentoNfseInput`,
|
|
136
|
+
`CancelamentoPorSubstituicaoInput`, `SefinRequestOptions`, `SefinResposta`,
|
|
137
|
+
`SefinErro`, `CertificateInput`, `NfseClientOptions`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Erros
|
|
2
|
+
|
|
3
|
+
Todos os erros estendem `Error` e têm `name` igual ao nome da classe. Como
|
|
4
|
+
tratar cada um: [Tratar rejeições e erros](../guias/rejeicoes.md).
|
|
5
|
+
|
|
6
|
+
## Antes de enviar (nada chegou à SEFIN)
|
|
7
|
+
|
|
8
|
+
| Classe | Campos | Quando |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `DpsFiscalValidationError` | `issues`, `report` | O JSON da DPS é inválido. Cada issue tem `code`, `path`, `severity`, `source`, `message`, `suggestion?`. |
|
|
11
|
+
| `DpsXsdValidationError` | `details` | O XML da DPS viola o XSD oficial v1.01. |
|
|
12
|
+
| `PedRegEventoXsdValidationError` | `details` | O pedido de evento viola o XSD oficial. |
|
|
13
|
+
| `EventoInvalidoError` | `code = 'EVENTO_INVALID'`, `field` | Entrada de evento inválida (chave, motivo, autor). |
|
|
14
|
+
| `CertificateValidationError` | `code` | Problema no A1; códigos abaixo. |
|
|
15
|
+
| `ChaveAcessoInvalidaError` | `code = 'CHAVE_ACESSO_INVALID_FORMAT'`, `chaveAcesso` | Chave sem exatamente 50 dígitos. |
|
|
16
|
+
| `SefinParametroInvalidoError` | `code = 'SEFIN_PARAMETER_INVALID'`, `field`, `value` | Id da DPS, tipo de evento, NSU, município ou outro parâmetro de caminho com formato errado. |
|
|
17
|
+
| `XsdEngineUnavailableError` | `cause` | O motor XSD (WebAssembly) falhou. Infraestrutura, não rejeição fiscal. |
|
|
18
|
+
|
|
19
|
+
### Códigos de `CertificateValidationError`
|
|
20
|
+
|
|
21
|
+
| `code` | Quando |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `CERTIFICATE_INVALID_PASSWORD` | Senha incorreta. |
|
|
24
|
+
| `CERTIFICATE_UNREADABLE` | O conteúdo não é um PFX/PEM válido. |
|
|
25
|
+
| `CERTIFICATE_MISSING` | `fromEnv` sem `NFSE_CERT_PATH` nem `NFSE_CERT_BASE64`. |
|
|
26
|
+
| `CERTIFICATE_PASSWORD_MISSING` | `fromEnv` sem `NFSE_CERT_PASSWORD` nem `NFSE_CERT_PASSWORD_FILE`. |
|
|
27
|
+
| `CERTIFICATE_NOT_YET_VALID` | Antes de `notBefore`. |
|
|
28
|
+
| `CERTIFICATE_EXPIRED` | Depois de `notAfter`. |
|
|
29
|
+
| `CERTIFICATE_HOLDER_MISMATCH` | O titular não é o CPF/CNPJ informado. |
|
|
30
|
+
|
|
31
|
+
## Depois de enviar (a SEFIN respondeu)
|
|
32
|
+
|
|
33
|
+
| Classe | Campos | Quando |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `EmitirNotaError` | `status`, `erros`, `dpsId`, `body` | Emissão rejeitada, ou HTTP 2xx sem XML autorizado (`INVALID_AUTHORIZATION_RESPONSE`). |
|
|
36
|
+
| `RegistrarEventoError` | `status`, `erros`, `pedRegEventoId`, `body` | Evento rejeitado. |
|
|
37
|
+
| `ConsultaNfseError` | `status`, `erros`, `body`, `notFound` | Consulta falhou; `notFound` para HTTP 404. |
|
|
38
|
+
|
|
39
|
+
`erros` é uma lista de `SefinErro` (`Codigo`, `Descricao`, `Complemento?`) com o
|
|
40
|
+
código oficial da SEFIN preservado.
|
|
41
|
+
|
|
42
|
+
## Erros de rede
|
|
43
|
+
|
|
44
|
+
Timeouts e falhas de conexão chegam como o `Error` original do Node (por exemplo
|
|
45
|
+
`ECONNRESET` ou `SEFIN request timed out after 60000ms`). Depois de um desses
|
|
46
|
+
numa emissão, o resultado é incerto: [recupere pela DPS](../guias/recuperar-emissao.md).
|
|
47
|
+
|
|
48
|
+
## Ferramentas de agente
|
|
49
|
+
|
|
50
|
+
`toAgentIssues(error)` converte os erros acima em issues com `code`, `path`,
|
|
51
|
+
`severity`, `source` e `suggestion`. Códigos próprios das ferramentas:
|
|
52
|
+
`UNSUPPORTED_FIELD`, `AMBIENTE_NOT_ALLOWED`, `CERTIFICATE_REQUIRED`,
|
|
53
|
+
`XSD_INVALID` e `SEFIN_REJECTED`. As ferramentas de escrita acrescentam
|
|
54
|
+
`CONFIRMATION_NOT_FOUND` (id desconhecido, usado ou expirado) e
|
|
55
|
+
`TRANSMISSION_UNCERTAIN` (falha de rede no envio; repita o confirm).
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Tutorial: sua primeira NFS-e na produção restrita
|
|
2
|
+
|
|
3
|
+
Neste tutorial você emite, consulta, baixa o DANFSe e cancela uma NFS-e na
|
|
4
|
+
produção restrita, o ambiente oficial de testes. Nada aqui tem validade jurídica.
|
|
5
|
+
Leva uns 15 minutos.
|
|
6
|
+
|
|
7
|
+
**Você vai precisar de:**
|
|
8
|
+
|
|
9
|
+
- Node.js 20.6 ou mais recente (para `--env-file`);
|
|
10
|
+
- um certificado A1 (`.pfx`) ICP-Brasil do prestador e a senha;
|
|
11
|
+
- o prestador habilitado no Emissor Nacional, com o município conveniado.
|
|
12
|
+
|
|
13
|
+
## 1. Crie o projeto
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mkdir minha-nfse && cd minha-nfse
|
|
17
|
+
npm init -y && npm pkg set type=module
|
|
18
|
+
npm install @useinvio/nfse-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 2. Configure o certificado
|
|
22
|
+
|
|
23
|
+
Copie o `.pfx` para a pasta e crie um `.env` (não versione nenhum dos dois):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
NFSE_CERT_PATH=./certificado.pfx
|
|
27
|
+
NFSE_CERT_PASSWORD=sua-senha
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Confira se o SDK lê o certificado:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node --env-file=.env -e "import('@useinvio/nfse-sdk').then(({ NfseCertificate }) => console.log(NfseCertificate.fromEnv()))"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A saída mostra só o CNPJ, a validade e o fingerprint, como
|
|
37
|
+
`NfseCertificate { cnpj=12345678000195, notAfter=..., fingerprintSha256=... }`.
|
|
38
|
+
Se aparecer `CERTIFICATE_INVALID_PASSWORD`, revise a senha.
|
|
39
|
+
|
|
40
|
+
## 3. Emita a nota
|
|
41
|
+
|
|
42
|
+
Crie `emitir.mjs`. Troque o CNPJ, os municípios (código IBGE) e os códigos de
|
|
43
|
+
serviço pelos do seu prestador; os valores abaixo são ilustrativos.
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { emitirNfse, EmitirNotaError, NfseCertificate } from '@useinvio/nfse-sdk';
|
|
47
|
+
|
|
48
|
+
const certificado = NfseCertificate.fromEnv();
|
|
49
|
+
|
|
50
|
+
const nota = {
|
|
51
|
+
ambiente: 'restrita',
|
|
52
|
+
prestador: {
|
|
53
|
+
cnpj: '12345678000195', // o CNPJ do certificado: certificado.cnpj
|
|
54
|
+
cLocEmi: '4106902',
|
|
55
|
+
serie: '1601',
|
|
56
|
+
opSimpNac: '1',
|
|
57
|
+
regEspTrib: '0',
|
|
58
|
+
},
|
|
59
|
+
servico: {
|
|
60
|
+
cTribNac: '010201',
|
|
61
|
+
xDescServ: 'Desenvolvimento de software',
|
|
62
|
+
cLocPrestacao: '4106902',
|
|
63
|
+
},
|
|
64
|
+
emissao: {
|
|
65
|
+
nDPS: '1',
|
|
66
|
+
valores: { vServ: '10.00' },
|
|
67
|
+
tributacaoMunicipal: { tribISSQN: '1', tpRetISSQN: '1' },
|
|
68
|
+
tributacaoFederal: { piscofins: { CST: '07' } },
|
|
69
|
+
totTrib: { pTotTribFed: '0.00', pTotTribEst: '0.00', pTotTribMun: '5.00' },
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const resultado = await emitirNfse(nota, certificado);
|
|
75
|
+
console.log('Chave de acesso:', resultado.chaveAcesso);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (!(error instanceof EmitirNotaError)) throw error;
|
|
78
|
+
for (const rejeicao of error.erros) console.error(rejeicao.Codigo, rejeicao.Descricao);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
node --env-file=.env emitir.mjs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Se a SEFIN rejeitar, a mensagem traz o código oficial da rejeição.
|
|
87
|
+
Corrija o campo indicado e rode de novo. Depois de uma emissão autorizada,
|
|
88
|
+
**incremente `nDPS`** para a próxima nota: cada número de DPS gera uma nota só.
|
|
89
|
+
|
|
90
|
+
## 4. Consulte e baixe o DANFSe
|
|
91
|
+
|
|
92
|
+
Crie `consultar.mjs` e passe a chave de acesso como argumento:
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
import { writeFile } from 'node:fs/promises';
|
|
96
|
+
import { baixarDanfse, NfseCertificate, obterNfse } from '@useinvio/nfse-sdk';
|
|
97
|
+
|
|
98
|
+
const certificado = NfseCertificate.fromEnv();
|
|
99
|
+
const chave = process.argv[2];
|
|
100
|
+
|
|
101
|
+
const nota = await obterNfse(chave, certificado, 'restrita');
|
|
102
|
+
console.log(nota.resumo.nNFSe, nota.resumo.cStat, nota.resumo.valores.vLiq);
|
|
103
|
+
|
|
104
|
+
const danfse = await baixarDanfse(chave, certificado, 'restrita');
|
|
105
|
+
if (danfse.pdf) await writeFile('danfse.pdf', danfse.pdf);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
node --env-file=.env consultar.mjs <chave-de-acesso>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 5. Cancele
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import { cancelarNfse, NfseCertificate } from '@useinvio/nfse-sdk';
|
|
116
|
+
|
|
117
|
+
const evento = await cancelarNfse(
|
|
118
|
+
{ ambiente: 'restrita', chaveAcesso: process.argv[2], cMotivo: '1', xMotivo: 'Teste de integracao do SDK' },
|
|
119
|
+
NfseCertificate.fromEnv(),
|
|
120
|
+
);
|
|
121
|
+
console.log('Cancelada:', evento.pedRegEventoId);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Próximos passos
|
|
125
|
+
|
|
126
|
+
- Leve o fluxo para a sua aplicação: [Emitir uma NFS-e](../guias/emitir.md).
|
|
127
|
+
- Proteja-se de timeouts: [Recuperar uma emissão](../guias/recuperar-emissao.md).
|
|
128
|
+
- Entenda o que acontece por baixo: [Como o SDK funciona](../conceitos/como-funciona.md).
|
|
129
|
+
- Antes de ir para `producao`, revise a [matriz fiscal](../FISCAL_MATRIX.md) com
|
|
130
|
+
quem cuida da parte tributária.
|
package/examples/README.md
CHANGED
|
@@ -11,5 +11,7 @@ The payloads in `payloads.ts` are shared by these examples and exercised by the
|
|
|
11
11
|
- [`emit-homologation.ts`](./emit-homologation.ts): emit in the restricted/sandbox SEFIN environment.
|
|
12
12
|
- [`client-resource.ts`](./client-resource.ts): use `NfseClient` with certificate and defaults configured once.
|
|
13
13
|
- [`handle-errors.ts`](./handle-errors.ts): normalize SEFIN rejection details for your application.
|
|
14
|
+
- [`cancel-nfse.ts`](./cancel-nfse.ts): download the DANFSe PDF and cancel an NFS-e (event e101101).
|
|
15
|
+
- [`recover-emission.ts`](./recover-emission.ts): recover an emission after a timeout with `GET /dps/{id}` instead of resending.
|
|
14
16
|
|
|
15
|
-
The examples assume Node.js 20+ and a valid A1/PFX certificate. They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
|
|
17
|
+
The examples assume Node.js 20+ and a valid A1/PFX certificate, loaded with `NfseCertificate.fromEnv()` from `NFSE_CERT_PATH` (or `NFSE_CERT_BASE64`) and `NFSE_CERT_PASSWORD` (or `NFSE_CERT_PASSWORD_FILE`). They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { NfseCertificate, NfseClient, RegistrarEventoError } from '@useinvio/nfse-sdk';
|
|
3
|
+
|
|
4
|
+
async function archiveAndCancel(chaveAcesso: string) {
|
|
5
|
+
const client = new NfseClient({
|
|
6
|
+
environment: 'sandbox',
|
|
7
|
+
certificate: NfseCertificate.fromEnv(), // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
|
|
8
|
+
request: { timeoutMs: 30_000, retries: 2 }, // retries apply to GETs only
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Keep the official DANFSe PDF before cancelling.
|
|
12
|
+
const danfse = await client.invoices.danfse(chaveAcesso);
|
|
13
|
+
if (danfse.pdf) await writeFile(`danfse-${chaveAcesso}.pdf`, danfse.pdf);
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// `autor` defaults to the certificate holder's CNPJ/CPF.
|
|
17
|
+
const evento = await client.invoices.cancel({
|
|
18
|
+
chaveAcesso,
|
|
19
|
+
cMotivo: '1', // 1 = erro na emissao, 2 = servico nao prestado, 9 = outros
|
|
20
|
+
xMotivo: 'Nota emitida com valor incorreto',
|
|
21
|
+
});
|
|
22
|
+
console.log('Evento registrado:', evento.pedRegEventoId);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (!(error instanceof RegistrarEventoError)) throw error;
|
|
25
|
+
console.error('Cancelamento rejeitado:', error.status, error.erros);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void archiveAndCancel(process.argv[2] ?? '0'.repeat(50));
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { NfseClient } from '@useinvio/nfse-sdk';
|
|
1
|
+
import { NfseCertificate, NfseClient } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
4
|
const client = new NfseClient({
|
|
5
5
|
environment: 'sandbox',
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
password: process.env.NFSE_CERTIFICATE_PASSWORD!,
|
|
9
|
-
},
|
|
6
|
+
// NFSE_CERT_PATH or NFSE_CERT_BASE64, plus NFSE_CERT_PASSWORD or NFSE_CERT_PASSWORD_FILE
|
|
7
|
+
certificate: NfseCertificate.fromEnv(),
|
|
10
8
|
defaults: { prestador: nationalInvoice.prestador, servico: nationalInvoice.servico },
|
|
11
9
|
});
|
|
12
10
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { EmitirNotaError, emitirNfse,
|
|
1
|
+
import { EmitirNotaError, emitirNfse, NfseCertificate } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
|
|
6
5
|
|
|
7
6
|
try {
|
|
8
|
-
const resultado = await emitirNfse(nationalInvoice,
|
|
7
|
+
const resultado = await emitirNfse(nationalInvoice, certificate);
|
|
9
8
|
console.log(resultado.chaveAcesso);
|
|
10
9
|
console.log(resultado.nfseXml);
|
|
11
10
|
} catch (error) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { EmitirNotaError, emitirNfse,
|
|
1
|
+
import { EmitirNotaError, emitirNfse, NfseCertificate, type DpsJsonRequest } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
4
|
async function emitWithStructuredErrors(nota: DpsJsonRequest) {
|
|
5
|
-
const
|
|
5
|
+
const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
|
|
6
6
|
|
|
7
7
|
try {
|
|
8
|
-
return await emitirNfse(nota,
|
|
8
|
+
return await emitirNfse(nota, certificate);
|
|
9
9
|
} catch (error) {
|
|
10
10
|
if (!(error instanceof EmitirNotaError)) throw error;
|
|
11
11
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NfseCertificate,
|
|
3
|
+
prepararNota,
|
|
4
|
+
recuperarNfsePorDps,
|
|
5
|
+
transmitirNotaPreparada,
|
|
6
|
+
type DpsJsonRequest,
|
|
7
|
+
} from '@useinvio/nfse-sdk';
|
|
8
|
+
import { nationalInvoice } from './payloads.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Safe emission: persist the signed DPS before sending, and after a timeout ask
|
|
12
|
+
* SEFIN whether the DPS was processed instead of sending it again.
|
|
13
|
+
*/
|
|
14
|
+
async function emitIdempotently(nota: DpsJsonRequest) {
|
|
15
|
+
const certificate = NfseCertificate.fromEnv();
|
|
16
|
+
const prepared = prepararNota(nota, certificate);
|
|
17
|
+
// await db.save(prepared.dpsId, prepared.signedXml);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
return await transmitirNotaPreparada(prepared, certificate, { timeoutMs: 30_000 });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (error instanceof Error && error.name === 'EmitirNotaError') throw error; // SEFIN answered: a real rejection
|
|
23
|
+
const existing = await recuperarNfsePorDps(prepared.dpsId, certificate, prepared.ambiente, { retries: 3 });
|
|
24
|
+
if (existing) return existing; // authorized before the connection dropped
|
|
25
|
+
return transmitirNotaPreparada(prepared, certificate); // never reached SEFIN: same DPS, same Id
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void emitIdempotently(nationalInvoice);
|