-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat webservice NFeDistribuicaoDFe #38
Conversation
WalkthroughAs alterações introduzem suporte para o serviço de Distribuição de Documentos Fiscais Eletrônicos (DFe) no sistema. Foram adicionados novos tipos e um método Changes
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/dfe/nfe/webServices/requests/distribuicaoDfe.ts (3)
12-28
: Abrangência e legibilidade da definição de tipo
A união de três variantes (distNSU, consNSU e consChNFe) em um tipo único (NfeDistribuicaoDfeOperation) é clara e garante flexibilidade. Contudo, avalie se há necessidade de padronizar o nome das propriedades, por exemplo “consChaveNFe” em vez de “consChNFe”, para manter consistência sem abreviações excessivas.
65-79
: Documentação refinada para propriedades opcionais
A interfaceNfeDistribuicaoDfeResponseRaw
cobre campos opcionais comoultNSU
emaxNSU
, além deloteDistDFeInt
. Considere incluir exemplos breves no JSDoc de como cada propriedade opcional aparece numa resposta real, aumentando a clareza para futuros integradores.
80-83
: Adição de valores status
Os valores possíveis paraNfeDistribuicaoDfeStatus
são adequados, mas se for previsto algum cenário futuro (p.ex. “emitente-nao-encontrado”), avalie a escalabilidade da enum.src/dfe/nfe/webServices/index.test.ts (1)
418-454
: Cobertura de teste apropriada
O teste paradistribuicaoDfe
está bem estruturado, simulando a requisição e validando o processamento do XML. Entretanto, considere adicionar um teste adicional para tratar cenários de erro (por exemplo, se o serviço retornarcStat
desconhecido ou se o XML vier malformado) a fim de ampliar a cobertura de falhas.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/dfe/nfe/webServices/__snapshots__/index.test.ts.snap
is excluded by!**/*.snap
📒 Files selected for processing (3)
src/dfe/nfe/webServices/index.test.ts
(1 hunks)src/dfe/nfe/webServices/index.ts
(2 hunks)src/dfe/nfe/webServices/requests/distribuicaoDfe.ts
(1 hunks)
🔇 Additional comments (4)
src/dfe/nfe/webServices/requests/distribuicaoDfe.ts (3)
38-38
: Validação extra de combinações possíveis
Ao unirCpfOrCnpj
eNfeDistribuicaoDfeOperation
, se o uso simultâneo de CPF/CNPJ com cada operação for complexo, considere adicionar um refinamento interno ou docstring que esclareça a combinação correta. Dessa forma, quem chama o método terá um fluxo de uso mais intuitivo.
40-49
: Coerência no tipo de requisição
O tipoNfeDistribuicaoDfeRequest
segue a mesma estrutura aplicada em outros serviços, mantendo a consistência. A inclusão detpAmb
ecUFAutor
dentro dedistDFeInt
está de acordo com a especificação. Não há problemas aparentes.
84-87
: Uso consistente de tipos genéricos
NfeDistribuicaoDfeResponse
segue o padrão de respostas do webservice, reaproveitandoNfeWebServiceResponse
. Bom uso de genéricos para vincularstatus
e o tipo cru (NfeDistribuicaoDfeResponseRaw
).src/dfe/nfe/webServices/index.ts (1)
70-77
: Importações novas e consistência de nomenclatura
A importação das novas definições emdistribuicaoDfe.ts
segue o padrão das demais. Sem problemas identificados na ordem e nomenclatura.
src/dfe/nfe/webServices/index.ts
Outdated
|
||
async distribuicaoDfe({ | ||
CPF, | ||
CNPJ, | ||
distNSU, | ||
consNSU, | ||
consChNFe, | ||
}: NfeDistribuicaoDfeOptions): Promise<NfeDistribuicaoDfeResponse> { | ||
let cpfOrCnpj: CpfOrCnpj; | ||
if (CPF) { | ||
// TODO: Validar resto do input. | ||
zCustom.cpf().parse(CPF); | ||
cpfOrCnpj = { CPF }; | ||
} else { | ||
zCustom.cnpj().parse(CNPJ); | ||
cpfOrCnpj = { CNPJ } as CpfOrCnpj; | ||
} | ||
|
||
let operation: NfeDistribuicaoDfeOperation; | ||
if (distNSU) { | ||
operation = { distNSU }; | ||
} else if (consNSU) { | ||
operation = { consNSU }; | ||
} else if (consChNFe) { | ||
operation = { consChNFe }; | ||
} | ||
|
||
const { retDistDFeInt } = await this.request< | ||
NfeDistribuicaoDfeRequest, | ||
{ retDistDFeInt: NfeDistribuicaoDfeResponseRaw } | ||
>(this.getUrl("NFeDistribuicaoDFe"), { | ||
timeout: this.timeout, | ||
body: { | ||
"@_xmlns": | ||
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", | ||
distDFeInt: { | ||
...this.xmlNamespace, | ||
"@_versao": "4.00", | ||
tpAmb: this.tpAmb, | ||
cUFAutor: this.cUF, | ||
...cpfOrCnpj, | ||
...operation, | ||
}, | ||
}, | ||
}); | ||
|
||
const statusMap: Record<string, NfeDistribuicaoDfeStatus> = { | ||
"137": "nenhum-documento-localizado", | ||
"138": "documento-localizado", | ||
}; | ||
return { | ||
status: statusMap[retDistDFeInt.cStat] ?? "outro", | ||
description: retDistDFeInt.xMotivo ?? "", | ||
raw: retDistDFeInt, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Validação adicional e tratamento de erro
A introdução de distribuicaoDfe
está bem alinhada com os serviços existentes. Há alguns pontos de melhoria:
- A validação com
zCustom
para CPF/CNPJ é adequada, mas considere validar também campos comodistNSU
,consNSU
econsChNFe
(e.g., se o NSU é numérico). - Caso falte operação no objeto (nem
distNSU
, nemconsNSU
, nemconsChNFe
), avalie lançar um erro explícito para evitar requisições inválidas. - Alguns cenários de erro, como interrupções no parsing de resposta, podem ser cobertos por testes específicos, garantindo robustez.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/dfe/nfe/webServices/index.ts
(2 hunks)
🔇 Additional comments (3)
src/dfe/nfe/webServices/index.ts (3)
70-77
: LGTM!As importações dos novos tipos estão bem organizadas e seguem o padrão existente no arquivo.
519-520
: Implementar validação pendente conforme TODO.O comentário TODO indica que há validações pendentes para os demais campos de entrada. Considere validar também os campos numéricos como
distNSU
,consNSU
econsChNFe
.
527-534
:⚠️ Potential issueAdicionar validação para operação obrigatória.
A lógica atual não valida se pelo menos uma das operações (
distNSU
,consNSU
ouconsChNFe
) foi fornecida. Isso pode resultar em uma requisição inválida se nenhuma operação for especificada.Sugestão de implementação:
let operation: NfeDistribuicaoDfeOperation; if (distNSU) { operation = { distNSU }; } else if (consNSU) { operation = { consNSU }; } else { + if (!consChNFe) { + throw new Error( + "É necessário fornecer uma das operações: distNSU, consNSU ou consChNFe" + ); + } operation = { consChNFe }; }Likely invalid or redundant comment.
src/dfe/nfe/webServices/index.ts
Outdated
async distribuicaoDfe({ | ||
CPF, | ||
CNPJ, | ||
distNSU, | ||
consNSU, | ||
consChNFe, | ||
}: NfeDistribuicaoDfeOptions): Promise<NfeDistribuicaoDfeResponse> { | ||
let cpfOrCnpj: CpfOrCnpj; | ||
if (CPF) { | ||
// TODO: Validar resto do input. | ||
zCustom.cpf().parse(CPF); | ||
cpfOrCnpj = { CPF }; | ||
} else { | ||
zCustom.cnpj().parse(CNPJ); | ||
cpfOrCnpj = { CNPJ } as CpfOrCnpj; | ||
} | ||
|
||
let operation: NfeDistribuicaoDfeOperation; | ||
if (distNSU) { | ||
operation = { distNSU }; | ||
} else if (consNSU) { | ||
operation = { consNSU }; | ||
} else { | ||
operation = { consChNFe }; | ||
} | ||
|
||
const { retDistDFeInt } = await this.request< | ||
NfeDistribuicaoDfeRequest, | ||
{ retDistDFeInt: NfeDistribuicaoDfeResponseRaw } | ||
>(this.getUrl("NFeDistribuicaoDFe"), { | ||
timeout: this.timeout, | ||
body: { | ||
"@_xmlns": | ||
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", | ||
distDFeInt: { | ||
...this.xmlNamespace, | ||
"@_versao": "4.00", | ||
tpAmb: this.tpAmb, | ||
cUFAutor: this.cUF, | ||
...cpfOrCnpj, | ||
...operation, | ||
}, | ||
}, | ||
}); | ||
|
||
const statusMap: Record<string, NfeDistribuicaoDfeStatus> = { | ||
"137": "nenhum-documento-localizado", | ||
"138": "documento-localizado", | ||
}; | ||
return { | ||
status: statusMap[retDistDFeInt.cStat] ?? "outro", | ||
description: retDistDFeInt.xMotivo ?? "", | ||
raw: retDistDFeInt, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Adicionar documentação JSDoc ao método.
O método carece de documentação JSDoc, que é importante para manter o padrão de documentação da classe e facilitar o uso da API.
Sugestão de implementação:
/**
* @description Consulta documentos fiscais eletrônicos através do serviço de distribuição DFe.
*
* @param {NfeDistribuicaoDfeOptions} options - Opções para a consulta.
*
* @returns {Promise<NfeDistribuicaoDfeResponse>} O resultado da consulta.
*
* @throws {Zod.ZodError} Se o CPF ou CNPJ informado não for válido.
* @throws {TimeoutError} Se a requisição exceder o tempo limite.
* @throws {NfeServiceRequestError} Se ocorrer um erro durante a requisição.
*/
async distribuicaoDfe(...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Perfect! The JSDoc documentation has been added correctly and follows the codebase's documentation standards. This will make the API more maintainable and easier to use.
🔗 Analysis chain
@CayoPOliveira Thanks for adding the JSDoc documentation! This will help maintain consistency in the codebase and make the API more user-friendly.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for JSDoc documentation of distribuicaoDfe method
ast-grep --pattern $'/**
* @description $$$
*/
async distribuicaoDfe'
Length of output: 76
Script:
#!/bin/bash
# Search for distribuicaoDfe method with context
rg "async distribuicaoDfe" -B 10 "src/dfe/nfe/webServices/index.ts"
Length of output: 651
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
src/dfe/nfe/webServices/index.ts
Outdated
"@_xmlns": | ||
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrigir namespace do serviço.
O namespace utilizado está incorreto. O serviço de distribuição DFe deve usar seu próprio namespace.
- "@_xmlns":
- "http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4",
+ "@_xmlns":
+ "http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe4",
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"@_xmlns": | |
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", | |
"@_xmlns": | |
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Great! The namespace correction will ensure proper communication with the NFeDistribuicaoDFe service. 🎉
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
…rt multiple zip documents
…ument zip responses
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/dfe/nfe/webServices/index.ts (1)
535-609
: 🛠️ Refactor suggestionMelhore a implementação do método distribuicaoDfe.
O método precisa de melhorias em validação, documentação e tratamento de erros:
- Adicione documentação JSDoc (conforme revisão anterior)
- Valide os parâmetros de entrada
- Adicione tratamento de erro para operação ausente
- Melhore a segurança de tipos no tratamento das operações
Exemplo de implementação:
/** * @description Consulta documentos fiscais eletrônicos através do serviço de distribuição DFe. * * @param {NfeDistribuicaoDfeOptions} options - Opções para a consulta. * * @returns {Promise<NfeDistribuicaoDfeResponse>} O resultado da consulta. * * @throws {Zod.ZodError} Se o CPF ou CNPJ informado não for válido. * @throws {TimeoutError} Se a requisição exceder o tempo limite. * @throws {NfeServiceRequestError} Se ocorrer um erro durante a requisição. */ async distribuicaoDfe({ CPF, CNPJ, distNSU, consNSU, consChNFe, }: NfeDistribuicaoDfeOptions): Promise<NfeDistribuicaoDfeResponse> { // Validar CPF/CNPJ let cpfOrCnpj: CpfOrCnpj; if (CPF) { zCustom.cpf().parse(CPF); cpfOrCnpj = { CPF }; } else if (CNPJ) { zCustom.cnpj().parse(CNPJ); cpfOrCnpj = { CNPJ }; } else { throw new Error("CPF ou CNPJ deve ser informado"); } // Validar e construir operação let operation: NfeDistribuicaoDfeOperation; if (distNSU) { const ultNSU = distNSU.ultNSU.padStart(15, "0"); if (!/^\d{15}$/.test(ultNSU)) { throw new Error("ultNSU deve conter 15 dígitos numéricos"); } operation = { distNSU: { ultNSU } }; } else if (consNSU) { if (!/^\d{15}$/.test(consNSU.NSU)) { throw new Error("NSU deve conter 15 dígitos numéricos"); } operation = { consNSU }; } else if (consChNFe) { if (!/^\d{44}$/.test(consChNFe.chNFe)) { throw new Error("chNFe deve conter 44 dígitos numéricos"); } operation = { consChNFe }; } else { throw new Error("Uma operação deve ser informada: distNSU, consNSU ou consChNFe"); } // Restante da implementação... }
🧹 Nitpick comments (3)
src/dfe/nfe/webServices/requests/distribuicaoDfe.ts (3)
12-27
: Adicione validação e documentação para o tipo NfeDistribuicaoDfeOperation.O tipo está bem estruturado para garantir exclusividade mútua das operações, mas pode ser melhorado:
- Adicione validação de formato:
- NSU deve ser numérico
- chNFe deve ter 44 caracteres numéricos
- Adicione documentação JSDoc explicando cada operação
Exemplo de implementação:
/** * @description Define as operações possíveis para o serviço de distribuição DFe. * Apenas uma operação pode ser utilizada por vez. */ export type NfeDistribuicaoDfeOperation = | { /** @description Distribui documentos a partir do último NSU recebido */ distNSU: { ultNSU: string }; consNSU?: never; consChNFe?: never; } | { /** @description Consulta um documento específico pelo NSU */ distNSU?: never; consNSU: { NSU: string }; consChNFe?: never; } | { /** @description Consulta um documento específico pela chave de acesso */ distNSU?: never; consNSU?: never; consChNFe: { chNFe: string }; };
29-38
: Melhore a documentação do tipo NfeDistribuicaoDfeOptions com exemplos.A documentação atual está boa, mas pode ser melhorada com exemplos de uso para cada operação.
Exemplo de implementação:
/** * @description Opções para configurar o web service de NFeDistribuiçãoDFe. * * @property CPF | CNPJ - CPF ou CNPJ do interessado no DF-e * @property distNSU | consNSU | consChNFe - Operação a ser realizada * @property distNSU.ultNSU - Último NSU recebido pelo autor * @property consNSU.NSU - NSU específico a ser consultado * @property consChNFe.chNFe - Chave da NFe a ser consultada * * @example * // Distribuição por NSU * const options = { * CNPJ: "12345678901234", * distNSU: { ultNSU: "000000000000000" } * }; * * @example * // Consulta por NSU específico * const options = { * CNPJ: "12345678901234", * consNSU: { NSU: "000000000000123" } * }; * * @example * // Consulta por chave de NFe * const options = { * CNPJ: "12345678901234", * consChNFe: { chNFe: "12345678901234567890123456789012345678901234" } * }; */
40-48
: Adicione documentação para os tipos restantes.Os tipos NfeDistribuicaoDfeRequest, NfeDistribuicaoDfeStatus e NfeDistribuicaoDfeResponse carecem de documentação JSDoc.
Exemplo de implementação:
/** * @description Estrutura da requisição para o serviço de distribuição DFe. */ export type NfeDistribuicaoDfeRequest = { distDFeInt: WithXmlnsVersao<{ tpAmb: "1" | "2"; cUFAutor: UFCode; } & CpfOrCnpj & NfeDistribuicaoDfeOperation>; }; /** * @description Status possíveis para a resposta do serviço de distribuição DFe. */ export type NfeDistribuicaoDfeStatus = | "documento-localizado" | "nenhum-documento-localizado"; /** * @description Resposta do serviço de distribuição DFe. */ export type NfeDistribuicaoDfeResponse = NfeWebServiceResponse< NfeDistribuicaoDfeStatus, NfeDistribuicaoDfeResponseRaw >;Also applies to: 80-87
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/dfe/nfe/webServices/__snapshots__/index.test.ts.snap
is excluded by!**/*.snap
📒 Files selected for processing (3)
src/dfe/nfe/webServices/index.test.ts
(1 hunks)src/dfe/nfe/webServices/index.ts
(10 hunks)src/dfe/nfe/webServices/requests/distribuicaoDfe.ts
(1 hunks)
🔇 Additional comments (1)
src/dfe/nfe/webServices/index.ts (1)
561-598
: LGTM! A implementação do request está correta.O código segue o mesmo padrão dos outros métodos, com:
- URL e timeout corretos
- Namespace específico do serviço
- Tratamento de arrays para docZip
/** | ||
* @description Resposta completa da consulta de status serviço. | ||
* | ||
* @property tpAmb - Tipo de ambiente: 1-Produção 2-Homologação. | ||
* @property verAplic - Versão do aplicativo que processou a consulta. | ||
* @property cStat - `"137"->"nenhum-documento-localizado"`, `"138"->"documento-localizado"`. | ||
* @property xMotivo - Descrição da resposta. | ||
* @property dhResp - Data e hora da resposta. | ||
* @property [ultNSU] - Último NSU processado. | ||
* @property [maxNSU] - Maior NSU encontrado. | ||
* @property [loteDistDFeInt] - Lote de distribuição de DF-e. | ||
* @property loteDistDFeInt.docZip - Array de documentos zipados. | ||
* @property loteDistDFeInt["@_NSU"] - NSU do lote. | ||
* @property loteDistDFeInt["@_schema"] - Schema do lote. | ||
*/ | ||
export type NfeDistribuicaoDfeResponseRaw = WithVersao<{ | ||
tpAmb: "1" | "2"; | ||
verAplic: string; | ||
cStat: LiteralStringUnion<"137" | "138">; | ||
xMotivo: string; | ||
dhResp: string; | ||
ultNSU?: string; | ||
maxNSU?: string; | ||
loteDistDFeInt?: { | ||
docZip: string[]; | ||
"@_NSU": string; | ||
"@_schema": string; | ||
}; | ||
}>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Corrija a documentação do tipo NfeDistribuicaoDfeResponseRaw.
A documentação atual contém um erro, mencionando "consulta de status serviço" ao invés de "distribuição DFe".
Corrija para:
/**
* @description Resposta completa da distribuição DFe.
*
* @property tpAmb - Tipo de ambiente: 1-Produção 2-Homologação
* @property verAplic - Versão do aplicativo que processou a consulta
* @property cStat - `"137"->"nenhum-documento-localizado"`, `"138"->"documento-localizado"`
* @property xMotivo - Descrição da resposta
* @property dhResp - Data e hora da resposta
* @property [ultNSU] - Último NSU processado
* @property [maxNSU] - Maior NSU encontrado
* @property [loteDistDFeInt] - Lote de distribuição de DF-e
* @property loteDistDFeInt.docZip - Array de documentos zipados
* @property loteDistDFeInt["@_NSU"] - NSU do lote
* @property loteDistDFeInt["@_schema"] - Schema do lote
*/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Thanks for making the fix!
🔗 Analysis chain
@CayoPOliveira Thanks for making the fix!
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check the current content of the file
cat src/dfe/nfe/webServices/requests/distribuicaoDfe.ts
Length of output: 2609
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
describe("distribuicaoDfe", () => { | ||
const url = getWebServiceUrl({ uf, env, service: "NFeDistribuicaoDFe" }); | ||
|
||
test("Returns valid response", async () => { | ||
mockRequest(url, { | ||
method: "POST", | ||
response: { | ||
data: buildMockResponse({ | ||
nfeDistDFeInteresseResponse: { | ||
nfeDistDFeInteresseResult: { | ||
retDistDFeInt: { | ||
tpAmb: "2", | ||
cStat: "138", | ||
xMotivo: "Documento localizado", | ||
dhResp: "2025-01-24T08:00:00-03:00", | ||
ultNSU: "0", | ||
maxNSU: "0", | ||
loteDistDFeInt: { | ||
"@_NSU": "0", | ||
"@_schema": "resNFe_v1.00.xsd", | ||
docZip: "NFe compactada no padrão gZip", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}), | ||
}, | ||
}); | ||
expect( | ||
await service.distribuicaoDfe({ | ||
CNPJ: "12345678901230", | ||
consChNFe: { | ||
chNFe: "0".repeat(44), | ||
}, | ||
}), | ||
).toMatchSnapshot(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Melhore a cobertura de testes do método distribuicaoDfe.
O teste atual cobre apenas o caso de sucesso com a operação consChNFe. Sugiro adicionar mais casos de teste:
-
Casos de erro:
- CPF/CNPJ inválido
- Timeout na requisição
- Erro na resposta do serviço
-
Diferentes operações:
- Distribuição por NSU (distNSU)
- Consulta por NSU específico (consNSU)
-
Diferentes status:
- Nenhum documento localizado (137)
- Erro genérico
Exemplo de implementação:
describe("distribuicaoDfe", () => {
const url = getWebServiceUrl({ uf, env, service: "NFeDistribuicaoDFe" });
test("Returns valid response for consChNFe", async () => {
// ... teste atual ...
});
test("Returns valid response for distNSU", async () => {
mockRequest(url, {
method: "POST",
response: {
data: buildMockResponse({
nfeDistDFeInteresseResponse: {
nfeDistDFeInteresseResult: {
retDistDFeInt: {
tpAmb: "2",
cStat: "138",
xMotivo: "Documento localizado",
dhResp: "2025-01-24T08:00:00-03:00",
ultNSU: "000000000000123",
maxNSU: "000000000000123",
loteDistDFeInt: {
"@_NSU": "000000000000123",
"@_schema": "resNFe_v1.00.xsd",
docZip: ["NFe1", "NFe2"],
},
},
},
},
}),
},
});
expect(
await service.distribuicaoDfe({
CNPJ: "12345678901230",
distNSU: { ultNSU: "000000000000123" },
}),
).toMatchSnapshot();
});
test("Returns valid response for consNSU", async () => {
mockRequest(url, {
method: "POST",
response: {
data: buildMockResponse({
nfeDistDFeInteresseResponse: {
nfeDistDFeInteresseResult: {
retDistDFeInt: {
tpAmb: "2",
cStat: "138",
xMotivo: "Documento localizado",
dhResp: "2025-01-24T08:00:00-03:00",
ultNSU: "000000000000123",
maxNSU: "000000000000123",
loteDistDFeInt: {
"@_NSU": "000000000000123",
"@_schema": "resNFe_v1.00.xsd",
docZip: ["NFe"],
},
},
},
},
}),
},
});
expect(
await service.distribuicaoDfe({
CNPJ: "12345678901230",
consNSU: { NSU: "000000000000123" },
}),
).toMatchSnapshot();
});
test("Returns no documents found", async () => {
mockRequest(url, {
method: "POST",
response: {
data: buildMockResponse({
nfeDistDFeInteresseResponse: {
nfeDistDFeInteresseResult: {
retDistDFeInt: {
tpAmb: "2",
cStat: "137",
xMotivo: "Nenhum documento localizado",
dhResp: "2025-01-24T08:00:00-03:00",
ultNSU: "000000000000123",
maxNSU: "000000000000123",
},
},
},
}),
},
});
expect(
await service.distribuicaoDfe({
CNPJ: "12345678901230",
distNSU: { ultNSU: "000000000000123" },
}),
).toMatchSnapshot();
});
test("Throws ZodError for invalid CNPJ", () => {
expect(() =>
service.distribuicaoDfe({
CNPJ: "12345678901299",
distNSU: { ultNSU: "000000000000123" },
}),
).toThrowError(ZodError);
});
test("Throws error on timeout", () => {
mockRequest(url, {
method: "POST",
throw: new Error("The operation timed out."),
});
expect(() =>
service.distribuicaoDfe({
CNPJ: "12345678901230",
distNSU: { ultNSU: "000000000000123" },
}),
).toThrowError("The operation timed out.");
});
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Adicionei apenas a validação de CPF e CNPJ, as demais, como vou remover em outra PR a abstração e retornar a resposta completa, não achei esses testes uteis por agora
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Entendi, faz sentido manter apenas os testes de validação por enquanto, já que você planeja remover a abstração em outro PR.
(`・ω・´)ゞ
✏️ Learnings added
Learnt from: CayoPOliveira
PR: fazendatech/brafis#38
File: src/dfe/nfe/webServices/index.test.ts:0-0
Timestamp: 2025-01-27T01:09:41.425Z
Learning: The abstraction layer in the NFe distribution service will be removed in a future PR to return the complete response instead of the current abstracted version.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
src/dfe/nfe/webServices/index.ts
Outdated
import type { | ||
NfeDistribuicaoDfeOperation, | ||
NfeDistribuicaoDfeOptions, | ||
NfeDistribuicaoDfeRequest, | ||
NfeDistribuicaoDfeResponse, | ||
NfeDistribuicaoDfeResponseRaw, | ||
NfeDistribuicaoDfeStatus, | ||
} from "./requests/distribuicaoDfe"; | ||
import { updateLanguageServiceSourceFile } from "typescript"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remova a importação não utilizada.
A importação updateLanguageServiceSourceFile
do módulo typescript
não está sendo utilizada.
Remova a linha:
-import { updateLanguageServiceSourceFile } from "typescript";
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import type { | |
NfeDistribuicaoDfeOperation, | |
NfeDistribuicaoDfeOptions, | |
NfeDistribuicaoDfeRequest, | |
NfeDistribuicaoDfeResponse, | |
NfeDistribuicaoDfeResponseRaw, | |
NfeDistribuicaoDfeStatus, | |
} from "./requests/distribuicaoDfe"; | |
import { updateLanguageServiceSourceFile } from "typescript"; | |
import type { | |
NfeDistribuicaoDfeOperation, | |
NfeDistribuicaoDfeOptions, | |
NfeDistribuicaoDfeRequest, | |
NfeDistribuicaoDfeResponse, | |
NfeDistribuicaoDfeResponseRaw, | |
NfeDistribuicaoDfeStatus, | |
} from "./requests/distribuicaoDfe"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Great! Thank you for removing the unused import.
🐰 happy bunny noises
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/dfe/nfe/webServices/index.ts
(13 hunks)
🔇 Additional comments (1)
src/dfe/nfe/webServices/index.ts (1)
70-77
: LGTM!As importações dos tipos necessários para a funcionalidade de distribuição DFe estão bem organizadas.
}: NfeDistribuicaoDfeOptions): Promise<NfeDistribuicaoDfeResponse> { | ||
let cpfOrCnpj: CpfOrCnpj; | ||
if (CPF) { | ||
// TODO: Validar resto do input. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Implementar validação completa dos parâmetros.
O TODO indica que falta validação dos parâmetros, mas não especifica quais validações são necessárias.
Sugestão de implementação:
// Validar formato e comprimento do NSU
if (distNSU?.ultNSU) {
if (!/^\d+$/.test(distNSU.ultNSU)) {
throw new Error("ultNSU deve conter apenas dígitos");
}
if (distNSU.ultNSU.length > 15) {
throw new Error("ultNSU deve ter no máximo 15 dígitos");
}
}
// Validar formato do NSU específico
if (consNSU?.NSU) {
if (!/^\d{15}$/.test(consNSU.NSU)) {
throw new Error("NSU deve conter exatamente 15 dígitos");
}
}
// Validar formato da chave NFe
if (consChNFe?.chNFe) {
if (!/^\d{44}$/.test(consChNFe.chNFe)) {
throw new Error("chNFe deve conter exatamente 44 dígitos");
}
}
src/dfe/nfe/webServices/index.ts
Outdated
let operation: NfeDistribuicaoDfeOperation; | ||
if (distNSU) { | ||
operation = { distNSU: { ultNSU: distNSU.ultNSU.padStart(15, "0") } }; | ||
} else if (consNSU) { | ||
operation = { consNSU }; | ||
} else { | ||
operation = { consChNFe }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Melhorar a lógica de seleção da operação.
A lógica atual não valida se múltiplas operações foram fornecidas simultaneamente, o que pode levar a comportamentos inesperados.
Sugestão de implementação:
let operation: NfeDistribuicaoDfeOperation;
const operationCount = [distNSU, consNSU, consChNFe].filter(Boolean).length;
if (operationCount === 0) {
throw new Error("É necessário fornecer uma operação: distNSU, consNSU ou consChNFe");
} else if (operationCount > 1) {
throw new Error("Apenas uma operação pode ser fornecida por vez");
}
if (distNSU) {
operation = { distNSU: { ultNSU: distNSU.ultNSU.padStart(15, "0") } };
} else if (consNSU) {
operation = { consNSU };
} else {
operation = { consChNFe };
}
src/dfe/nfe/webServices/index.ts
Outdated
/** | ||
* @description Consulta a distribuição de informações resumidas e documentos fiscais eletrônicos de interesse de um ator, seja este uma pessoa física ou jurídica. | ||
* | ||
* @param {NfeRecepcaoEventoOptions} options - Opções para o serviço. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrigir tipo no JSDoc.
O tipo do parâmetro options
está incorreto no JSDoc.
- * @param {NfeRecepcaoEventoOptions} options - Opções para o serviço.
+ * @param {NfeDistribuicaoDfeOptions} options - Opções para o serviço.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
* @param {NfeRecepcaoEventoOptions} options - Opções para o serviço. | |
* @param {NfeDistribuicaoDfeOptions} options - Opções para o serviço. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CayoPOliveira Thanks for fixing the JSDoc parameter type! 🎉
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
O webservice NFeDistribuicaoDFe
possui outros campos na estrutura de request e response, devido a isso deixei o método request mais genérico e atualizei os tipos nos demais webservices.
Irei criar uma nova PR para atualizar os tipos corretamente nos arquivos de tipo.
Reviewed 4 of 4 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status: all files reviewed, 13 unresolved discussions (waiting on @coderabbitai[bot])
src/dfe/nfe/webServices/index.ts
line 131 at r3 (raw file):
const response = await fetchWithTls(url, { method: "POST", headers: { "Content-Type": "application/soap+xml; charset=utf-8" },
O método request agora apenas encapsula e desencapsula o SOAP
src/dfe/nfe/webServices/index.ts
line 166 at r3 (raw file):
const { nfeResultMsg: { retConsStatServ }, } = await this.request<
Essa é a atualização de tipos que falei, irei criar uma PR separada para incluir adequadamente esses tipos
src/dfe/nfe/webServices/index.ts
line 565 at r3 (raw file):
nfeDistDFeInteresseResult: { retDistDFeInt }, }, } = await this.request<
A estrutura desse serviço dentro do SOAP é diferente dos demais webservices
src/dfe/nfe/webServices/index.ts
Outdated
"@_xmlns": | ||
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/dfe/nfe/webServices/index.ts
Outdated
async distribuicaoDfe({ | ||
CPF, | ||
CNPJ, | ||
distNSU, | ||
consNSU, | ||
consChNFe, | ||
}: NfeDistribuicaoDfeOptions): Promise<NfeDistribuicaoDfeResponse> { | ||
let cpfOrCnpj: CpfOrCnpj; | ||
if (CPF) { | ||
// TODO: Validar resto do input. | ||
zCustom.cpf().parse(CPF); | ||
cpfOrCnpj = { CPF }; | ||
} else { | ||
zCustom.cnpj().parse(CNPJ); | ||
cpfOrCnpj = { CNPJ } as CpfOrCnpj; | ||
} | ||
|
||
let operation: NfeDistribuicaoDfeOperation; | ||
if (distNSU) { | ||
operation = { distNSU }; | ||
} else if (consNSU) { | ||
operation = { consNSU }; | ||
} else { | ||
operation = { consChNFe }; | ||
} | ||
|
||
const { retDistDFeInt } = await this.request< | ||
NfeDistribuicaoDfeRequest, | ||
{ retDistDFeInt: NfeDistribuicaoDfeResponseRaw } | ||
>(this.getUrl("NFeDistribuicaoDFe"), { | ||
timeout: this.timeout, | ||
body: { | ||
"@_xmlns": | ||
"http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4", | ||
distDFeInt: { | ||
...this.xmlNamespace, | ||
"@_versao": "4.00", | ||
tpAmb: this.tpAmb, | ||
cUFAutor: this.cUF, | ||
...cpfOrCnpj, | ||
...operation, | ||
}, | ||
}, | ||
}); | ||
|
||
const statusMap: Record<string, NfeDistribuicaoDfeStatus> = { | ||
"137": "nenhum-documento-localizado", | ||
"138": "documento-localizado", | ||
}; | ||
return { | ||
status: statusMap[retDistDFeInt.cStat] ?? "outro", | ||
description: retDistDFeInt.xMotivo ?? "", | ||
raw: retDistDFeInt, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/dfe/nfe/webServices/index.ts
Outdated
import type { | ||
NfeDistribuicaoDfeOperation, | ||
NfeDistribuicaoDfeOptions, | ||
NfeDistribuicaoDfeRequest, | ||
NfeDistribuicaoDfeResponse, | ||
NfeDistribuicaoDfeResponseRaw, | ||
NfeDistribuicaoDfeStatus, | ||
} from "./requests/distribuicaoDfe"; | ||
import { updateLanguageServiceSourceFile } from "typescript"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/dfe/nfe/webServices/index.ts
Outdated
/** | ||
* @description Consulta a distribuição de informações resumidas e documentos fiscais eletrônicos de interesse de um ator, seja este uma pessoa física ou jurídica. | ||
* | ||
* @param {NfeRecepcaoEventoOptions} options - Opções para o serviço. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
describe("distribuicaoDfe", () => { | ||
const url = getWebServiceUrl({ uf, env, service: "NFeDistribuicaoDFe" }); | ||
|
||
test("Returns valid response", async () => { | ||
mockRequest(url, { | ||
method: "POST", | ||
response: { | ||
data: buildMockResponse({ | ||
nfeDistDFeInteresseResponse: { | ||
nfeDistDFeInteresseResult: { | ||
retDistDFeInt: { | ||
tpAmb: "2", | ||
cStat: "138", | ||
xMotivo: "Documento localizado", | ||
dhResp: "2025-01-24T08:00:00-03:00", | ||
ultNSU: "0", | ||
maxNSU: "0", | ||
loteDistDFeInt: { | ||
"@_NSU": "0", | ||
"@_schema": "resNFe_v1.00.xsd", | ||
docZip: "NFe compactada no padrão gZip", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}), | ||
}, | ||
}); | ||
expect( | ||
await service.distribuicaoDfe({ | ||
CNPJ: "12345678901230", | ||
consChNFe: { | ||
chNFe: "0".repeat(44), | ||
}, | ||
}), | ||
).toMatchSnapshot(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Adicionei apenas a validação de CPF e CNPJ, as demais, como vou remover em outra PR a abstração e retornar a resposta completa, não achei esses testes uteis por agora
/** | ||
* @description Resposta completa da consulta de status serviço. | ||
* | ||
* @property tpAmb - Tipo de ambiente: 1-Produção 2-Homologação. | ||
* @property verAplic - Versão do aplicativo que processou a consulta. | ||
* @property cStat - `"137"->"nenhum-documento-localizado"`, `"138"->"documento-localizado"`. | ||
* @property xMotivo - Descrição da resposta. | ||
* @property dhResp - Data e hora da resposta. | ||
* @property [ultNSU] - Último NSU processado. | ||
* @property [maxNSU] - Maior NSU encontrado. | ||
* @property [loteDistDFeInt] - Lote de distribuição de DF-e. | ||
* @property loteDistDFeInt.docZip - Array de documentos zipados. | ||
* @property loteDistDFeInt["@_NSU"] - NSU do lote. | ||
* @property loteDistDFeInt["@_schema"] - Schema do lote. | ||
*/ | ||
export type NfeDistribuicaoDfeResponseRaw = WithVersao<{ | ||
tpAmb: "1" | "2"; | ||
verAplic: string; | ||
cStat: LiteralStringUnion<"137" | "138">; | ||
xMotivo: string; | ||
dhResp: string; | ||
ultNSU?: string; | ||
maxNSU?: string; | ||
loteDistDFeInt?: { | ||
docZip: string[]; | ||
"@_NSU": string; | ||
"@_schema": string; | ||
}; | ||
}>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 4 files at r3, 3 of 3 files at r5, 1 of 1 files at r6, all commit messages.
Dismissed @coderabbitai[bot] from 10 discussions.
Reviewable status: complete! all files reviewed, all discussions resolved (waiting on @CayoPOliveira)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/dfe/nfe/webServices/index.ts
(13 hunks)
🧰 Additional context used
📓 Learnings (1)
src/dfe/nfe/webServices/index.ts (1)
Learnt from: CayoPOliveira
PR: fazendatech/brafis#38
File: src/dfe/nfe/webServices/index.test.ts:0-0
Timestamp: 2025-01-27T01:09:41.872Z
Learning: The abstraction layer in the NFe distribution service will be removed in a future PR to return the complete response instead of the current abstracted version.
🔇 Additional comments (3)
src/dfe/nfe/webServices/index.ts (3)
70-77
: LGTM!As importações dos tipos para o serviço de distribuição DFe seguem o padrão estabelecido no código.
573-610
: LGTM!A estrutura da requisição SOAP e o processamento da resposta estão implementados corretamente.
612-620
: LGTM!O mapeamento de status e a estrutura da resposta seguem o padrão estabelecido no código.
This change is
Summary by CodeRabbit
Novos Recursos
Testes
Melhorias de Tipo