@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/services/client.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* cancelamento por substituição, CC-e, manifestação do destinatário no AN), inutilização, consulta cadastro e
|
|
5
5
|
* Distribuição DF-e. Contingência SVC por dado: o autorizador SVC-AN ou SVC-RS de cada UF vem do `@sinete/transport`.
|
|
6
6
|
*
|
|
7
|
-
* Todo desfecho que chega a uma resposta da SEFAZ é um `
|
|
7
|
+
* Todo desfecho que chega a uma resposta da SEFAZ é um `ResultadoSefaz` do core (autorizado, rejeitado, denegado,
|
|
8
8
|
* pendente), com a dica do `@sinete/rejeicoes` na rejeição. Os documentos processados (`nfeProc`, `procEventoNFe`,
|
|
9
9
|
* `ProcInutNFe`) são montados por splice: o XML assinado entra byte a byte, o protocolo entra como fatia da resposta.
|
|
10
10
|
*
|
|
@@ -13,23 +13,23 @@
|
|
|
13
13
|
* número. Consulte a chave (`resolverEnvioSemResposta`) e, se ela não constar, reenvie exatamente os mesmos bytes.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import type { Ambiente,
|
|
16
|
+
import type { Ambiente, Assinador, CUf, Logger, Relogio, ResultadoSefaz, Uf } from '@sinete/core';
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
criarAutorizado,
|
|
19
|
+
criarDenegado,
|
|
20
|
+
criarPendente,
|
|
21
|
+
ErroDeConfiguracao,
|
|
22
|
+
ErroDeValidacao,
|
|
23
|
+
ErroRespostaInvalida,
|
|
24
|
+
loggerSilencioso,
|
|
25
|
+
tpAmbDoAmbiente,
|
|
26
|
+
ufPorCUf,
|
|
27
|
+
ufPorSigla,
|
|
28
28
|
} from '@sinete/core';
|
|
29
|
-
import type {
|
|
30
|
-
import {
|
|
31
|
-
import type { ComplexType,
|
|
32
|
-
import {
|
|
29
|
+
import type { DocumentoXml, ElementoXml } from '@sinete/core/xml';
|
|
30
|
+
import { assinarXml, elementosFilhos, lerXml, primeiroFilho, textoDe } from '@sinete/core/xml';
|
|
31
|
+
import type { ComplexType, OcorrenciaSchema } from '@sinete/schemas';
|
|
32
|
+
import { decodificar, decodificarXml, serializar, serializarRaiz, validar } from '@sinete/schemas';
|
|
33
33
|
import type { TRetConsCad_infCons_infCad } from '@sinete/schemas/nfe/consulta-cadastro/PL_010d';
|
|
34
34
|
import { ConsCadElement, TRetConsCad } from '@sinete/schemas/nfe/consulta-cadastro/PL_010d';
|
|
35
35
|
import { consSitNFeElement, TProtNFe, TRetConsSitNFe } from '@sinete/schemas/nfe/consulta-protocolo/PL_010d';
|
|
@@ -52,15 +52,15 @@ import { TEvento_infEvento as TEventoNaoRealizada } from '@sinete/schemas/nfe/ev
|
|
|
52
52
|
import { TInutNFe_infInut, TRetInutNFe } from '@sinete/schemas/nfe/inutilizacao/PL_010d';
|
|
53
53
|
import { TRetConsReciNFe, TRetEnviNFe } from '@sinete/schemas/nfe/PL_010f';
|
|
54
54
|
import { consStatServElement, TRetConsStatServ } from '@sinete/schemas/nfe/status-servico/PL_009q';
|
|
55
|
-
import type {
|
|
55
|
+
import type { EndpointResolvido, NfeServico, Transporte } from '@sinete/transport';
|
|
56
56
|
import { nfceEndpoint, nfeContingenciaDaUf, nfeEndpoint } from '@sinete/transport';
|
|
57
57
|
import type { ChaveAcesso } from '@sinete/validators';
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
60
|
-
import {
|
|
58
|
+
import { lerChaveAcesso, lerCnpj, lerCpf } from '@sinete/validators';
|
|
59
|
+
import { deslocamentoDaUf, formatarDh } from '../time.ts';
|
|
60
|
+
import { descomprimirGzipBase64 } from './gzip.ts';
|
|
61
61
|
import { cstatEm, rejeitado } from './outcome.ts';
|
|
62
62
|
import type { DocumentoAssinado } from './proc.ts';
|
|
63
|
-
import { documentoAssinado, envelope, NFE_NS,
|
|
63
|
+
import { documentoAssinado, envelope, NFE_NS, recortarElemento } from './proc.ts';
|
|
64
64
|
import type { RespostaSoap } from './soap.ts';
|
|
65
65
|
import { chamar } from './soap.ts';
|
|
66
66
|
|
|
@@ -74,27 +74,27 @@ export type AutorDocumento =
|
|
|
74
74
|
| { readonly CPF: string; readonly CNPJ?: never };
|
|
75
75
|
|
|
76
76
|
/** Espera injetável (testes passam uma que não dorme). */
|
|
77
|
-
export type
|
|
77
|
+
export type Espera = (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
78
78
|
|
|
79
|
-
export interface
|
|
80
|
-
readonly
|
|
79
|
+
export interface ClienteNfeOpcoes {
|
|
80
|
+
readonly transporte: Transporte;
|
|
81
81
|
/** Assina NF-e, eventos e inutilização (A1 WebCrypto, A3 via PKCS#11, HSM). */
|
|
82
|
-
readonly
|
|
82
|
+
readonly assinador: Assinador;
|
|
83
83
|
readonly ambiente: Ambiente;
|
|
84
84
|
/**
|
|
85
85
|
* UF dos serviços que não partem de um documento: status do serviço, inutilização, recibo consultado sem a NF-e,
|
|
86
86
|
* `cUFAutor` padrão da distribuição e fuso da manifestação. Autorização, consulta, recibo com a NF-e e eventos da
|
|
87
87
|
* própria nota vão ao autorizador da chave (cUF e tpEmis), seja qual for esta UF; sem ela, os serviços que precisam
|
|
88
|
-
* dela lançam `
|
|
88
|
+
* dela lançam `ErroDeConfiguracao`.
|
|
89
89
|
*/
|
|
90
90
|
readonly uf?: Uf;
|
|
91
91
|
/** Relógio de emissão: `dhEvento`, número do lote. */
|
|
92
|
-
readonly
|
|
92
|
+
readonly relogio: Relogio;
|
|
93
93
|
readonly logger?: Logger;
|
|
94
94
|
/** Prazo por requisição; padrão o do transporte. */
|
|
95
95
|
readonly timeoutMs?: number;
|
|
96
96
|
/** Fuso do emitente em minutos; padrão o da UF da chave nos eventos e o de `uf` na manifestação (`data/fusos.json`). */
|
|
97
|
-
readonly
|
|
97
|
+
readonly deslocamentoMin?: number;
|
|
98
98
|
/**
|
|
99
99
|
* `svc`: o status do serviço e o recibo consultado sem a NF-e vão ao SVC-AN ou SVC-RS de `uf`. Não vale para o que
|
|
100
100
|
* parte de um documento: a NF-e assinada em SVC (tpEmis 6 ou 7, na chave) vai ao SVC que a chave diz, e a assinada
|
|
@@ -103,21 +103,25 @@ export interface NfeClientOptions {
|
|
|
103
103
|
readonly contingencia?: 'svc';
|
|
104
104
|
/** CNPJ ou CPF do titular do certificado: autor da manifestação, interessado da distribuição, emitente da inutilização. */
|
|
105
105
|
readonly autor?: AutorDocumento;
|
|
106
|
-
readonly
|
|
106
|
+
readonly esperar?: Espera;
|
|
107
107
|
/**
|
|
108
108
|
* Sobrepõe o endpoint da NFC-e (modelo 65) por serviço e UF. Sem ela, vale a tabela da NFC-e do `@sinete/transport`
|
|
109
109
|
* (`nfceEndpoint`), que em várias UFs (SP, MG, PR, RS, SVRS) é outro host que o da NF-e. A NFC-e não tem SVC: com
|
|
110
110
|
* `contingencia: 'svc'`, o documento modelo 65 continua indo ao autorizador normal da NFC-e.
|
|
111
111
|
*/
|
|
112
|
-
readonly
|
|
112
|
+
readonly endpointNfce?: (servico: NfeServico, uf: Uf) => EndpointResolvido;
|
|
113
113
|
/** Gerador de `idLote` (até 15 dígitos); padrão: os milissegundos do relógio. */
|
|
114
114
|
readonly idLote?: () => string;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
/** Opções
|
|
118
|
-
export interface
|
|
117
|
+
/** Opções de toda chamada que vai à rede. */
|
|
118
|
+
export interface EnvioOpcoes {
|
|
119
119
|
/** Cancela a requisição em curso. */
|
|
120
120
|
readonly signal?: AbortSignal;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Opções da consulta de um recibo. */
|
|
124
|
+
export interface ConsultaReciboOpcoes extends EnvioOpcoes {
|
|
121
125
|
/**
|
|
122
126
|
* Modelo do lote, para escolher o serviço (NFC-e vai pelo `nfceEndpoint`). Com a NF-e assinada o modelo vem da
|
|
123
127
|
* chave e este campo, se vier, tem de bater; sem ela, é obrigatório para NFC-e e o padrão é 55.
|
|
@@ -170,8 +174,8 @@ export interface ProtocoloNfe {
|
|
|
170
174
|
readonly nfeProc?: string;
|
|
171
175
|
}
|
|
172
176
|
|
|
173
|
-
/** Desfecho da autorização: autorizada, denegada (número consumido), rejeitada ou pendente (recibo em `
|
|
174
|
-
export type
|
|
177
|
+
/** Desfecho da autorização: autorizada, denegada (número consumido), rejeitada ou pendente (recibo em `referencia`). */
|
|
178
|
+
export type ResultadoAutorizacao = ResultadoSefaz<ProtocoloNfe, ProtocoloNfe>;
|
|
175
179
|
|
|
176
180
|
/** Situação da NF-e na consulta protocolo. */
|
|
177
181
|
export interface ConsultaNfe {
|
|
@@ -184,7 +188,7 @@ export interface ConsultaNfe {
|
|
|
184
188
|
readonly digValConfere?: boolean;
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
export type
|
|
191
|
+
export type ResultadoConsulta = ResultadoSefaz<ConsultaNfe, ConsultaNfe>;
|
|
188
192
|
|
|
189
193
|
/** Evento registrado (cStat 135, 136 ou 155). */
|
|
190
194
|
export interface EventoRegistrado {
|
|
@@ -199,7 +203,7 @@ export interface EventoRegistrado {
|
|
|
199
203
|
readonly procEventoNFe: string;
|
|
200
204
|
}
|
|
201
205
|
|
|
202
|
-
export type
|
|
206
|
+
export type ResultadoEvento = ResultadoSefaz<EventoRegistrado, never>;
|
|
203
207
|
|
|
204
208
|
/** Inutilização homologada (cStat 102). */
|
|
205
209
|
export interface Inutilizacao {
|
|
@@ -209,7 +213,7 @@ export interface Inutilizacao {
|
|
|
209
213
|
readonly procInutNFe: string;
|
|
210
214
|
}
|
|
211
215
|
|
|
212
|
-
export type
|
|
216
|
+
export type ResultadoInutilizacao = ResultadoSefaz<Inutilizacao, never>;
|
|
213
217
|
|
|
214
218
|
export interface Cadastro {
|
|
215
219
|
readonly UF: string;
|
|
@@ -238,11 +242,15 @@ export interface Distribuicao {
|
|
|
238
242
|
|
|
239
243
|
export type ManifestacaoTipo = 'ciencia' | 'confirmacao' | 'desconhecimento' | 'nao-realizada';
|
|
240
244
|
|
|
241
|
-
export interface AutorizarOpcoes {
|
|
245
|
+
export interface AutorizarOpcoes extends EnvioOpcoes {
|
|
242
246
|
/** `indSinc` 1 (padrão) ou 0 (lote assíncrono com recibo). */
|
|
243
247
|
readonly sincrono?: boolean;
|
|
244
|
-
|
|
245
|
-
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Opções do status do serviço. */
|
|
251
|
+
export interface StatusServicoOpcoes extends EnvioOpcoes {
|
|
252
|
+
/** `65` consulta o autorizador da NFC-e. Padrão 55. */
|
|
253
|
+
readonly mod?: '55' | '65';
|
|
246
254
|
}
|
|
247
255
|
|
|
248
256
|
export interface CancelamentoPedido {
|
|
@@ -303,38 +311,38 @@ export type DistribuicaoConsulta =
|
|
|
303
311
|
| { readonly NSU: string | number }
|
|
304
312
|
| { readonly chNFe: string };
|
|
305
313
|
|
|
306
|
-
export interface DistribuicaoOpcoes {
|
|
314
|
+
export interface DistribuicaoOpcoes extends EnvioOpcoes {
|
|
307
315
|
/** UF do interessado; padrão a UF do cliente. */
|
|
308
316
|
readonly cUFAutor?: string;
|
|
309
317
|
readonly autor?: AutorDocumento;
|
|
310
318
|
}
|
|
311
319
|
|
|
312
|
-
export interface
|
|
313
|
-
readonly
|
|
320
|
+
export interface ClienteNfe {
|
|
321
|
+
readonly opcoes: ClienteNfeOpcoes;
|
|
314
322
|
/**
|
|
315
323
|
* Status do serviço de autorização na UF das opções (MOC 7.0, tabela 4.4.1: 107 em operação, 108 e 109 paralisado).
|
|
316
324
|
* Com `mod: '65'`, o do autorizador da NFC-e, que em várias UFs é outro host.
|
|
317
325
|
*/
|
|
318
|
-
statusServico(opcoes?:
|
|
326
|
+
statusServico(opcoes?: StatusServicoOpcoes): Promise<ResultadoSefaz<StatusServico, never>>;
|
|
319
327
|
/** Envia uma NF-e assinada (a string devolvida pela assinatura, sem outra alteração). Padrão síncrono. */
|
|
320
|
-
autorizar(nfeAssinada: string, opcoes?: AutorizarOpcoes): Promise<
|
|
328
|
+
autorizar(nfeAssinada: string, opcoes?: AutorizarOpcoes): Promise<ResultadoAutorizacao>;
|
|
321
329
|
/** Consulta o recibo de um lote assíncrono; com a NF-e assinada, monta o `nfeProc`. */
|
|
322
|
-
consultarRecibo(nRec: string, nfeAssinada?: string, opcoes?: ConsultaReciboOpcoes): Promise<
|
|
330
|
+
consultarRecibo(nRec: string, nfeAssinada?: string, opcoes?: ConsultaReciboOpcoes): Promise<ResultadoAutorizacao>;
|
|
323
331
|
/** Consulta o recibo até sair de pendente ou esgotar a política. */
|
|
324
|
-
aguardarRecibo(nRec: string, nfeAssinada?: string, politica?: PoliticaRecibo): Promise<
|
|
325
|
-
consultar(chave: string, nfeAssinada?: string): Promise<
|
|
326
|
-
cancelar(p: CancelamentoPedido): Promise<
|
|
332
|
+
aguardarRecibo(nRec: string, nfeAssinada?: string, politica?: PoliticaRecibo): Promise<ResultadoAutorizacao>;
|
|
333
|
+
consultar(chave: string, nfeAssinada?: string, opcoes?: EnvioOpcoes): Promise<ResultadoConsulta>;
|
|
334
|
+
cancelar(p: CancelamentoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento>;
|
|
327
335
|
/** Cancelamento por substituição (110112): só NFC-e (modelo 65). */
|
|
328
|
-
cancelarPorSubstituicao(p: CancelamentoSubstituicaoPedido): Promise<
|
|
329
|
-
cartaCorrecao(p: CartaCorrecaoPedido): Promise<
|
|
336
|
+
cancelarPorSubstituicao(p: CancelamentoSubstituicaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento>;
|
|
337
|
+
cartaCorrecao(p: CartaCorrecaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento>;
|
|
330
338
|
/** Manifestação do destinatário, registrada no Ambiente Nacional (cOrgao 91). */
|
|
331
|
-
manifestar(p: ManifestacaoPedido): Promise<
|
|
332
|
-
inutilizar(p: InutilizacaoPedido): Promise<
|
|
333
|
-
consultarCadastro(p: CadastroPedido): Promise<
|
|
339
|
+
manifestar(p: ManifestacaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento>;
|
|
340
|
+
inutilizar(p: InutilizacaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoInutilizacao>;
|
|
341
|
+
consultarCadastro(p: CadastroPedido, opcoes?: EnvioOpcoes): Promise<ResultadoSefaz<Cadastro, never>>;
|
|
334
342
|
distribuicaoDFe(
|
|
335
343
|
consulta: DistribuicaoConsulta,
|
|
336
344
|
opcoes?: DistribuicaoOpcoes,
|
|
337
|
-
): Promise<
|
|
345
|
+
): Promise<ResultadoSefaz<Distribuicao, never>>;
|
|
338
346
|
}
|
|
339
347
|
|
|
340
348
|
// ---------------------------------------------------------------------------------------------------------------
|
|
@@ -350,7 +358,7 @@ export function autorizadorContingencia(
|
|
|
350
358
|
return { autorizador, tpEmis: autorizador === 'SVC-AN' ? '6' : '7' };
|
|
351
359
|
}
|
|
352
360
|
|
|
353
|
-
const defaultSleep:
|
|
361
|
+
const defaultSleep: Espera = (ms: number, signal?: AbortSignal): Promise<void> =>
|
|
354
362
|
new Promise<void>((resolve, reject) => {
|
|
355
363
|
if (signal?.aborted) {
|
|
356
364
|
reject(signal.reason);
|
|
@@ -369,28 +377,28 @@ const defaultSleep: Sleep = (ms: number, signal?: AbortSignal): Promise<void> =>
|
|
|
369
377
|
});
|
|
370
378
|
|
|
371
379
|
function chaveValida(chave: string, path: string): ChaveAcesso {
|
|
372
|
-
const r =
|
|
373
|
-
if (!r.ok) throw new
|
|
374
|
-
return r.
|
|
380
|
+
const r = lerChaveAcesso(chave, { caminho: path });
|
|
381
|
+
if (!r.ok) throw new ErroDeValidacao(`chave de acesso inválida: ${r.erro.mensagem}`, [r.erro]);
|
|
382
|
+
return r.valor;
|
|
375
383
|
}
|
|
376
384
|
|
|
377
|
-
function schemaIssues(what: string, issues: readonly
|
|
378
|
-
if (issues.length > 0) throw new
|
|
385
|
+
function schemaIssues(what: string, issues: readonly OcorrenciaSchema[]): void {
|
|
386
|
+
if (issues.length > 0) throw new ErroDeValidacao(`${what} não confere com o schema`, issues);
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
function documentoAutor(a: AutorDocumento, path: string): { CNPJ: string } | { CPF: string } {
|
|
382
390
|
if (a.CNPJ !== undefined) {
|
|
383
|
-
const r =
|
|
384
|
-
if (!r.ok) throw new
|
|
385
|
-
return { CNPJ: r.
|
|
391
|
+
const r = lerCnpj(a.CNPJ, { caminho: `${path}.CNPJ` });
|
|
392
|
+
if (!r.ok) throw new ErroDeValidacao('CNPJ do autor inválido', [r.erro]);
|
|
393
|
+
return { CNPJ: r.valor };
|
|
386
394
|
}
|
|
387
|
-
const r =
|
|
388
|
-
if (!r.ok) throw new
|
|
389
|
-
return { CPF: r.
|
|
395
|
+
const r = lerCpf(a.CPF ?? '', { caminho: `${path}.CPF` });
|
|
396
|
+
if (!r.ok) throw new ErroDeValidacao('CPF do autor inválido', [r.erro]);
|
|
397
|
+
return { CPF: r.valor };
|
|
390
398
|
}
|
|
391
399
|
|
|
392
400
|
function autorDaChave(c: ChaveAcesso): { CNPJ: string } | { CPF: string } {
|
|
393
|
-
//
|
|
401
|
+
// lerChaveAcesso já exigiu CNPJ ou "000" + CPF válido nas 14 posições do emitente.
|
|
394
402
|
return c.cnpj !== undefined ? { CNPJ: c.cnpj } : { CPF: c.cpf ?? c.emitente.slice(3) };
|
|
395
403
|
}
|
|
396
404
|
|
|
@@ -404,11 +412,11 @@ function autorDoEmitente(a: AutorDocumento | undefined, c: ChaveAcesso): { CNPJ:
|
|
|
404
412
|
const autor = documentoAutor(a, 'autor');
|
|
405
413
|
const [campo, valor] = 'CNPJ' in autor ? ['CNPJ', autor.CNPJ] : ['CPF', autor.CPF];
|
|
406
414
|
if (valor !== ('CNPJ' in daChave ? daChave.CNPJ : daChave.CPF) || campo !== ('CNPJ' in daChave ? 'CNPJ' : 'CPF')) {
|
|
407
|
-
throw new
|
|
415
|
+
throw new ErroDeValidacao('o autor do evento não é o emitente da NF-e', [
|
|
408
416
|
{
|
|
409
|
-
|
|
417
|
+
caminho: `autor.${campo}`,
|
|
410
418
|
code: 'autor_difere_do_emitente',
|
|
411
|
-
|
|
419
|
+
mensagem: `o autor de um evento do emitente é o ${'CNPJ' in daChave ? 'CNPJ' : 'CPF'} da chave (P12-44, rejeição 574)`,
|
|
412
420
|
origem: 'entrada',
|
|
413
421
|
},
|
|
414
422
|
]);
|
|
@@ -424,14 +432,14 @@ const SVC_DO_TPEMIS: Readonly<Record<string, 'SVC-AN' | 'SVC-RS'>> = { '6': 'SVC
|
|
|
424
432
|
|
|
425
433
|
/** Chave do documento assinado, lida para rotear: o emitente é conferido pela SEFAZ, não aqui. */
|
|
426
434
|
function chaveDoDocumento(a: DocumentoAssinado): ChaveAcesso {
|
|
427
|
-
const r =
|
|
428
|
-
if (!r.ok) throw new
|
|
429
|
-
return r.
|
|
435
|
+
const r = lerChaveAcesso(a.id.slice(3), { caminho: 'infNFe.Id', conferirEmitente: false });
|
|
436
|
+
if (!r.ok) throw new ErroDeConfiguracao(`Id da NF-e assinada não é uma chave de acesso: ${r.erro.mensagem}`);
|
|
437
|
+
return r.valor;
|
|
430
438
|
}
|
|
431
439
|
|
|
432
440
|
/** Fatia autossuficiente (com o `xmlns` do elemento), para devolver ao chamador fora de um envelope. */
|
|
433
|
-
function avulso(doc:
|
|
434
|
-
return
|
|
441
|
+
function avulso(doc: DocumentoXml, el: ElementoXml): string {
|
|
442
|
+
return recortarElemento(doc, el, '');
|
|
435
443
|
}
|
|
436
444
|
|
|
437
445
|
/** Protocolo lido e a fatia sem `xmlns` redundante, para entrar no `nfeProc`. */
|
|
@@ -441,10 +449,10 @@ interface ProtocoloLido {
|
|
|
441
449
|
}
|
|
442
450
|
|
|
443
451
|
/** Monta o protocolo a partir do `protNFe` da resposta. */
|
|
444
|
-
function lerProtocolo(doc:
|
|
445
|
-
const { value } =
|
|
452
|
+
function lerProtocolo(doc: DocumentoXml, el: ElementoXml): ProtocoloLido {
|
|
453
|
+
const { valor: value } = decodificar(TProtNFe, el, doc.texto);
|
|
446
454
|
const inf = value.infProt;
|
|
447
|
-
if (!inf) throw new
|
|
455
|
+
if (!inf) throw new ErroRespostaInvalida('protNFe sem infProt');
|
|
448
456
|
const p = {
|
|
449
457
|
chNFe: inf.chNFe,
|
|
450
458
|
cStat: inf.cStat,
|
|
@@ -455,15 +463,15 @@ function lerProtocolo(doc: XmlDocument, el: XmlElement): ProtocoloLido {
|
|
|
455
463
|
...(inf.nProt === undefined ? {} : { nProt: inf.nProt }),
|
|
456
464
|
...(inf.digVal === undefined ? {} : { digVal: inf.digVal }),
|
|
457
465
|
};
|
|
458
|
-
return { p, embutido:
|
|
466
|
+
return { p, embutido: recortarElemento(doc, el) };
|
|
459
467
|
}
|
|
460
468
|
|
|
461
469
|
/**
|
|
462
470
|
* Protocolo de uma NF-e que este cliente enviou: o `digVal` tem de ser o DigestValue da nota assinada, senão o
|
|
463
|
-
* protocolo é de outro conteúdo e nenhum `nfeProc` é montado (`
|
|
471
|
+
* protocolo é de outro conteúdo e nenhum `nfeProc` é montado (`ErroRespostaInvalida`). Sem `digVal` não há como provar que o
|
|
464
472
|
* protocolo é deste conteúdo: o desfecho volta sem `nfeProc` (confirme com `consultar`).
|
|
465
473
|
*/
|
|
466
|
-
function desfechoDoProtocolo({ p, embutido }: ProtocoloLido, a: DocumentoAssinado | undefined):
|
|
474
|
+
function desfechoDoProtocolo({ p, embutido }: ProtocoloLido, a: DocumentoAssinado | undefined): ResultadoAutorizacao {
|
|
467
475
|
const status = { cStat: p.cStat, xMotivo: p.xMotivo };
|
|
468
476
|
const autorizada = cstatEm(p.cStat, 'autorizada');
|
|
469
477
|
const denegada = cstatEm(p.cStat, 'denegada');
|
|
@@ -471,27 +479,27 @@ function desfechoDoProtocolo({ p, embutido }: ProtocoloLido, a: DocumentoAssinad
|
|
|
471
479
|
let full: ProtocoloNfe = p;
|
|
472
480
|
if (a) {
|
|
473
481
|
if (`NFe${p.chNFe}` !== a.id) {
|
|
474
|
-
throw new
|
|
482
|
+
throw new ErroRespostaInvalida('protocolo de outra chave de acesso', { detalhes: { chNFe: p.chNFe } });
|
|
475
483
|
}
|
|
476
484
|
if (p.digVal !== undefined && p.digVal !== a.digestValue) {
|
|
477
|
-
throw new
|
|
478
|
-
|
|
485
|
+
throw new ErroRespostaInvalida('digVal do protocolo difere do DigestValue da NF-e enviada', {
|
|
486
|
+
detalhes: { chNFe: p.chNFe, cStat: p.cStat },
|
|
479
487
|
});
|
|
480
488
|
}
|
|
481
489
|
if (p.digVal !== undefined) full = { ...p, nfeProc: envelope('nfeProc', '4.00', [a.xml, embutido]) };
|
|
482
490
|
}
|
|
483
|
-
return autorizada ?
|
|
491
|
+
return autorizada ? criarAutorizado(status, full) : criarDenegado(status, full);
|
|
484
492
|
}
|
|
485
493
|
|
|
486
|
-
function protNFeDaChave(parent:
|
|
487
|
-
const prots =
|
|
494
|
+
function protNFeDaChave(parent: ElementoXml, a: DocumentoAssinado | undefined): ElementoXml | undefined {
|
|
495
|
+
const prots = elementosFilhos(parent).filter((e) => e.local === 'protNFe' && e.ns === NFE_NS);
|
|
488
496
|
if (!a) return prots[0];
|
|
489
497
|
const chave = a.id.slice(3);
|
|
490
498
|
return (
|
|
491
499
|
prots.find((e) => {
|
|
492
|
-
const inf =
|
|
493
|
-
const ch = inf &&
|
|
494
|
-
return ch !== undefined &&
|
|
500
|
+
const inf = primeiroFilho(e, 'infProt', NFE_NS);
|
|
501
|
+
const ch = inf && primeiroFilho(inf, 'chNFe', NFE_NS);
|
|
502
|
+
return ch !== undefined && textoDe(ch).trim() === chave;
|
|
495
503
|
}) ?? (prots.length === 1 ? prots[0] : undefined)
|
|
496
504
|
);
|
|
497
505
|
}
|
|
@@ -523,52 +531,59 @@ interface EventoPedido {
|
|
|
523
531
|
readonly cOrgao: string;
|
|
524
532
|
readonly autor: { CNPJ: string } | { CPF: string };
|
|
525
533
|
readonly detEvento: Readonly<Record<string, unknown>>;
|
|
526
|
-
readonly endpoint:
|
|
534
|
+
readonly endpoint: EndpointResolvido;
|
|
527
535
|
/** Fuso do `dhEvento`. */
|
|
528
536
|
readonly offsetMinutes: number;
|
|
537
|
+
readonly signal: AbortSignal | undefined;
|
|
529
538
|
}
|
|
530
539
|
|
|
531
540
|
/** Cria o cliente dos serviços da NF-e. */
|
|
532
|
-
export function
|
|
533
|
-
const logger = (
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
541
|
+
export function criarClienteNfe(opcoesDoCliente: ClienteNfeOpcoes): ClienteNfe {
|
|
542
|
+
const logger = (opcoesDoCliente.logger ?? loggerSilencioso).child({
|
|
543
|
+
modulo: 'nfe',
|
|
544
|
+
ambiente: opcoesDoCliente.ambiente,
|
|
545
|
+
});
|
|
546
|
+
const sleep = opcoesDoCliente.esperar ?? defaultSleep;
|
|
547
|
+
const tpAmb = tpAmbDoAmbiente(opcoesDoCliente.ambiente);
|
|
548
|
+
const ufInfo = opcoesDoCliente.uf === undefined ? undefined : ufPorSigla(opcoesDoCliente.uf);
|
|
549
|
+
if (opcoesDoCliente.uf !== undefined && !ufInfo)
|
|
550
|
+
throw new ErroDeConfiguracao(`UF inválida: ${String(opcoesDoCliente.uf)}`);
|
|
551
|
+
/** UF dos serviços sem documento; sem `opcoesDoCliente.uf`, `ErroDeConfiguracao` nomeando o serviço. */
|
|
539
552
|
const ufPadrao = (servico: string): { readonly uf: Uf; readonly cUF: CUf } => {
|
|
540
|
-
if (
|
|
541
|
-
throw new
|
|
553
|
+
if (opcoesDoCliente.uf === undefined || ufInfo === undefined) {
|
|
554
|
+
throw new ErroDeConfiguracao(`${servico} precisa da UF: informe ClienteNfeOpcoes.uf`);
|
|
542
555
|
}
|
|
543
|
-
return { uf:
|
|
556
|
+
return { uf: opcoesDoCliente.uf, cUF: ufInfo.cUF };
|
|
544
557
|
};
|
|
545
558
|
/** Fuso de um evento pela UF de quem o registra. */
|
|
546
|
-
const offsetDe = (uf: Uf): number =>
|
|
559
|
+
const offsetDe = (uf: Uf): number => opcoesDoCliente.deslocamentoMin ?? deslocamentoDaUf(uf);
|
|
547
560
|
|
|
548
561
|
const idLote = (): string => {
|
|
549
|
-
const id =
|
|
550
|
-
|
|
562
|
+
const id = opcoesDoCliente.idLote
|
|
563
|
+
? opcoesDoCliente.idLote()
|
|
564
|
+
: String(opcoesDoCliente.relogio.agora().getTime()).slice(-15);
|
|
565
|
+
if (!/^[0-9]{1,15}$/.test(id)) throw new ErroDeConfiguracao(`idLote inválido: ${id}`);
|
|
551
566
|
return id;
|
|
552
567
|
};
|
|
553
568
|
|
|
554
|
-
/** Endpoint da NFC-e: a opção `
|
|
555
|
-
const endpointNfce = (servico: NfeServico, uf: Uf):
|
|
556
|
-
|
|
557
|
-
?
|
|
558
|
-
: nfceEndpoint({ ambiente:
|
|
569
|
+
/** Endpoint da NFC-e: a opção `endpointNfce` ou a tabela da NFC-e do transporte, sempre no autorizador normal. */
|
|
570
|
+
const endpointNfce = (servico: NfeServico, uf: Uf): EndpointResolvido =>
|
|
571
|
+
opcoesDoCliente.endpointNfce
|
|
572
|
+
? opcoesDoCliente.endpointNfce(servico, uf)
|
|
573
|
+
: nfceEndpoint({ ambiente: opcoesDoCliente.ambiente, servico, uf });
|
|
559
574
|
|
|
560
575
|
/**
|
|
561
576
|
* Endpoint de um serviço sem documento, pela UF das opções: NF-e com SVC quando `contingencia` pede; NFC-e no
|
|
562
577
|
* autorizador normal.
|
|
563
578
|
*/
|
|
564
|
-
const endpoint = (servico: NfeServico, mod = '55'):
|
|
579
|
+
const endpoint = (servico: NfeServico, mod = '55'): EndpointResolvido => {
|
|
565
580
|
const { uf } = ufPadrao(servico);
|
|
566
581
|
if (mod === '65') return endpointNfce(servico, uf);
|
|
567
582
|
return nfeEndpoint({
|
|
568
|
-
ambiente:
|
|
583
|
+
ambiente: opcoesDoCliente.ambiente,
|
|
569
584
|
servico,
|
|
570
585
|
uf,
|
|
571
|
-
...(
|
|
586
|
+
...(opcoesDoCliente.contingencia === undefined ? {} : { contingencia: opcoesDoCliente.contingencia }),
|
|
572
587
|
});
|
|
573
588
|
};
|
|
574
589
|
|
|
@@ -577,37 +592,37 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
577
592
|
* autorizou a nota. `naUf` força o autorizador da UF (a CC-e não existe no SVC). A NFC-e vai sempre ao autorizador
|
|
578
593
|
* normal da NFC-e.
|
|
579
594
|
*/
|
|
580
|
-
const endpointDaChave = (servico: NfeServico, c: ChaveAcesso, naUf = false):
|
|
595
|
+
const endpointDaChave = (servico: NfeServico, c: ChaveAcesso, naUf = false): EndpointResolvido => {
|
|
581
596
|
if (c.mod === '65') return endpointNfce(servico, c.uf);
|
|
582
597
|
const svc = naUf || c.tpEmis === undefined ? undefined : SVC_DO_TPEMIS[c.tpEmis];
|
|
583
598
|
return nfeEndpoint({
|
|
584
|
-
ambiente:
|
|
599
|
+
ambiente: opcoesDoCliente.ambiente,
|
|
585
600
|
servico,
|
|
586
601
|
...(svc === undefined ? { uf: c.uf } : { autorizador: svc }),
|
|
587
602
|
});
|
|
588
603
|
};
|
|
589
604
|
|
|
590
605
|
const call = (
|
|
591
|
-
ep:
|
|
606
|
+
ep: EndpointResolvido,
|
|
592
607
|
servico: NfeServico,
|
|
593
608
|
mensagem: string,
|
|
594
609
|
retorno: string,
|
|
595
610
|
signal?: AbortSignal,
|
|
596
611
|
): Promise<RespostaSoap> =>
|
|
597
612
|
chamar({
|
|
598
|
-
transport:
|
|
613
|
+
transport: opcoesDoCliente.transporte,
|
|
599
614
|
endpoint: ep,
|
|
600
615
|
servico,
|
|
601
616
|
mensagem,
|
|
602
617
|
retorno,
|
|
603
618
|
logger,
|
|
604
|
-
...(
|
|
619
|
+
...(opcoesDoCliente.timeoutMs === undefined ? {} : { timeoutMs: opcoesDoCliente.timeoutMs }),
|
|
605
620
|
...(signal === undefined ? {} : { signal }),
|
|
606
621
|
});
|
|
607
622
|
|
|
608
623
|
const autorPadrao = (a: AutorDocumento | undefined, path: string): { CNPJ: string } | { CPF: string } => {
|
|
609
|
-
const autor = a ??
|
|
610
|
-
if (!autor) throw new
|
|
624
|
+
const autor = a ?? opcoesDoCliente.autor;
|
|
625
|
+
if (!autor) throw new ErroDeConfiguracao(`informe o CNPJ ou CPF do autor (${path} ou ClienteNfeOpcoes.autor)`);
|
|
611
626
|
return documentoAutor(autor, path);
|
|
612
627
|
};
|
|
613
628
|
|
|
@@ -615,42 +630,42 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
615
630
|
nRec: string,
|
|
616
631
|
nfeAssinada?: string,
|
|
617
632
|
opcoes: ConsultaReciboOpcoes = {},
|
|
618
|
-
): Promise<
|
|
619
|
-
if (!/^[0-9]{15}$/.test(nRec)) throw new
|
|
633
|
+
): Promise<ResultadoAutorizacao> {
|
|
634
|
+
if (!/^[0-9]{15}$/.test(nRec)) throw new ErroDeConfiguracao(`número de recibo inválido: ${nRec}`);
|
|
620
635
|
const a = nfeAssinada === undefined ? undefined : documentoAssinado(nfeAssinada, 'NFe', 'infNFe');
|
|
621
636
|
const c = a === undefined ? undefined : chaveDoDocumento(a);
|
|
622
637
|
if (c !== undefined && opcoes.mod !== undefined && opcoes.mod !== c.mod) {
|
|
623
|
-
throw new
|
|
638
|
+
throw new ErroDeConfiguracao(`mod ${opcoes.mod} não é o da NF-e assinada (${c.mod})`);
|
|
624
639
|
}
|
|
625
640
|
const msg = envelope('consReciNFe', '4.00', [`<tpAmb>${tpAmb}</tpAmb><nRec>${nRec}</nRec>`]);
|
|
626
641
|
// O recibo é do autorizador que recebeu o lote: com a NF-e, o da chave; sem ela, o das opções.
|
|
627
642
|
const ep =
|
|
628
643
|
c === undefined ? endpoint('NFeRetAutorizacao', opcoes.mod ?? '55') : endpointDaChave('NFeRetAutorizacao', c);
|
|
629
644
|
const r = await call(ep, 'NFeRetAutorizacao', msg, 'retConsReciNFe', opcoes.signal);
|
|
630
|
-
const v =
|
|
645
|
+
const v = decodificar(TRetConsReciNFe, r.ret, r.doc.texto).valor;
|
|
631
646
|
if (v.nRec !== undefined && v.nRec !== nRec) {
|
|
632
|
-
throw new
|
|
647
|
+
throw new ErroRespostaInvalida('retorno de outro recibo', { detalhes: { nRec: v.nRec } });
|
|
633
648
|
}
|
|
634
649
|
const status = { cStat: v.cStat, xMotivo: v.xMotivo };
|
|
635
650
|
logger.info('nfe.recibo', { nRec, cStat: v.cStat });
|
|
636
651
|
if (cstatEm(v.cStat, 'loteEmProcessamento') || cstatEm(v.cStat, 'loteRecebido'))
|
|
637
|
-
return
|
|
652
|
+
return criarPendente(status, { referencia: nRec });
|
|
638
653
|
if (cstatEm(v.cStat, 'loteProcessado')) {
|
|
639
654
|
const el = protNFeDaChave(r.ret, a);
|
|
640
|
-
if (!el) throw new
|
|
655
|
+
if (!el) throw new ErroRespostaInvalida('lote processado sem o protNFe da NF-e', { detalhes: { nRec } });
|
|
641
656
|
return desfechoDoProtocolo(lerProtocolo(r.doc, el), a);
|
|
642
657
|
}
|
|
643
658
|
return rejeitado(status);
|
|
644
659
|
}
|
|
645
660
|
|
|
646
|
-
async function consultar(chave: string, nfeAssinada?: string): Promise<
|
|
661
|
+
async function consultar(chave: string, nfeAssinada?: string, opcoes?: EnvioOpcoes): Promise<ResultadoConsulta> {
|
|
647
662
|
const c = chaveValida(chave, 'chNFe');
|
|
648
663
|
const a = nfeAssinada === undefined ? undefined : documentoAssinado(nfeAssinada, 'NFe', 'infNFe');
|
|
649
|
-
if (a && a.id !== `NFe${c.chave}`) throw new
|
|
650
|
-
const msg =
|
|
664
|
+
if (a && a.id !== `NFe${c.chave}`) throw new ErroDeConfiguracao('a NF-e assinada não é a da chave consultada');
|
|
665
|
+
const msg = serializarRaiz(consSitNFeElement, { versao: '4.00', tpAmb, xServ: 'CONSULTAR', chNFe: c.chave });
|
|
651
666
|
const ep = endpointDaChave('NfeConsultaProtocolo', c);
|
|
652
|
-
const r = await call(ep, 'NfeConsultaProtocolo', msg, 'retConsSitNFe');
|
|
653
|
-
const v =
|
|
667
|
+
const r = await call(ep, 'NfeConsultaProtocolo', msg, 'retConsSitNFe', opcoes?.signal);
|
|
668
|
+
const v = decodificar(TRetConsSitNFe, r.ret, r.doc.texto).valor;
|
|
654
669
|
const status = { cStat: v.cStat, xMotivo: v.xMotivo };
|
|
655
670
|
logger.info('nfe.consulta', { chNFe: c.chave, cStat: v.cStat });
|
|
656
671
|
const situacao = cstatEm(v.cStat, 'autorizada')
|
|
@@ -661,8 +676,8 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
661
676
|
? 'denegada'
|
|
662
677
|
: undefined;
|
|
663
678
|
if (situacao === undefined) return rejeitado(status);
|
|
664
|
-
const protEl =
|
|
665
|
-
const eventos =
|
|
679
|
+
const protEl = primeiroFilho(r.ret, 'protNFe', NFE_NS);
|
|
680
|
+
const eventos = elementosFilhos(r.ret)
|
|
666
681
|
.filter((e) => e.local === 'procEventoNFe' && e.ns === NFE_NS)
|
|
667
682
|
.map((e) => avulso(r.doc, e));
|
|
668
683
|
let protocolo: ProtocoloNfe | undefined;
|
|
@@ -670,7 +685,9 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
670
685
|
if (protEl) {
|
|
671
686
|
const { p, embutido } = lerProtocolo(r.doc, protEl);
|
|
672
687
|
if (p.chNFe !== c.chave) {
|
|
673
|
-
throw new
|
|
688
|
+
throw new ErroRespostaInvalida('protocolo de outra chave de acesso na consulta', {
|
|
689
|
+
detalhes: { chNFe: p.chNFe },
|
|
690
|
+
});
|
|
674
691
|
}
|
|
675
692
|
protocolo = p;
|
|
676
693
|
if (a) {
|
|
@@ -685,12 +702,12 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
685
702
|
...(protocolo === undefined ? {} : { protocolo }),
|
|
686
703
|
...(digValConfere === undefined ? {} : { digValConfere }),
|
|
687
704
|
};
|
|
688
|
-
return situacao === 'denegada' ?
|
|
705
|
+
return situacao === 'denegada' ? criarDenegado(status, value) : criarAutorizado(status, value);
|
|
689
706
|
}
|
|
690
707
|
|
|
691
|
-
async function enviarEvento(p: EventoPedido): Promise<
|
|
708
|
+
async function enviarEvento(p: EventoPedido): Promise<ResultadoEvento> {
|
|
692
709
|
const nSeq = p.nSeqEvento;
|
|
693
|
-
if (!Number.isInteger(nSeq) || nSeq < 1 || nSeq > 99) throw new
|
|
710
|
+
if (!Number.isInteger(nSeq) || nSeq < 1 || nSeq > 99) throw new ErroDeConfiguracao(`nSeqEvento inválido: ${nSeq}`);
|
|
694
711
|
const nSeqEvento = String(nSeq);
|
|
695
712
|
// Id = "ID" + tpEvento + chave + nSeqEvento com 2 dígitos (leiaute do evento, atributo Id de infEvento).
|
|
696
713
|
const id = `ID${p.tpEvento}${p.chave}${nSeqEvento.padStart(2, '0')}`;
|
|
@@ -700,25 +717,25 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
700
717
|
tpAmb,
|
|
701
718
|
...p.autor,
|
|
702
719
|
chNFe: p.chave,
|
|
703
|
-
dhEvento:
|
|
720
|
+
dhEvento: formatarDh(opcoesDoCliente.relogio.agora(), p.offsetMinutes),
|
|
704
721
|
tpEvento: p.tpEvento,
|
|
705
722
|
nSeqEvento,
|
|
706
723
|
verEvento: EVENTO_VERSAO,
|
|
707
724
|
detEvento: p.detEvento,
|
|
708
725
|
};
|
|
709
|
-
const infXml =
|
|
726
|
+
const infXml = serializar(p.ct, 'infEvento', inf, NFE_NS);
|
|
710
727
|
const evento = `<evento xmlns="${NFE_NS}" versao="${EVENTO_VERSAO}">${infXml}</evento>`;
|
|
711
|
-
const infEl =
|
|
712
|
-
schemaIssues('evento',
|
|
713
|
-
const assinado = await
|
|
728
|
+
const infEl = primeiroFilho(lerXml(evento).raiz, 'infEvento', NFE_NS) as ElementoXml;
|
|
729
|
+
schemaIssues('evento', validar(p.ct, infEl));
|
|
730
|
+
const assinado = await assinarXml(evento, { id }, opcoesDoCliente.assinador);
|
|
714
731
|
const msg = envelope('envEvento', EVENTO_VERSAO, [`<idLote>${idLote()}</idLote>`, assinado]);
|
|
715
|
-
const r = await call(p.endpoint, 'RecepcaoEvento', msg, 'retEnvEvento');
|
|
716
|
-
const v =
|
|
732
|
+
const r = await call(p.endpoint, 'RecepcaoEvento', msg, 'retEnvEvento', p.signal);
|
|
733
|
+
const v = decodificar(TRetEnvEvento, r.ret, r.doc.texto).valor;
|
|
717
734
|
logger.info('nfe.evento', { chNFe: p.chave, tpEvento: p.tpEvento, cStat: v.cStat });
|
|
718
735
|
if (!cstatEm(v.cStat, 'loteEventoProcessado')) return rejeitado({ cStat: v.cStat, xMotivo: v.xMotivo });
|
|
719
|
-
const retEl =
|
|
736
|
+
const retEl = elementosFilhos(r.ret).find((e) => e.local === 'retEvento' && e.ns === NFE_NS);
|
|
720
737
|
const ret = v.retEvento?.[0]?.infEvento;
|
|
721
|
-
if (!retEl || !ret) throw new
|
|
738
|
+
if (!retEl || !ret) throw new ErroRespostaInvalida('lote de evento processado sem retEvento');
|
|
722
739
|
// O retorno tem de ser deste evento: chave, tipo e sequência, quando vierem, iguais aos enviados.
|
|
723
740
|
const divergentes = (
|
|
724
741
|
[
|
|
@@ -728,35 +745,41 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
728
745
|
] as const
|
|
729
746
|
).filter(([, veio, enviado]) => veio !== undefined && veio !== enviado);
|
|
730
747
|
if (divergentes.length > 0) {
|
|
731
|
-
throw new
|
|
732
|
-
|
|
748
|
+
throw new ErroRespostaInvalida('retEvento de outro evento', {
|
|
749
|
+
detalhes: Object.fromEntries(divergentes.map(([k, veio]) => [k, veio])),
|
|
733
750
|
});
|
|
734
751
|
}
|
|
735
752
|
const status = { cStat: ret.cStat, xMotivo: ret.xMotivo };
|
|
736
753
|
if (!cstatEm(ret.cStat, 'eventoRegistrado')) return rejeitado(status);
|
|
737
|
-
return
|
|
754
|
+
return criarAutorizado(status, {
|
|
738
755
|
chNFe: p.chave,
|
|
739
756
|
tpEvento: p.tpEvento,
|
|
740
757
|
nSeqEvento,
|
|
741
758
|
dhRegEvento: ret.dhRegEvento,
|
|
742
759
|
retEvento: avulso(r.doc, retEl),
|
|
743
|
-
procEventoNFe: envelope('procEventoNFe', EVENTO_VERSAO, [assinado,
|
|
760
|
+
procEventoNFe: envelope('procEventoNFe', EVENTO_VERSAO, [assinado, recortarElemento(r.doc, retEl)]),
|
|
744
761
|
...(ret.nProt === undefined ? {} : { nProt: ret.nProt }),
|
|
745
762
|
});
|
|
746
763
|
}
|
|
747
764
|
|
|
748
|
-
const client:
|
|
749
|
-
|
|
765
|
+
const client: ClienteNfe = {
|
|
766
|
+
opcoes: opcoesDoCliente,
|
|
750
767
|
|
|
751
|
-
async statusServico(opcoes?:
|
|
768
|
+
async statusServico(opcoes?: StatusServicoOpcoes): Promise<ResultadoSefaz<StatusServico, never>> {
|
|
752
769
|
const { cUF } = ufPadrao('NfeStatusServico');
|
|
753
|
-
const msg =
|
|
754
|
-
const r = await call(
|
|
755
|
-
|
|
770
|
+
const msg = serializarRaiz(consStatServElement, { versao: '4.00', tpAmb, cUF, xServ: 'STATUS' });
|
|
771
|
+
const r = await call(
|
|
772
|
+
endpoint('NfeStatusServico', opcoes?.mod),
|
|
773
|
+
'NfeStatusServico',
|
|
774
|
+
msg,
|
|
775
|
+
'retConsStatServ',
|
|
776
|
+
opcoes?.signal,
|
|
777
|
+
);
|
|
778
|
+
const v = decodificar(TRetConsStatServ, r.ret, r.doc.texto).valor;
|
|
756
779
|
const status = { cStat: v.cStat, xMotivo: v.xMotivo };
|
|
757
780
|
logger.info('nfe.status', { cStat: v.cStat });
|
|
758
781
|
if (!cstatEm(v.cStat, 'servicoEmOperacao')) return rejeitado(status);
|
|
759
|
-
return
|
|
782
|
+
return criarAutorizado(status, {
|
|
760
783
|
cUF: v.cUF,
|
|
761
784
|
verAplic: v.verAplic,
|
|
762
785
|
dhRecbto: v.dhRecbto,
|
|
@@ -766,7 +789,7 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
766
789
|
});
|
|
767
790
|
},
|
|
768
791
|
|
|
769
|
-
async autorizar(nfeAssinada: string, opcoes: AutorizarOpcoes = {}): Promise<
|
|
792
|
+
async autorizar(nfeAssinada: string, opcoes: AutorizarOpcoes = {}): Promise<ResultadoAutorizacao> {
|
|
770
793
|
const a = documentoAssinado(nfeAssinada, 'NFe', 'infNFe');
|
|
771
794
|
const sincrono = opcoes.sincrono ?? true;
|
|
772
795
|
const msg = envelope('enviNFe', '4.00', [
|
|
@@ -776,14 +799,14 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
776
799
|
// O autorizador é o do documento: a UF do cUF e, assinada em SVC (tpEmis 6 ou 7), o SVC da chave.
|
|
777
800
|
const ep = endpointDaChave('NFeAutorizacao', chaveDoDocumento(a));
|
|
778
801
|
const r = await call(ep, 'NFeAutorizacao', msg, 'retEnviNFe', opcoes.signal);
|
|
779
|
-
const v =
|
|
802
|
+
const v = decodificar(TRetEnviNFe, r.ret, r.doc.texto).valor;
|
|
780
803
|
const status = { cStat: v.cStat, xMotivo: v.xMotivo };
|
|
781
804
|
logger.info('nfe.autorizacao', { chNFe: a.id.slice(3), cStat: v.cStat, sincrono });
|
|
782
805
|
if (cstatEm(v.cStat, 'loteRecebido')) {
|
|
783
806
|
const nRec = v.infRec?.nRec;
|
|
784
|
-
if (!nRec) throw new
|
|
807
|
+
if (!nRec) throw new ErroRespostaInvalida('lote recebido sem número de recibo');
|
|
785
808
|
const tMed = Number(v.infRec?.tMed ?? '0');
|
|
786
|
-
return
|
|
809
|
+
return criarPendente(status, { referencia: nRec, aguardarMs: Math.max(1, tMed) * 1000 });
|
|
787
810
|
}
|
|
788
811
|
const protEl = protNFeDaChave(r.ret, a);
|
|
789
812
|
if (protEl) return desfechoDoProtocolo(lerProtocolo(r.doc, protEl), a);
|
|
@@ -796,29 +819,31 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
796
819
|
nRec: string,
|
|
797
820
|
nfeAssinada?: string,
|
|
798
821
|
politica: PoliticaRecibo = {},
|
|
799
|
-
): Promise<
|
|
822
|
+
): Promise<ResultadoAutorizacao> {
|
|
800
823
|
const max = politica.maxTentativas ?? 10;
|
|
801
824
|
const minimo = politica.esperaMinimaMs ?? 2000;
|
|
802
825
|
const mult = politica.multiplicador ?? 1.5;
|
|
803
826
|
const teto = politica.esperaMaximaMs ?? 30_000;
|
|
804
827
|
if (!(max >= 1) || !(minimo >= 0) || !(mult >= 1) || !(teto >= minimo)) {
|
|
805
|
-
throw new
|
|
828
|
+
throw new ErroDeConfiguracao('política de consulta do recibo inválida', {
|
|
829
|
+
detalhes: { max, minimo, mult, teto },
|
|
830
|
+
});
|
|
806
831
|
}
|
|
807
832
|
let espera = minimo;
|
|
808
|
-
let ultimo:
|
|
833
|
+
let ultimo: ResultadoAutorizacao | undefined;
|
|
809
834
|
for (let i = 0; i < max; i++) {
|
|
810
835
|
await sleep(espera, politica.signal);
|
|
811
836
|
// O mesmo signal cancela a espera e a requisição em curso.
|
|
812
837
|
ultimo = await consultarRecibo(nRec, nfeAssinada, politica);
|
|
813
|
-
if (ultimo.
|
|
814
|
-
espera = Math.min(teto, Math.max(minimo, Math.round(espera * mult), ultimo.
|
|
838
|
+
if (ultimo.tipo !== 'pendente') return ultimo;
|
|
839
|
+
espera = Math.min(teto, Math.max(minimo, Math.round(espera * mult), ultimo.aguardarMs ?? 0));
|
|
815
840
|
}
|
|
816
|
-
return ultimo as
|
|
841
|
+
return ultimo as ResultadoAutorizacao;
|
|
817
842
|
},
|
|
818
843
|
|
|
819
844
|
consultar,
|
|
820
845
|
|
|
821
|
-
async cancelar(p: CancelamentoPedido): Promise<
|
|
846
|
+
async cancelar(p: CancelamentoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento> {
|
|
822
847
|
const c = chaveValida(p.chave, 'chave');
|
|
823
848
|
return enviarEvento({
|
|
824
849
|
ct: TEventoCanc,
|
|
@@ -831,17 +856,18 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
831
856
|
// No autorizador da nota: o SVC só cancela a NF-e que ele autorizou, e a da UF só se cancela na UF.
|
|
832
857
|
endpoint: endpointDaChave('RecepcaoEvento', c),
|
|
833
858
|
offsetMinutes: offsetDe(c.uf),
|
|
859
|
+
signal: opcoes?.signal,
|
|
834
860
|
});
|
|
835
861
|
},
|
|
836
862
|
|
|
837
|
-
async cancelarPorSubstituicao(p: CancelamentoSubstituicaoPedido): Promise<
|
|
863
|
+
async cancelarPorSubstituicao(p: CancelamentoSubstituicaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento> {
|
|
838
864
|
const c = chaveValida(p.chave, 'chave');
|
|
839
865
|
if (c.mod !== '65') {
|
|
840
|
-
throw new
|
|
866
|
+
throw new ErroDeValidacao('cancelamento por substituição só existe para NFC-e', [
|
|
841
867
|
{
|
|
842
|
-
|
|
868
|
+
caminho: 'chave',
|
|
843
869
|
code: 'modelo_nao_suportado',
|
|
844
|
-
|
|
870
|
+
mensagem: 'O evento 110112 é exclusivo da NFC-e (modelo 65)',
|
|
845
871
|
},
|
|
846
872
|
]);
|
|
847
873
|
}
|
|
@@ -867,13 +893,14 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
867
893
|
detEvento,
|
|
868
894
|
endpoint: endpointDaChave('RecepcaoEvento', c),
|
|
869
895
|
offsetMinutes: offsetDe(c.uf),
|
|
896
|
+
signal: opcoes?.signal,
|
|
870
897
|
});
|
|
871
898
|
},
|
|
872
899
|
|
|
873
|
-
async cartaCorrecao(p: CartaCorrecaoPedido): Promise<
|
|
900
|
+
async cartaCorrecao(p: CartaCorrecaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento> {
|
|
874
901
|
const c = chaveValida(p.chave, 'chave');
|
|
875
902
|
if (!Number.isInteger(p.nSeqEvento) || p.nSeqEvento < 1 || p.nSeqEvento > 20) {
|
|
876
|
-
throw new
|
|
903
|
+
throw new ErroDeConfiguracao(`nSeqEvento da CC-e vai de 1 a 20: ${p.nSeqEvento}`);
|
|
877
904
|
}
|
|
878
905
|
return enviarEvento({
|
|
879
906
|
ct: TEventoCce,
|
|
@@ -891,13 +918,14 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
891
918
|
// A CC-e vai sempre à UF: o SVC só recebe o cancelamento (NT 2013.007).
|
|
892
919
|
endpoint: endpointDaChave('RecepcaoEvento', c, true),
|
|
893
920
|
offsetMinutes: offsetDe(c.uf),
|
|
921
|
+
signal: opcoes?.signal,
|
|
894
922
|
});
|
|
895
923
|
},
|
|
896
924
|
|
|
897
|
-
async manifestar(p: ManifestacaoPedido): Promise<
|
|
925
|
+
async manifestar(p: ManifestacaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoEvento> {
|
|
898
926
|
const c = chaveValida(p.chave, 'chave');
|
|
899
927
|
const m = MANIFESTACOES[p.tipo];
|
|
900
|
-
if (!m) throw new
|
|
928
|
+
if (!m) throw new ErroDeConfiguracao(`tipo de manifestação desconhecido: ${String(p.tipo)}`);
|
|
901
929
|
return enviarEvento({
|
|
902
930
|
ct: m.ct,
|
|
903
931
|
tpEvento: m.tpEvento,
|
|
@@ -911,22 +939,23 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
911
939
|
descEvento: m.descEvento,
|
|
912
940
|
...(p.xJust === undefined ? {} : { xJust: p.xJust }),
|
|
913
941
|
},
|
|
914
|
-
endpoint: nfeEndpoint({ ambiente:
|
|
942
|
+
endpoint: nfeEndpoint({ ambiente: opcoesDoCliente.ambiente, servico: 'RecepcaoEvento', autorizador: 'AN' }),
|
|
915
943
|
// Quem manifesta é o destinatário: o fuso é o da UF dele, quando informada.
|
|
916
|
-
offsetMinutes: offsetDe(
|
|
944
|
+
offsetMinutes: offsetDe(opcoesDoCliente.uf ?? c.uf),
|
|
945
|
+
signal: opcoes?.signal,
|
|
917
946
|
});
|
|
918
947
|
},
|
|
919
948
|
|
|
920
|
-
async inutilizar(p: InutilizacaoPedido): Promise<
|
|
949
|
+
async inutilizar(p: InutilizacaoPedido, opcoes?: EnvioOpcoes): Promise<ResultadoInutilizacao> {
|
|
921
950
|
const autor = autorPadrao(p.autor, 'autor');
|
|
922
951
|
// NT 2018.001 v1.10, item 6.1: o controle de inutilização não se aplica ao emitente pessoa física, e o leiaute do
|
|
923
952
|
// pedido não prevê o CPF; a série 910 a 969 (emitente CPF) é rejeitada com 266 (regra I02a, item 6.2).
|
|
924
953
|
if (!('CNPJ' in autor)) {
|
|
925
|
-
throw new
|
|
954
|
+
throw new ErroDeValidacao('inutilização não se aplica ao emitente pessoa física', [
|
|
926
955
|
{
|
|
927
|
-
|
|
956
|
+
caminho: 'autor.CPF',
|
|
928
957
|
code: 'inutilizacao_emitente_cpf',
|
|
929
|
-
|
|
958
|
+
mensagem: 'O pedido de inutilização só existe para emitente CNPJ (NT 2018.001 v1.10, item 6.1)',
|
|
930
959
|
},
|
|
931
960
|
]);
|
|
932
961
|
}
|
|
@@ -944,15 +973,16 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
944
973
|
['nNFIni', ini, /^[1-9][0-9]{0,8}$/],
|
|
945
974
|
['nNFFin', fin, /^[1-9][0-9]{0,8}$/],
|
|
946
975
|
] as const) {
|
|
947
|
-
if (!re.test(x)) throw new
|
|
976
|
+
if (!re.test(x)) throw new ErroDeConfiguracao(`${k} inválido para inutilização: ${x}`);
|
|
948
977
|
}
|
|
949
|
-
if (Number(fin) < Number(ini)) throw new
|
|
978
|
+
if (Number(fin) < Number(ini)) throw new ErroDeConfiguracao('nNFFin menor que nNFIni');
|
|
950
979
|
if (Number(serie) >= 910 && Number(serie) <= 969) {
|
|
951
|
-
throw new
|
|
980
|
+
throw new ErroDeValidacao('série de emitente pessoa física não se inutiliza', [
|
|
952
981
|
{
|
|
953
|
-
|
|
982
|
+
caminho: 'serie',
|
|
954
983
|
code: 'inutilizacao_serie_cpf',
|
|
955
|
-
|
|
984
|
+
mensagem:
|
|
985
|
+
'Série 910 a 969 identifica emitente CPF: a SEFAZ rejeita com 266 (NT 2018.001 v1.10, regra I02a)',
|
|
956
986
|
},
|
|
957
987
|
]);
|
|
958
988
|
}
|
|
@@ -971,18 +1001,18 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
971
1001
|
nNFFin: fin,
|
|
972
1002
|
xJust: p.xJust,
|
|
973
1003
|
};
|
|
974
|
-
const infXml =
|
|
1004
|
+
const infXml = serializar(TInutNFe_infInut, 'infInut', inf, NFE_NS);
|
|
975
1005
|
const inut = envelope('inutNFe', '4.00', [infXml]);
|
|
976
|
-
const infEl =
|
|
977
|
-
schemaIssues('pedido de inutilização',
|
|
978
|
-
const assinado = await
|
|
1006
|
+
const infEl = primeiroFilho(lerXml(inut).raiz, 'infInut', NFE_NS) as ElementoXml;
|
|
1007
|
+
schemaIssues('pedido de inutilização', validar(TInutNFe_infInut, infEl));
|
|
1008
|
+
const assinado = await assinarXml(inut, { id }, opcoesDoCliente.assinador);
|
|
979
1009
|
// A inutilização não existe no SVC (o SVC-RS nem publica o serviço): vai sempre ao autorizador normal da UF.
|
|
980
1010
|
const ep =
|
|
981
1011
|
mod === '65'
|
|
982
1012
|
? endpointNfce('NfeInutilizacao', uf)
|
|
983
|
-
: nfeEndpoint({ ambiente:
|
|
984
|
-
const r = await call(ep, 'NfeInutilizacao', assinado, 'retInutNFe');
|
|
985
|
-
const v =
|
|
1013
|
+
: nfeEndpoint({ ambiente: opcoesDoCliente.ambiente, servico: 'NfeInutilizacao', uf });
|
|
1014
|
+
const r = await call(ep, 'NfeInutilizacao', assinado, 'retInutNFe', opcoes?.signal);
|
|
1015
|
+
const v = decodificar(TRetInutNFe, r.ret, r.doc.texto).valor;
|
|
986
1016
|
const status = { cStat: v.infInut.cStat, xMotivo: v.infInut.xMotivo };
|
|
987
1017
|
logger.info('nfe.inutilizacao', { id, cStat: status.cStat });
|
|
988
1018
|
if (!cstatEm(status.cStat, 'inutilizacaoHomologada')) return rejeitado(status);
|
|
@@ -999,44 +1029,44 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
999
1029
|
];
|
|
1000
1030
|
const fora = confere.filter(([, veio, pedido]) => veio !== undefined && veio !== pedido);
|
|
1001
1031
|
if (fora.length > 0) {
|
|
1002
|
-
throw new
|
|
1003
|
-
|
|
1032
|
+
throw new ErroRespostaInvalida('retInutNFe de outra faixa', {
|
|
1033
|
+
detalhes: Object.fromEntries(fora.map(([k, v]) => [k, v])),
|
|
1004
1034
|
});
|
|
1005
1035
|
}
|
|
1006
|
-
return
|
|
1036
|
+
return criarAutorizado(status, {
|
|
1007
1037
|
dhRecbto: v.infInut.dhRecbto,
|
|
1008
1038
|
retInutNFe: avulso(r.doc, r.ret),
|
|
1009
|
-
procInutNFe: envelope('ProcInutNFe', '4.00', [assinado,
|
|
1039
|
+
procInutNFe: envelope('ProcInutNFe', '4.00', [assinado, recortarElemento(r.doc, r.ret)]),
|
|
1010
1040
|
...(v.infInut.nProt === undefined ? {} : { nProt: v.infInut.nProt }),
|
|
1011
1041
|
});
|
|
1012
1042
|
},
|
|
1013
1043
|
|
|
1014
|
-
async consultarCadastro(p: CadastroPedido): Promise<
|
|
1044
|
+
async consultarCadastro(p: CadastroPedido, opcoes?: EnvioOpcoes): Promise<ResultadoSefaz<Cadastro, never>> {
|
|
1015
1045
|
const doc =
|
|
1016
1046
|
'CNPJ' in p
|
|
1017
1047
|
? documentoAutor({ CNPJ: p.CNPJ }, 'CNPJ')
|
|
1018
1048
|
: 'CPF' in p
|
|
1019
1049
|
? documentoAutor({ CPF: p.CPF }, 'CPF')
|
|
1020
1050
|
: { IE: p.IE.replace(/[^0-9A-Za-z]/g, '').toUpperCase() };
|
|
1021
|
-
const msg =
|
|
1022
|
-
const ep = nfeEndpoint({ ambiente:
|
|
1023
|
-
const r = await call(ep, 'NfeConsultaCadastro', msg, 'retConsCad');
|
|
1024
|
-
const v =
|
|
1051
|
+
const msg = serializarRaiz(ConsCadElement, { versao: '2.00', infCons: { xServ: 'CONS-CAD', UF: p.uf, ...doc } });
|
|
1052
|
+
const ep = nfeEndpoint({ ambiente: opcoesDoCliente.ambiente, servico: 'NfeConsultaCadastro', uf: p.uf });
|
|
1053
|
+
const r = await call(ep, 'NfeConsultaCadastro', msg, 'retConsCad', opcoes?.signal);
|
|
1054
|
+
const v = decodificar(TRetConsCad, r.ret, r.doc.texto).valor;
|
|
1025
1055
|
const i = v.infCons;
|
|
1026
1056
|
const status = { cStat: i.cStat, xMotivo: i.xMotivo };
|
|
1027
1057
|
logger.info('nfe.cadastro', { uf: p.uf, cStat: i.cStat });
|
|
1028
1058
|
if (!cstatEm(i.cStat, 'cadastroEncontrado')) return rejeitado(status);
|
|
1029
|
-
return
|
|
1059
|
+
return criarAutorizado(status, { UF: i.UF, dhCons: i.dhCons, infCad: i.infCad ?? [] });
|
|
1030
1060
|
},
|
|
1031
1061
|
|
|
1032
1062
|
async distribuicaoDFe(
|
|
1033
1063
|
consulta: DistribuicaoConsulta,
|
|
1034
1064
|
opcoes: DistribuicaoOpcoes = {},
|
|
1035
|
-
): Promise<
|
|
1065
|
+
): Promise<ResultadoSefaz<Distribuicao, never>> {
|
|
1036
1066
|
const autor = autorPadrao(opcoes.autor, 'autor');
|
|
1037
1067
|
const nsu = (x: string | number, k: string): string => {
|
|
1038
1068
|
const s = String(x);
|
|
1039
|
-
if (!/^[0-9]{1,15}$/.test(s)) throw new
|
|
1069
|
+
if (!/^[0-9]{1,15}$/.test(s)) throw new ErroDeConfiguracao(`${k} inválido: ${s}`);
|
|
1040
1070
|
return s.padStart(15, '0');
|
|
1041
1071
|
};
|
|
1042
1072
|
const grupo =
|
|
@@ -1046,28 +1076,28 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
1046
1076
|
? { consNSU: { NSU: nsu(consulta.NSU, 'NSU') } }
|
|
1047
1077
|
: { consChNFe: { chNFe: chaveValida(consulta.chNFe, 'chNFe').chave } };
|
|
1048
1078
|
const cUFAutor = opcoes.cUFAutor ?? ufPadrao('NFeDistribuicaoDFe').cUF;
|
|
1049
|
-
if (
|
|
1050
|
-
const msg =
|
|
1079
|
+
if (ufPorCUf(cUFAutor) === undefined) throw new ErroDeConfiguracao(`cUFAutor inválido: ${cUFAutor}`);
|
|
1080
|
+
const msg = serializarRaiz(distDFeIntElement, {
|
|
1051
1081
|
versao: '1.01',
|
|
1052
1082
|
tpAmb,
|
|
1053
1083
|
cUFAutor: cUFAutor as CUf,
|
|
1054
1084
|
...autor,
|
|
1055
1085
|
...grupo,
|
|
1056
1086
|
} as distDFeInt);
|
|
1057
|
-
const ep = nfeEndpoint({ ambiente:
|
|
1058
|
-
const r = await call(ep, 'NFeDistribuicaoDFe', msg, 'retDistDFeInt');
|
|
1059
|
-
const v =
|
|
1087
|
+
const ep = nfeEndpoint({ ambiente: opcoesDoCliente.ambiente, servico: 'NFeDistribuicaoDFe' });
|
|
1088
|
+
const r = await call(ep, 'NFeDistribuicaoDFe', msg, 'retDistDFeInt', opcoes.signal);
|
|
1089
|
+
const v = decodificar(retDistDFeInt, r.ret, r.doc.texto).valor;
|
|
1060
1090
|
const status = { cStat: v.cStat, xMotivo: v.xMotivo };
|
|
1061
1091
|
logger.info('nfe.distribuicao', { cStat: v.cStat, ultNSU: v.ultNSU, maxNSU: v.maxNSU });
|
|
1062
1092
|
const base = { ultNSU: v.ultNSU, maxNSU: v.maxNSU, dhResp: v.dhResp };
|
|
1063
|
-
if (cstatEm(v.cStat, 'distribuicaoNenhumDocumento')) return
|
|
1093
|
+
if (cstatEm(v.cStat, 'distribuicaoNenhumDocumento')) return criarAutorizado(status, { ...base, documentos: [] });
|
|
1064
1094
|
if (!cstatEm(v.cStat, 'distribuicaoDocumentos')) return rejeitado(status);
|
|
1065
1095
|
const documentos: DocumentoDistribuido[] = [];
|
|
1066
1096
|
for (const z of v.loteDistDFeInt?.docZip ?? []) {
|
|
1067
|
-
const xml = await
|
|
1097
|
+
const xml = await descomprimirGzipBase64(z.$text);
|
|
1068
1098
|
documentos.push(documentoDistribuido(z.NSU ?? '', z.schema, xml));
|
|
1069
1099
|
}
|
|
1070
|
-
return
|
|
1100
|
+
return criarAutorizado(status, { ...base, documentos });
|
|
1071
1101
|
},
|
|
1072
1102
|
};
|
|
1073
1103
|
return client;
|
|
@@ -1077,8 +1107,9 @@ export function createNfeClient(options: NfeClientOptions): NfeClient {
|
|
|
1077
1107
|
function documentoDistribuido(NSU: string, schema: string, xml: string): DocumentoDistribuido {
|
|
1078
1108
|
const nome = schema.replace(/_v?\d.*$/, '');
|
|
1079
1109
|
const base = { NSU, schema, xml };
|
|
1080
|
-
if (nome === 'resNFe') return { ...base, tipo: 'resNFe', resNFe:
|
|
1081
|
-
if (nome === 'resEvento')
|
|
1110
|
+
if (nome === 'resNFe') return { ...base, tipo: 'resNFe', resNFe: decodificarXml(resNFeElement, xml).valor };
|
|
1111
|
+
if (nome === 'resEvento')
|
|
1112
|
+
return { ...base, tipo: 'resEvento', resEvento: decodificarXml(resEventoElement, xml).valor };
|
|
1082
1113
|
if (nome === 'procNFe') return { ...base, tipo: 'procNFe' };
|
|
1083
1114
|
if (nome === 'procEventoNFe') return { ...base, tipo: 'procEventoNFe' };
|
|
1084
1115
|
return { ...base, tipo: 'outro' };
|