sowai-fiscal
Núcleo fiscal puro da SowAI: motor de regras tributário (imposto-como-dado),
chave de acesso de NF-e (módulo 11) e builder do XML NF-e 55 (leiaute NT
2025.002 v1.40, bindings nfelib 2.5.x). Extraído do produto sowai-auto
(F1 do plano sowai-fiscal-svc) como lib versionada — zero I/O, zero
SQLAlchemy, zero FastAPI, zero acoplamento a nenhum produto: a interface com
o ORM do consumidor é o Protocol estrutural sowai_fiscal.types.TaxRuleLike.
Módulos
domains— catálogoTaxDomain/DOMAIN_FIELDS/MATCHER_WEIGHTS+ transposição de CFOP intra→interestadual.chave_acesso— DV módulo 11, sorteio decNF, montagem da chave de 44 dígitos.tpag— tabela de códigostPag(MOC, grupo YA02).presets— presets fiscais seed-editáveis (perfis reais extraídos do iCode da Thiago Auto Center).resolver—resolve_fiscal:FiscalOperation× regras (TaxRuleLike) →FiscalResult. Puro, determinístico, fail-closed.xml_builder—build_nfe:DadosEmissao(já resolvido) → objetoNfe(bindingsnfelib).types—TaxRuleLike, oProtocolque desacopla o resolver do ORM do produto.golden_helpers—dados_from_json/serialize_infnfe, usados pelo corpus golden (goldens/) e pelo teste de paridade do produto consumidor.
Corpus golden
src/sowai_fiscal/goldens/caso_<nome>.{input.json,expected.xml} — pares
determinísticos (dh_emi/cnf/chave_acesso pinados no input) que travam
o leiaute XML pré-assinatura gerado a partir de um DadosEmissao. São dados
de pacote (lidos via importlib.resources), para que o produto consumidor
compare byte a byte contra os MESMOS arquivos da lib instalada — nenhuma
cópia que possa divergir. Regenerar com uv run python scripts/gen_goldens.py
apenas quando uma NT mudar o leiaute DE PROPÓSITO.
Testes
uv sync
uv run pytest
100% local — sem Postgres, sem k8s.
Versionamento (contrato)
- SemVer estrito. Os nomes públicos (
resolve_fiscal,build_nfe,montar_chave_acesso,TaxDomain,DOMAIN_FIELDS,MATCHER_WEIGHTS,PRESETS,TPAG_CODES,DadosEmissaoe sub-dataclasses,FiscalOperation/FiscalItem/ FiscalResult/TributoLinha, exceções) são O CONTRATO — mudança incompatível = major. - Consumidores pinam por TAG, nunca por branch:
uv add "sowai-fiscal @ git+https://git.sowai.com.br/jonatan/sowai-fiscal.git@vX.Y.Z"(o lock pina o hash). - Goldens mudam SÓ quando uma NT muda o leiaute de propósito (ver seção acima) — e isso é sempre pelo menos um minor, com nota de release explicando a NT.
Gap conhecido (registrado na F1, 2026-07-17)
- Grupo ANP (
gProdANP) não é emitido —ItemData/builder não têm o campo. NF-e de óleo lubrificante SEM esse grupo é REJEITADA pela SEFAZ. Fechar na cobertura R1 (junto do cClassTrib) ANTES de homologar o caso Óleos na F4. O goldencaso_st_intracobre ICMS-ST/CSOSN 500, NÃO cobre ANP.