feat: extract pure fiscal core from sowai-auto (parity-preserving copy)

Copies the 6 pure fiscal modules (domains, chave_acesso, tpag, presets,
resolver, xml_builder) from sowai-auto's backend/app/modules/fiscal/ into
this standalone lib, with only the two mechanical changes required to drop
the app.* dependency: import prefix rename, and TaxRule (ORM) -> TaxRuleLike
(structural Protocol) in the resolver. No other line changes -- byte-level
parity with the auto is the point.

Ports the pure test suites (domains, chave_acesso, resolver with a local
FakeTaxRule satisfying TaxRuleLike, xml_builder) plus a new test_presets_data
covering the PRESETS dict directly (the auto's equivalent test exercises the
apply-preset HTTP/DB flow, which isn't part of the extracted pure core).

55 tests pass locally via `uv run pytest`, no Postgres/k8s required.
This commit is contained in:
jonatanritter
2026-07-22 15:05:10 -03:00
commit 032151af34
17 changed files with 2413 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
# 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álogo `TaxDomain`/`DOMAIN_FIELDS`/`MATCHER_WEIGHTS` +
transposição de CFOP intra→interestadual.
- `chave_acesso` — DV módulo 11, sorteio de `cNF`, montagem da chave de 44
dígitos.
- `tpag` — tabela de códigos `tPag` (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) → objeto `Nfe`
(bindings `nfelib`).
- `types``TaxRuleLike`, o `Protocol` que 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
```bash
uv sync
uv run pytest
```
100% local — sem Postgres, sem k8s.