Skip to content

fix(nfse): municípios da API própria do provedor saem no Padrão Nacional - #24

Merged
rodrigofs merged 2 commits into
mainfrom
fix/nfse-apipropria-layout
Oct 3, 2026
Merged

rodrigofs merged 2 commits into
mainfrom
fix/nfse-apipropria-layout

Conversation

@rodrigofs

@rodrigofs rodrigofs commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Em 608 municípios o POST /v1/nfse/xml devolvia uma DPS do Padrão Nacional montada com o INI do ABRASF, e respondia validacao.ok: true. O XML não servia ao provedor nem ao Padrão Nacional.

Exemplo, Brasília (5300108, ISSNet) contra Porto Alegre com o mesmo pedido: cTribNac saía 01.05 em vez de 010501, aparecia <cTribMun>0</cTribMun>, opSimpNac ia de 3 para 2, regApTribSN sumia e pTotTribSN virava vTotTrib zerado.

Causa

A lib escolhe o gravador por município. Quando os Params do município ou do provedor têm APIPropria: e a versão resolvida é 1.00 ou 1.01 (TGeralConfNFSe.SetCodigoMunicipio), o GetProvider instancia a classe *APIPropria do provedor. O gravador dela descende de TNFSeW_PadraoNacional. Brasília não declara Versao, herda Versao=1.01 e APIPropria: da seção [ISSNet], e emite DPS 1.01 pelo wsnfsenacional do ISSNet.

O roteamento daqui decidia só pela família do provedor (provedor_familia.tsv), e o ISSNet é abrasf_v1_v2.

Afetados, por provedor: Betha 227, Pronim 157, ABase 37, EL 31, Citta 23, Coplan 21, ISSNet 20, SimplISS 20, Digifred 13, Fiorilli 12, SilTecnologia 9, Infisc 9, RLZ 8, ModernizacaoPublica 6, Tiplan 4, SpeedGov 3, DBSeller 3, ISSDigital 3, DSF 2.

Mudanças

  • scripts/gerar-tabelas-nfse.py marca esses municípios numa quarta coluna de municipios_provedor.tsv, com a regra da lib. A seção do provedor é buscada sem diferenciar caixa, como no TIniFile: Esperança do Sul declara Provedor=Abase e a seção é [ABase].
  • LayoutDoMunicipio devolve padrao_nacional para eles e o pedido vai pelo ToINI.
  • Credenciais de prefeitura passam a depender do provedor, não do layout. ABase e EL leem WSChaveAcesso e ModernizacaoPublica lê WSUser e WSSenha na API própria; com a regra antiga, a troca de layout as descartaria.
  • O /xml confere a raiz do XML contra o layout. Padrão Nacional é raiz DPS (o Fiorilli usa namespace próprio) ou qualquer raiz no namespace http://www.sped.fazenda.gov.br/nfse (Citta, Digifred, SilTecnologia e DBSeller geram NFSe). Divergência vira 500 layout_divergente e o XML não é devolvido.
  • serv.cTribMun passa a ser obrigatório no ISSNet pela API própria. O gravador o emite como inteiro com StrToIntDef(..., 0), e sem o campo a DPS saía com <cTribMun>0</cTribMun>, que Brasília recusou em homologação com EM020, E244 e EM076. O /xml e a substituição por DPS respondem 400 campo_obrigatorio. Nos outros provedores o campo segue opcional: no Padrão Nacional ele é opcional no gravador, e nos dois ABRASF que o exigem (ISSGoiania e Centi) a lib já acusa a tag vazia.
  • make acbr-tabelas-conferir falha se a tabela divergir do fonte pinado.
  • make test-integracao-nfse gera o XML contra uma API com worker, um município por (provedor, versão, API própria), e cobra a raiz.

O que o cliente vê

GET /v1/nfse/municipios/{codigo} e a resposta do /xml passam a dizer layout: padrao_nacional nesses 608 municípios, com o mesmo provedor. Para eles valem os campos do Padrão Nacional do infDPS: serv.cServ com 6 dígitos, regApTribSN, pTotTribSN. No ISSNet, serv.cTribMun é obrigatório.

Fora deste PR

  • Cancelamento e substituição seguem o layout, então nesses municípios passam a ir por evento e por subst na DPS. Para a maioria isso é o certo, porque as classes APIPropria sobrescrevem o EnviarEvento. O Coplan cancela por CancelaNFSe e substitui por SubstituiNFSe, e oito classes herdam o evento do Padrão Nacional sem sobrescrever. Vai num PR separado.
  • Nenhum desses municípios foi transmitido em homologação.
  • O Aspec (1500909) devolve a mensagem "" is an invalid integer no lugar do XML. É anterior a este PR, e a guarda não o pega porque provedor próprio pode montar JSON ou TXT.

Verificação

  • make test, vet, fmt-check, openapi-check e acbr-tabelas-conferir passam.
  • Mutando o roteamento, a regra de credencial ou a guarda, os testes novos falham.
  • make test-integracao-nfse com a API deste branch sobre o worker da v1.3.1: 122 combinações passam, 21 delas com API própria. Contra a API da v1.3.1, falham exatamente essas 21.

Em 608 municípios o /v1/nfse/xml devolvia uma DPS com valores do ABRASF:
cTribNac "01.05", cTribMun 0, vTotTrib no lugar de pTotTribSN, com
validacao.ok. Brasília e Goiânia no ISSNet e Campo Grande no DSF entre eles.

Nesses municípios a lib instancia a classe APIPropria do provedor, cujo
gravador descende do Padrão Nacional e gera DPS. O roteamento olhava só a
família do provedor e mandava o INI do ABRASF.

O gerador da tabela passa a marcar esses municípios com a regra da lib
(Params com APIPropria:, versão resolvida 1.00 ou 1.01, ramo no GetProvider),
e o layout deles é padrao_nacional. As credenciais de prefeitura passam a
depender do provedor, não do layout: ABase, EL e ModernizacaoPublica
autenticam na API própria.

O /xml confere a raiz do XML contra o layout e responde 500
layout_divergente em vez de devolver XML de leiaute trocado.
make acbr-tabelas-conferir e make test-integracao-nfse cobram os dois lados.
O gravador do ISSNet pela API própria emite cTribMun obrigatório como
inteiro, com StrToIntDef(..., 0). Sem o campo, ou com texto, a DPS saía com
<cTribMun>0</cTribMun>, sem alerta da lib, e Brasília recusou com EM020,
E244 e EM076.

O /xml e a substituição por DPS respondem 400 campo_obrigatorio quando o
município é do ISSNet pela API própria e serv.cTribMun não é numérico, não
zero e dentro do Integer de 32 bits. Nos demais provedores o campo segue
opcional.
@rodrigofs
rodrigofs force-pushed the fix/nfse-apipropria-layout branch from 9031500 to 18e4106 Compare October 3, 2026 20:34
@rodrigofs
rodrigofs merged commit 6145dd8 into main Oct 3, 2026
10 checks passed
@rodrigofs
rodrigofs deleted the fix/nfse-apipropria-layout branch October 3, 2026 20:37
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