Skip to content

fix(infProt): modela o grupo PR13 como ocorrências repetíveis (alertas do cStat=120) - #88

Open
rhfranzoni wants to merge 1 commit into
masterfrom
feat/pr13-alert-group
Open

fix(infProt): modela o grupo PR13 como ocorrências repetíveis (alertas do cStat=120)#88
rhfranzoni wants to merge 1 commit into
masterfrom
feat/pr13-alert-group

Conversation

@rhfranzoni

Copy link
Copy Markdown

Resumo

Modela o grupo PR13 do protocolo como ocorrências repetíveis, em vez do par escalar cMsg/xMsg que existia.

O leiaute descreve o PR13 como grupo de 0 a 5 ocorrências, sem elemento agrupador ("Sequência XML"), com PR14 cMsg em 0-1 (opcional) e PR15 xMsg em 1-1 (obrigatório). A NT 2018.005 criou o grupo; a NT 2026.002 §2.3 o ampliou ao introduzir o cStat=120"Autorizado o uso da NF-e, com alerta" — que devolve até 5 alertas por nota.

O problema

infProt mapeava cMsg e xMsg em propriedades escalares. Com XmlSerializer, ocorrências repetidas do mesmo elemento colapsam: só a última sobrevive à desserialização.

Uma nota autorizada com 5 alertas chegava ao consumidor com 1 — silenciosamente, e sem meio de perceber a perda. O consumidor não tem como distinguir "veio 1 alerta" de "vieram 5 e 4 se perderam".

A modelagem

Coleção de escolha com XmlChoiceIdentifier:

[XmlElement("cMsg", typeof(string))]
[XmlElement("xMsg", typeof(string))]
[XmlChoiceIdentifier(nameof(MensagensTipos))]
public string[] Mensagens { get; set; }

[XmlIgnore]
public TipoMensagemProtocolo[] MensagensTipos { get; set; }

É o único arranjo do XmlSerializer que preserva a ordem entre dois nomes de elemento distintos — e é a ordem que permite reconstruir cada ocorrência: o cMsg imediatamente anterior a um xMsg é o código daquela ocorrência.

Mapear em duas listas paralelas (List<string> cMsgs / List<string> xMsgs) não funciona: como o cMsg é opcional, o pareamento por índice desalinha assim que uma ocorrência vem sem código.

API resultante

Membro Papel
Mensagens + MensagensTipos coleção crua, na ordem do documento
Alertas ocorrências já reconstruídas em pares (Codigo, Mensagem); Codigo é anulável porque o cMsg é opcional
cMsg / xMsg mantidos, agora como projeções da primeira ocorrência

O agrupamento é ancorado no xMsg, que é o campo obrigatório: cada xMsg encerra uma ocorrência. Um cMsg sem xMsg seguinte não forma ocorrência, conforme o leiaute.

Compatibilidade

cMsg e xMsg continuam existindo e devolvem a primeira ocorrência — o consumidor interno NFe.Danfe.Nativo/NFCe/DanfeNativoNfce.cs usa infProt.xMsg e segue funcionando sem alteração. Passaram a ser somente-leitura (antes o cMsg tinha setter usado apenas pelo próprio proxy de serialização).

Também

Corrige o doc comment de Signature, rotulado PR13 quando é PR90.

Testes

NFCe.Tests/InfProtAlertGroupTests.cs6 testes, todos passando:

  • múltiplas ocorrências preservadas na ordem do documento;
  • ocorrência sem cMsg preservada com código nulo;
  • protocolo sem o grupo → lista vazia;
  • cMsg órfão não forma ocorrência;
  • campos escalares seguem expondo a primeira ocorrência;
  • round-trip preservando a contagem exata de cMsg e xMsg.

A única falha da suíte, ServicosNFe_WhenNfeNFeAutorizacao4_ReturnsxMotivoSuccess, é pré-existente e sem relação: o teste aponta para um caminho absoluto de outra máquina (C:\Works\nfe\nfe-products-api\schemas).

Contexto

Vem de nfe/dfetech-product-invoice-api#423, que expõe os alertas do cStat=120 na API e no webhook. Lá o produto contorna a limitação com um parser próprio sobre o XML bruto do protocolo, justamente porque a lib colapsava as ocorrências. Com este PR mergeado, o consumidor passa a poder usar infProt.Alertas direto, e o nfeProc remontado volta a poder carregar o grupo — hoje ele sai sem os alertas, divergindo do que a API expõe.

… de par escalar

O leiaute do protocolo descreve o PR13 como grupo de 0 a 5 ocorrências, sem
elemento agrupador ("Sequência XML"), com PR14 cMsg em 0-1 (opcional) e PR15
xMsg em 1-1 (obrigatório) — ver NT 2018.005 e a ampliação da NT 2026.002 §2.3,
que criou o cStat=120 ("Autorizado o uso da NF-e, com alerta") e passou a usar
o grupo para devolver até 5 alertas.

infProt mapeava cMsg e xMsg em propriedades ESCALARES. Com XmlSerializer, as
ocorrências repetidas colapsam: só a última sobrevive à desserialização. Uma
nota autorizada com 5 alertas chegava ao consumidor com 1 — silenciosamente, e
sem meio de perceber a perda.

Modelagem: coleção de escolha com XmlChoiceIdentifier. É o único arranjo do
XmlSerializer que preserva a ORDEM entre dois nomes de elemento distintos, e é
a ordem que permite reconstruir cada ocorrência — o cMsg imediatamente anterior
a um xMsg é o código daquela ocorrência.

- `Mensagens` + `MensagensTipos`: a coleção crua, na ordem do documento.
- `Alertas`: as ocorrências já reconstruídas em pares (Codigo, Mensagem), com
  Codigo anulável porque o cMsg é opcional. cMsg sem xMsg seguinte não forma
  ocorrência, conforme o leiaute.
- `cMsg` e `xMsg` permanecem, agora como projeções da primeira ocorrência, para
  não quebrar quem já os consumia — NFe.Danfe.Nativo/NFCe/DanfeNativoNfce.cs
  usa infProt.xMsg.

Também corrige o doc comment do Signature, que estava rotulado PR13 quando é
PR90.

Testes (NFCe.Tests/InfProtAlertGroupTests.cs): múltiplas ocorrências na ordem
do documento; ocorrência sem cMsg preservada com código nulo; protocolo sem o
grupo; cMsg órfão; compatibilidade dos campos escalares; e round-trip
preservando a contagem exata de cMsg e xMsg.

NFCe.Tests: 6 novos testes passam. A única falha da suíte
(ServicosNFe_WhenNfeNFeAutorizacao4_ReturnsxMotivoSuccess) é pré-existente e
sem relação — o teste aponta para um caminho absoluto de outra máquina
(C:\Works\nfe\nfe-products-api\schemas).
@rhfranzoni
rhfranzoni requested a review from john182 August 8, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant