chore: establish project baseline

This commit is contained in:
OpenCode
2026-09-21 15:51:47 -03:00
commit 9dcc263217
459 changed files with 447890 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
def test_parser_extracts_item_cest_and_ncm_from_official_table_text():
from central.app.datasets.ba_st_mva import parse_page
records, rejected = parse_page("ITEM CEST NCM/SH DESCRIÇÃO\n3.3 03.003.00 2201.1 Água mineral 114%", 1)
assert records[0]["item"] == "3.3"
assert records[0]["cest"] == "03.003.00"
assert records[0]["ncm_sh"] == ["2201.1"]
assert not rejected
+113
View File
@@ -0,0 +1,113 @@
from datetime import datetime, timezone
from functools import lru_cache
from pathlib import Path
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from central.app.datasets import bootstrap_v1_extra as parsers
from central.app.datasets.service import DatasetService
from central.app.models import Base
ROOT = Path(__file__).parents[2] / "sources" / "raw" / "bootstrap_v1"
FILES = {
"cfop": ROOT / "IT_2023_002_v2_10_Tabela_CFOP_Descrição.xlsx",
"fcp": ROOT / "Tabela_Alíquotas_FCP_por_UF_2025-02_07.xlsx",
"anp": ROOT / "Tabela_Codigo_Produto_ANP-20241118.xlsx",
"ncm_utrib": ROOT / "IT2024.001v2.40 - Tabela NCM 2022 com Utrib_Comércio Exterior_vigência 01.10.26.xlsx",
"biofuel": ROOT / "IT 2025.004 v.1.20 - Tabela de Índice.xlsx",
"credpres": ROOT / "cCredPres_2026-06-22.xlsx",
}
pytestmark = pytest.mark.skipif(not all(p.exists() for p in FILES.values()), reason="bootstrap_v1 extra source files not present locally")
@lru_cache(maxsize=None)
def _payload(name):
parse_fn = {"cfop": parsers.parse_cfop, "fcp": parsers.parse_fcp, "anp": parsers.parse_anp,
"ncm_utrib": parsers.parse_ncm_utrib, "biofuel": parsers.parse_rtc_biofuel_index,
"credpres": parsers.parse_rtc_cred_pres}[name]
return parse_fn(FILES[name].read_bytes())
def _engine():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
return engine
def test_cfop_parses_full_table_with_official_fields():
payload = _payload("cfop")
assert len(payload.entries) >= 500
sample = payload.entries[0]
assert set(sample) >= {"code", "title", "description", "effective_from", "ind_nfe", "ind_comb"}
def test_fcp_covers_all_states_and_df():
payload = _payload("fcp")
ufs = {e["uf"] for e in payload.entries}
assert len(ufs) == 27 # 26 states + DF
assert "BA" in ufs
def test_anp_has_no_invented_descriptions():
payload = _payload("anp")
assert len(payload.entries) >= 900
assert all(set(e) == {"cprod_anp"} for e in payload.entries) # source truly has no description column
def test_ncm_utrib_covers_thousands_of_ncms():
payload = _payload("ncm_utrib")
assert len(payload.entries) >= 10000
assert all(len(e["ncm"]) == 8 for e in payload.entries[:50])
def test_biofuel_index_separates_current_from_historical():
payload = _payload("biofuel")
current = [e for e in payload.entries if not e["is_historical"]]
historical = [e for e in payload.entries if e["is_historical"]]
assert current and historical
assert all(e["p_bio_percent"] is not None for e in current)
def test_credpres_preserves_rich_official_fields_not_just_code_description():
payload = _payload("credpres")
sample = payload.entries[0]
assert sample["legal_basis"]
assert "d_ini_vig_cbs" in sample and "aliquota_cbs_text" in sample
@pytest.mark.parametrize("domain,method,lookup", [
("cfop", "import_cfop", lambda s: s.cfop_lookup(code="1101")),
("fcp", "import_fcp", lambda s: [s.fcp_for_uf("BA")]),
("anp", "import_anp", lambda s: [s.anp_code_exists("110203073")]),
("ncm_utrib", "import_ncm_utrib", lambda s: [s.ncm_utrib_for_ncm("01012100")]),
("biofuel", "import_rtc_biofuel_index", lambda s: s.rtc_biofuel_for_anp("320102001")),
("credpres", "import_rtc_cred_pres", lambda s: s.rtc_cred_pres(code="1")),
])
def test_import_idempotent_and_lookup_smoke(domain, method, lookup):
engine = _engine()
with Session(engine) as session:
service = DatasetService(session)
payload = _payload(domain)
first = getattr(service, method)(payload, f"file://{domain}", datetime.now(timezone.utc))
second = getattr(service, method)(payload, f"file://{domain}", datetime.now(timezone.utc))
assert first.id == second.id
assert second.status == "ACTIVE"
assert second.record_count == len(payload.entries)
result = lookup(service)
assert result
assert all(item is not None and item is not False for item in result) or result == [True]
def test_dataset_versions_includes_all_new_kinds():
engine = _engine()
with Session(engine) as session:
service = DatasetService(session)
versions = service.dataset_versions()
for key in ("cfop", "fcp", "anp", "ncm_utrib", "rtc_biofuel_index", "rtc_ccredpres"):
assert key in versions
assert versions[key] is None
service.import_cfop(_payload("cfop"), "file://cfop", datetime.now(timezone.utc))
assert service.dataset_versions()["cfop"] is not None
@@ -0,0 +1,38 @@
from central.app.classification import Classifier
class _Repository:
def __init__(self, cest_entries):
self._cest_entries = cest_entries
def active_entries(self):
return [type("Entry", (), {"code": "19022000", "description": "Massas"})()]
def cest_for_ncm(self, code):
return self._cest_entries if code == "19022000" else []
def legacy_ncm(self, code):
return None
def dataset_versions(self):
return {"ncm": "n", "cest": "c"}
def test_stopwords_do_not_inflate_description_score():
# "RISOLE DE CAMARAO" vs an official text that only shares the stopword "DE"
# ("... preparadas de outro modo") must score 0, not a false-positive overlap.
cest = type("Cest", (), {
"code": "17.048.02",
"description": "Massas alimenticias recheadas (mesmo cozidas ou preparadas de outro modo)",
})()
result = Classifier(_Repository([cest])).classify({"current_ncm": "19022000", "description": "RISOLE DE CAMARAO"})
candidate = result["classification"]["cest_candidates"][0]
assert candidate["description_score"] == 0.0
assert result["cest_status"] == "CEST_DESCRIPTION_MISMATCH"
def test_genuine_token_overlap_still_scores_above_zero():
cest = type("Cest", (), {"code": "17.024.01", "description": "Queijo mucarela"})()
result = Classifier(_Repository([cest])).classify({"current_ncm": "19022000", "description": "BOLINHO DE QUEIJO"})
candidate = result["classification"]["cest_candidates"][0]
assert candidate["description_score"] > 0
@@ -0,0 +1,62 @@
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from central.app import api as api_module
from central.app.main import create_app
from central.app.models import Base
HEADERS = {"Authorization": "Bearer test-token"}
PAYLOAD = {"current_ncm": "22030000", "description": "CERVEJA LATA"}
def make_client(monkeypatch, calls, engine_version="0.3.0", datasets=None):
versions = datasets if datasets is not None else {"ncm": "aaa"}
class FakeClassifier:
def __init__(self, repository): pass
def classify(self, product):
calls.append(product)
return {"status": "EXACT_NCM", "engine_version": api_module.ENGINE_VERSION, "decision_version": "x", "dataset_versions": dict(versions), "classification": {"ncm": product["current_ncm"]}}
monkeypatch.setattr(api_module, "Classifier", FakeClassifier)
monkeypatch.setattr(api_module, "ENGINE_VERSION", engine_version)
monkeypatch.setattr(api_module.DatasetService, "dataset_versions", lambda self: dict(versions))
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
return TestClient(create_app(session_factory=lambda: Session(engine), bootstrap_token="test-token")), versions
def test_cache_hit_does_not_run_the_classifier(monkeypatch):
calls = []
client, _ = make_client(monkeypatch, calls)
first = client.post("/v1/classify", json=PAYLOAD, headers=HEADERS).json()
assert first["provenance"]["cache_hit"] is False and len(calls) == 1
for _ in range(3):
again = client.post("/v1/classify", json=PAYLOAD, headers=HEADERS).json()
assert again["provenance"]["cache_hit"] is True
assert {k: v for k, v in again.items() if k != "provenance"} == {k: v for k, v in first.items() if k != "provenance"} # same fiscal result
assert len(calls) == 1 # CLASSIFIER_EXECUTIONS_ON_HIT = 0
def test_batch_hits_skip_the_classifier_and_new_inputs_miss(monkeypatch):
calls = []
client, _ = make_client(monkeypatch, calls)
products = [PAYLOAD, {"current_ncm": "19022000", "description": "MASSA"}]
client.post("/v1/classify/batch", json={"products": products}, headers=HEADERS)
assert len(calls) == 2
res = client.post("/v1/classify/batch", json={"products": products + [{"current_ncm": "20099000", "description": "SUCO"}]}, headers=HEADERS).json()["results"]
assert [r["provenance"]["cache_hit"] for r in res] == [True, True, False] and len(calls) == 3
def test_engine_or_dataset_version_change_invalidates_naturally(monkeypatch):
calls = []
client, versions = make_client(monkeypatch, calls)
client.post("/v1/classify", json=PAYLOAD, headers=HEADERS)
versions["ncm"] = "bbb" # a new ACTIVE dataset version changes dataset_versions()
assert client.post("/v1/classify", json=PAYLOAD, headers=HEADERS).json()["provenance"]["cache_hit"] is False
monkeypatch.setattr(api_module, "ENGINE_VERSION", "0.4.0")
assert client.post("/v1/classify", json=PAYLOAD, headers=HEADERS).json()["provenance"]["cache_hit"] is False
assert len(calls) == 3
+31
View File
@@ -0,0 +1,31 @@
from types import SimpleNamespace
from central.app.classification import classify_tipi_rate
def _entry(ex=None, ipi_rate=None, ipi_rate_text=None):
return SimpleNamespace(ex=ex, ipi_rate=ipi_rate, ipi_rate_text=ipi_rate_text)
def test_ex_specific():
assert classify_tipi_rate(_entry(ex="01")) == "EX_SPECIFIC"
def test_source_blank():
assert classify_tipi_rate(_entry(ipi_rate_text=None)) == "SOURCE_BLANK"
def test_nt_or_non_taxed():
assert classify_tipi_rate(_entry(ipi_rate_text="NT")) == "NT_OR_NON_TAXED"
def test_explicit_zero_text():
assert classify_tipi_rate(_entry(ipi_rate_text="0,00")) == "EXPLICIT_ZERO"
def test_explicit_zero_numeric():
assert classify_tipi_rate(_entry(ipi_rate=0, ipi_rate_text="0")) == "EXPLICIT_ZERO"
def test_other_unrecognized_marker():
assert classify_tipi_rate(_entry(ipi_rate_text="ISENTO")) == "OTHER"
+11
View File
@@ -0,0 +1,11 @@
import importlib
def test_database_url_encodes_password_from_component_environment(monkeypatch):
monkeypatch.delenv("DATABASE_URL", raising=False)
monkeypatch.setenv("POSTGRES_PASSWORD", "a@b/c")
import central.app.config as config
module = importlib.reload(config)
assert module.settings.database_url == "postgresql+psycopg://gti:a%40b%2Fc@postgres:5432/gti_fiscal"
+180
View File
@@ -0,0 +1,180 @@
import pytest
from central.app.dry_run_planner import (
build_field_proposals,
execute,
mva_evidence,
split_by_eligibility,
)
def _decision(**overrides):
base = {
"status": "EXACT_NCM",
"cest_status": "NO_CEST_MAPPING_FOUND",
"ipi_status": "NO_TIPI_MAPPING_FOUND",
"ba_st_mva_status": "NO_MVA_MAPPING_FOUND",
"classification": {
"ncm": "07069000",
"cest": [],
"ipi": None,
"ba_st_mva": None,
"ba_st_mva_candidates": [],
},
"dataset_versions": {"ncm": "n1", "cest": "c1", "tipi_ipi": "t1", "ba_st_mva": "m1"},
"engine_version": "0.1.0",
"decision_version": "mvp",
"request_fingerprint": "fp",
}
base.update(overrides)
return base
def test_ipi_resolved_numeric_current_unknown():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {})
ipi = next(p for p in proposals if p["field"] == "IPI")
assert ipi["status"] == "CURRENT_UNKNOWN"
assert ipi["write_eligible"] is False
assert ipi["proposed_value"] == 3.25
def test_ipi_resolved_numeric_same_value():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {"ipi": 3.25, "ex_tipi": None})
ipi = next(p for p in proposals if p["field"] == "IPI")
assert ipi["status"] == "SAME_VALUE"
assert ipi["write_eligible"] is False
def test_ipi_resolved_numeric_change_required():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {"ipi": None, "ex_tipi": None})
ipi = next(p for p in proposals if p["field"] == "IPI")
assert ipi["status"] == "CHANGE_REQUIRED"
assert ipi["write_eligible"] is True
assert ipi["proposed_value"] == 3.25
def test_ipi_non_numeric_marker_never_proposes_a_write():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "NT", "rate_numeric": None, "rate_kind": "NON_NUMERIC", "rate_classification": "NT_OR_NON_TAXED", "ex": None}})
proposals = build_field_proposals("000004", decision, {"ipi": None, "ex_tipi": None})
ipi = next(p for p in proposals if p["field"] == "IPI")
assert ipi["status"] == "NON_NUMERIC_IPI_STATUS"
assert ipi["proposed_value"] is None
assert ipi["write_eligible"] is False
assert ipi["reason_code"] == "TIPI_RATE_NT_OR_NON_TAXED"
def test_ipi_resolved_without_concrete_rate_still_produces_a_row():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": None, "rate_numeric": None, "rate_kind": "BLANK", "rate_classification": "SOURCE_BLANK", "ex": None}})
proposals = build_field_proposals("000018", decision, {"ipi": 5, "ex_tipi": None})
ipi = next(p for p in proposals if p["field"] == "IPI")
assert ipi["status"] == "SOURCE_BLANK"
assert ipi["proposed_value"] is None
assert ipi["write_eligible"] is False
assert ipi["reason_code"] == "TIPI_RATE_SOURCE_BLANK"
def test_no_ex_tipi_row_when_no_ex_candidates():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}, "ipi_candidates": []})
proposals = build_field_proposals("000026", decision, {"ipi": None, "ex_tipi": None})
assert all(p["field"] != "EX_TIPI" for p in proposals)
def test_ex_tipi_concrete_single_candidate_change_required():
decision = _decision(
ipi_status="IPI_CANDIDATES",
classification={**_decision()["classification"], "ipi": None, "ipi_candidates": [{"ncm": "07069000", "ex": "01", "description": "specific", "rate": "5"}]},
)
proposals = build_field_proposals("000004", decision, {"ex_tipi": None})
ex = next(p for p in proposals if p["field"] == "EX_TIPI")
assert ex["status"] == "CHANGE_REQUIRED"
assert ex["proposed_value"] == "01"
assert ex["write_eligible"] is True
def test_ex_tipi_multiple_candidates_is_candidate_not_eligible():
decision = _decision(
ipi_status="IPI_CANDIDATES",
classification={**_decision()["classification"], "ipi": None, "ipi_candidates": [
{"ncm": "07069000", "ex": "01", "description": "a", "rate": "5"},
{"ncm": "07069000", "ex": "02", "description": "b", "rate": "7"},
]},
)
proposals = build_field_proposals("000004", decision, {"ex_tipi": None})
ex = next(p for p in proposals if p["field"] == "EX_TIPI")
assert ex["status"] == "CANDIDATE"
assert ex["proposed_value"] is None
assert ex["write_eligible"] is False
def test_cest_confirmed_change_required():
decision = _decision(cest_status="CEST_CONFIRMED", classification={**_decision()["classification"], "cest": ["17.087.02"]})
proposals = build_field_proposals("000018", decision, {"cest": ""})
cest = next(p for p in proposals if p["field"] == "CEST")
assert cest["status"] == "CHANGE_REQUIRED"
assert cest["write_eligible"] is True
assert cest["proposed_value"] == "17.087.02"
def test_cest_candidates_not_eligible():
decision = _decision(cest_status="CEST_CANDIDATES")
proposals = build_field_proposals("000024", decision, {"cest": ""})
cest = next(p for p in proposals if p["field"] == "CEST")
assert cest["status"] == "CANDIDATE"
assert cest["proposed_value"] is None
assert cest["write_eligible"] is False
def test_cest_description_mismatch_not_eligible():
decision = _decision(cest_status="CEST_DESCRIPTION_MISMATCH")
proposals = build_field_proposals("000018", decision, {"cest": ""})
cest = next(p for p in proposals if p["field"] == "CEST")
assert cest["status"] == "UNRESOLVED"
assert cest["reason_code"] == "CEST_DESCRIPTION_SCORE_BELOW_THRESHOLD"
assert cest["write_eligible"] is False
def test_legacy_ncm_review_no_invented_successor():
decision = _decision(status="LEGACY_NCM", classification={**_decision()["classification"], "ncm": "02071400"})
proposals = build_field_proposals("000016", decision, {"ipi": "3.25", "cest": ""})
assert len(proposals) == 1
row = proposals[0]
assert row["field"] == "CLASSIFICACAO_FISCAL"
assert row["status"] == "LEGACY_NCM_REVIEW"
assert row["proposed_value"] is None
assert row["write_eligible"] is False
def test_mva_never_produces_a_write_proposal():
decision = _decision(ba_st_mva_status="MVA_CANDIDATES", classification={**_decision()["classification"], "ba_st_mva_candidates": [{"item": "1"}]})
proposals = build_field_proposals("000024", decision, {"cest": ""})
assert all(p["field"] != "BA_ST_MVA" for p in proposals)
evidence = mva_evidence("000024", decision)
assert evidence["status"] == "MVA_CANDIDATES"
assert evidence["candidates"]
def test_split_by_eligibility():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {})
split = split_by_eligibility(proposals)
assert split["blocked"] == proposals
assert split["eligible"] == []
def test_execute_refuses_non_eligible_proposal():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {})
with pytest.raises(PermissionError):
execute(proposals)
def test_execute_never_writes_even_when_eligible():
decision = _decision(ipi_status="IPI_RESOLVED", classification={**_decision()["classification"], "ipi": {"rate": "3.25", "rate_numeric": 3.25, "rate_kind": "NUMERIC", "ex": None}})
proposals = build_field_proposals("000026", decision, {"ipi": "0"})
eligible_only = split_by_eligibility(proposals)["eligible"]
assert eligible_only
with pytest.raises(NotImplementedError):
execute(eligible_only)
+270
View File
@@ -0,0 +1,270 @@
import importlib.util
import sys
from pathlib import Path
import pytest
from central.app.field_contract import (ALREADY, CHANGE, CONTRACT, MANUAL, NA, WRITE_FIELDS, Context, infer_role, resolve_product)
ROOT = Path(__file__).parents[2]
REFS = {"cfop_valid": {"5101", "5102", "5401", "5405", "1102", "1101", "1403", "2102"}, "csosn": {"101", "102", "103", "300", "400", "500"}, "cst_icms": {"00", "20", "40", "41", "60"},
"cst_pis": {"01", "49", "98"}, "cst_cofins": {"01", "49", "98"}, "origem": set("012345678"), "fcp_uf": {}, "cbs_rate_2026": None, "cclasstrib_count": 0}
CO1 = {"uf": "BA", "crt": "1", "contribuinte_ipi": "N", "company_code": "000001"}
CO3 = {"uf": "BA", "crt": "3", "contribuinte_ipi": "S", "company_code": "000001"}
def product(**kw):
p = {f: None for f in WRITE_FIELDS}
p.update({"CODIGO": "000001", "PRODUTO": "CERVEJA LATA", "CODGRUPO": "000019", "TIPO": "VENDA", "PROD_COZINHA": None, "PRODUTO_SERVICO": None, "CLASSIFICACAO_FISCAL": "22030000",
"CFOP": "5102", "CSOSN": "102", "CST": "000", "SITUACAO_TRIBUTARIA": "T", "IAT": "A", "IPPT": "T", "INCIDENCIA_PISCOFINS": "NENHUMA", "PISCOFINS": "N"})
p.update(kw)
return p
def decision(**kw):
d = {"status": "EXACT_NCM", "cest_status": "NO_CEST_MAPPING_FOUND", "ipi_status": "IPI_RESOLVED", "ba_st_mva_status": "NO_MVA_MAPPING_FOUND", "dataset_versions": {},
"classification": {"ncm": "22030000", "ipi": {"rate_kind": "NUMERIC", "rate_numeric": 3.9, "rate": "3.9"}, "ipi_candidates": [], "cest": None, "cest_candidates": [], "ba_st_mva": None, "ba_st_mva_candidates": []}}
cls = kw.pop("classification", {})
d.update(kw)
d["classification"] = {**d["classification"], **cls}
return d
EV = {"recipes": set(), "composed": set(), "purchases": {}, "stock_entry": {}, "stock_in": {"000001": True}}
IPI_POP = {"scope": "COMPANY", "scope_key": "", "key": "store_ipi_profile", "value": "POPULATE_REFERENCE_RATE"}
def run(p=None, d=None, co=CO1, ctx=None, ev=EV, manual=None, ipi_profile=IPI_POP):
return resolve_product(p or product(), d or decision(), co, REFS, ev, Context((ctx or []) + ([ipi_profile] if ipi_profile else [])), manual_ncm=manual)
def st(res, f):
return res[f]["state"], res[f]["proposed"]
def test_every_write_field_has_a_complete_contract():
keys = {"ERP_FIELD", "UI_LABEL", "SEMANTICS", "DATA_TYPE", "SOURCE_OF_TRUTH", "REQUIRED_INPUTS", "RESOLUTION_RULE", "VALID_VALUES", "NOT_APPLICABLE_RULE", "MANUAL_INPUT_RULE", "WRITE_ALLOWED", "VALIDATION_RULE", "PROVENANCE"}
assert set(CONTRACT) == set(WRITE_FIELDS) and len(WRITE_FIELDS) == 23
for f, c in CONTRACT.items():
assert keys <= set(c) and all(c[k] not in (None, "", []) for k in keys - {"WRITE_ALLOWED"}), f
def test_only_five_final_states_and_manual_always_names_its_input():
res = run()
for f in WRITE_FIELDS:
assert res[f]["state"] in (ALREADY, CHANGE, NA, MANUAL)
if res[f]["state"] == MANUAL:
assert res[f]["input_key"]
assert res[f]["write_eligible"] == (res[f]["state"] == CHANGE)
def test_ncm_states_and_operator_ncm_reprocessing():
bad = run(p=product(CLASSIFICACAO_FISCAL="12345678"), d=decision(status="INVALID_NCM"))
assert st(bad, "CLASSIFICACAO_FISCAL")[0] == MANUAL and bad["CLASSIFICACAO_FISCAL"]["input_key"] == "ncm"
for f in ("IPI", "EX_TIPI", "CEST", "CFOP", "CSOSN"):
assert bad[f]["state"] == MANUAL and bad[f]["reason"] == "BLOCKED_BY_NCM"
assert st(run(manual=("22030000", False), p=product(CLASSIFICACAO_FISCAL="12345678"), d=decision(status="INVALID_NCM")), "CLASSIFICACAO_FISCAL")[0] == MANUAL
fixed = run(manual=("22030000", True), p=product(CLASSIFICACAO_FISCAL="12345678"), d=decision())
assert st(fixed, "CLASSIFICACAO_FISCAL") == (CHANGE, "22030000") and fixed["IPI"]["state"] == CHANGE and fixed["IPI"]["proposed"] == 3.9 # dependents reprocessed with the manual NCM
def test_ipi_rules_never_write_nt_or_blank_and_ask_when_ambiguous():
assert st(run(), "IPI") == (CHANGE, 3.9)
assert st(run(p=product(IPI=3.9)), "IPI")[0] == ALREADY
nt = run(d=decision(classification={"ipi": {"rate_kind": "NON_NUMERIC", "rate_classification": "NT"}}))
assert nt["IPI"]["state"] == NA and not nt["IPI"]["write_eligible"]
blank = run(d=decision(classification={"ipi": {"rate_kind": "BLANK"}}))
assert blank["IPI"]["state"] == NA and "NEVER_ZERO" in blank["IPI"]["reason"]
amb = decision(ipi_status="IPI_CANDIDATES", classification={"ipi": None, "ipi_candidates": [{"ex": None, "rate": "5", "description": "base"}, {"ex": "1", "rate": "0", "description": "Chope"}]})
r = run(d=amb)
assert r["IPI"]["state"] == MANUAL and r["IPI"]["input_key"] == "ex_tipi" and len(r["IPI"]["choices"]) == 2
solved = run(d=amb, ctx=[{"scope": "PRODUCT", "scope_key": "000001", "key": "ex_tipi", "value": "NONE"}])
assert st(solved, "IPI") == (CHANGE, 5.0) and solved["EX_TIPI"]["state"] == NA
def test_cest_contract():
off = [{"code": "03.021.03", "official_description": "Cerveja em lata", "description_score": 1.0}, {"code": "03.021.05", "official_description": "PET", "description_score": 0.5}]
conf = run(d=decision(cest_status="CEST_CONFIRMED", classification={"cest": ["03.021.03"], "cest_candidates": off}))
assert st(conf, "CEST") == (CHANGE, "0302103")
assert run(p=product(CEST="0302103"), d=decision(cest_status="CEST_CANDIDATES", classification={"cest_candidates": off}))["CEST"]["state"] == ALREADY
many = run(d=decision(cest_status="CEST_CANDIDATES", classification={"cest_candidates": off}))
assert many["CEST"]["state"] == MANUAL and many["CEST"]["input_key"] == "cest" and len(many["CEST"]["choices"]) == 2
assert run(d=decision(cest_status="CEST_DESCRIPTION_MISMATCH", classification={"cest_candidates": off}))["CEST"]["state"] == NA
assert run()["CEST"]["state"] == NA
assert run(p=product(CEST="9999999"))["CEST"]["state"] == MANUAL
picked = run(d=decision(cest_status="CEST_CANDIDATES", classification={"cest_candidates": off}), ctx=[{"scope": "NCM", "scope_key": "22030000", "key": "cest", "value": "03.021.05"}])
assert st(picked, "CEST") == (CHANGE, "0302105")
def test_cfop_role_and_st_rules():
ok = run() # RESALE (stock entries), not subject to ST, declared 5102 == derived
assert ok["CFOP"]["state"] == ALREADY and ok["_facts"]["role"] == "RESALE"
assert st(run(p=product(CFOP="5405")), "CFOP") == (CHANGE, "5102") # 5405 but proven NOT_SUBJECT
assert st(run(p=product(CFOP=None)), "CFOP") == (CHANGE, "5102") # blank filled
unk = run(d=decision(ba_st_mva_status="MVA_CANDIDATES"), p=product(CFOP=None)) # ST unknown, blank -> asks
assert unk["CFOP"]["state"] == MANUAL and unk["CFOP"]["input_key"] == "st_status"
assert run(d=decision(ba_st_mva_status="MVA_CANDIDATES"))["CFOP"]["state"] == ALREADY # declared valid, not contradicted
role_unknown = run(ev={**EV, "stock_in": {}}, p=product(CFOP=None))
assert role_unknown["CFOP"]["state"] == MANUAL and role_unknown["CFOP"]["input_key"] == "product_role"
own = run(ev={**EV, "recipes": {"000001"}}, p=product(CFOP="5102"))
assert st(own, "CFOP") == (CHANGE, "5101")
assert run(p=product(TIPO="MATERIA-PRIMA"))["CFOP"]["state"] == NA
def test_cfop_entrada_needs_company_entry_scope_then_derives():
r = run(p=product(CFOP_ENTRADA=None))
assert r["CFOP_ENTRADA"]["state"] == MANUAL and r["CFOP_ENTRADA"]["input_key"] == "entry_scope"
r = run(p=product(CFOP_ENTRADA=None), ctx=[{"scope": "COMPANY", "scope_key": "", "key": "entry_scope", "value": "INTRA"}])
assert st(r, "CFOP_ENTRADA") == (CHANGE, "1102")
assert run(p=product(CFOP_ENTRADA="1102"))["CFOP_ENTRADA"]["state"] == ALREADY
def test_icms_code_fields_follow_the_regime():
r1 = run()
assert r1["CST"]["state"] == NA and r1["CST_ENTRADA"]["state"] == NA and r1["CSOSN"]["state"] == ALREADY
assert run(p=product(CSOSN=None))["CSOSN"]["state"] == MANUAL
assert st(run(p=product(CSOSN=None), ctx=[{"scope": "GROUP", "scope_key": "000019", "key": "icms_treatment", "value": "EXEMPT"}]), "CSOSN") == (CHANGE, "400")
assert st(run(p=product(CSOSN="102"), ctx=[{"scope": "GROUP", "scope_key": "000019", "key": "icms_treatment", "value": "ST_WITHHELD"}]), "CSOSN") == (CHANGE, "500")
r3 = run(co=CO3, p=product(CSOSN=None))
assert r3["CSOSN"]["state"] == NA and r3["CST"]["state"] == ALREADY and r3["ALIQUOTA"]["state"] in (ALREADY, MANUAL)
blank = run(co=CO3, p=product(CST=None, COD_ORIGEM_MERCADORIA="0"))
assert blank["CST"]["state"] == MANUAL and blank["CST"]["input_key"] == "icms_treatment"
filled = run(co=CO3, p=product(CST=None, COD_ORIGEM_MERCADORIA="0"), ctx=[{"scope": "COMPANY", "scope_key": "", "key": "icms_treatment", "value": "TAXED"}])
assert st(filled, "CST") == (CHANGE, "000")
def test_aliquota_not_copied_blindly():
assert run()["ALIQUOTA"]["state"] == NA # Simples CSOSN 102 highlights no ICMS
assert run(p=product(CSOSN="101", ALIQUOTA=None))["ALIQUOTA"]["input_key"] == "credit_rate"
assert st(run(co=CO3, p=product(ALIQUOTA="17"), ctx=[{"scope": "COMPANY", "scope_key": "", "key": "icms_rate", "value": "20,5"}]), "ALIQUOTA") == (CHANGE, 20.5)
def test_origin_binding_rules():
r0 = run(p=product(COD_ORIGEM_MERCADORIA=None, CST="040"))["COD_ORIGEM_MERCADORIA"] # audit V2: the CST first digit is padding, never origin evidence
assert r0["state"] == MANUAL and r0["reason"] == "ORIGIN_NO_EVIDENCE" and r0["proposed"] is None
assert run(p=product(COD_ORIGEM_MERCADORIA="0", CST="040"))["COD_ORIGEM_MERCADORIA"]["state"] == ALREADY
assert run(p=product(COD_ORIGEM_MERCADORIA="2", CST="040"))["COD_ORIGEM_MERCADORIA"]["state"] == ALREADY # declared origin stays; CST digit is padding
assert run(p=product(COD_ORIGEM_MERCADORIA=None, CST="540"))["COD_ORIGEM_MERCADORIA"]["state"] == MANUAL # 5 is not on the SGV screen
assert st(run(p=product(COD_ORIGEM_MERCADORIA=None, CST="540"), ctx=[{"scope": "GROUP", "scope_key": "000019", "key": "origin", "value": "1"}]), "COD_ORIGEM_MERCADORIA") == (CHANGE, 1)
def test_cst_ipi_pis_cofins_incidence_iat_ippt():
assert run()["CST_IPI"]["state"] == NA
assert run(co=CO3)["CST_IPI"]["state"] == MANUAL
r = run()
assert r["COD_SAIDA_PIS"]["state"] == MANUAL and r["COD_SAIDA_PIS"]["input_key"] == "pis_cofins_profile" and r["ALIQ_COFINS"]["state"] == MANUAL
prof = '{"pis_out_cst": "49", "pis_in_cst": "98", "pis_rate": "0", "cofins_out_cst": "49", "cofins_in_cst": "98", "cofins_rate": "0"}'
r = run(ctx=[{"scope": "COMPANY", "scope_key": "", "key": "pis_cofins_profile", "value": prof}])
assert st(r, "COD_SAIDA_PIS") == (CHANGE, "49") and st(r, "COD_ENTRADA_COFINS") == (CHANGE, "98") and st(r, "ALIQ_PIS") == (CHANGE, "0")
bad = run(ctx=[{"scope": "COMPANY", "scope_key": "", "key": "pis_cofins_profile", "value": '{"pis_out_cst": "77"}'}])
assert bad["COD_SAIDA_PIS"]["state"] == MANUAL # not in the official CST table
assert run(p=product(IAT=None))["IAT"]["input_key"] == "rounding"
assert run()["INCIDENCIA_PISCOFINS"]["state"] == ALREADY
assert st(run(ev={**EV, "recipes": {"000001"}}), "IPPT") == (CHANGE, "P") and run()["IPPT"]["state"] == ALREADY
assert run(p=product(TIPO="MATERIA-PRIMA"))["IPPT"]["state"] == NA
def test_context_hierarchy_product_beats_group_beats_company():
ctx = Context([{"scope": "COMPANY", "scope_key": "", "key": "product_role", "value": "RESALE"}, {"scope": "GROUP", "scope_key": "G1", "key": "product_role", "value": "OWN_PRODUCTION"},
{"scope": "PRODUCT", "scope_key": "P1", "key": "product_role", "value": "INPUT"}])
assert ctx.get("product_role", "P1", "G1") == ("INPUT", "PRODUCT")
assert ctx.get("product_role", "P2", "G1") == ("OWN_PRODUCTION", "GROUP")
assert ctx.get("product_role", "P2", "G9") == ("RESALE", "COMPANY")
assert Context([]).get("product_role", "P2", "G9") == (None, None)
def test_role_inference_is_evidence_based_and_conflicts_stay_unknown():
assert infer_role(product(TIPO="MATERIA-PRIMA"), EV, Context([]), "000001", "1")[0] == "INPUT"
assert infer_role(product(), {**EV, "stock_in": {}}, Context([]), "000001", "1")[0] == "UNKNOWN"
assert infer_role(product(PROD_COZINHA=1), {**EV, "purchases": {"000001": [{}]}}, Context([]), "000001", "1")[0] == "UNKNOWN"
assert infer_role(product(PROD_COZINHA=1), EV, Context([]), "000001", "1")[0] == "UNKNOWN" # kitchen flag alone is not proof
assert infer_role(product(PROD_COZINHA=1), {**EV, "recipes": {"000001"}}, Context([]), "000001", "1")[0] == "OWN_PRODUCTION"
# ---------------- executor guards ----------------
def load_executor():
spec = importlib.util.spec_from_file_location("fwe_local", ROOT / "scripts" / "firebird_write_executor.py")
m = importlib.util.module_from_spec(spec); sys.modules[spec.name] = m; spec.loader.exec_module(m)
return m
class FakeCursor:
def __init__(self, db):
self.db, self.rowcount, self._row = db, 0, None
def execute(self, sql, params=()):
s = " ".join(sql.split())
if "RDB$FIELD_TYPE" in s:
self._row = (37, 20)
elif s.startswith("SELECT") and "FROM C000025" in s:
fields = [x.strip() for x in s.split("SELECT")[1].split("FROM")[0].split(",")]
row = self.db["rows"].get(params[0])
self._row = tuple(row[f] for f in fields) if row else None
elif s.startswith("UPDATE"):
row = self.db["rows"].get(params[-1])
self.rowcount = 0 if row is None else self.db["update_rowcount"]
if row is not None and self.rowcount == 1:
for f, v in zip([x.split("=")[0].strip() for x in s.split("SET")[1].split("WHERE")[0].split(",")], params[:-1]):
self.db["pending"][f] = v
def fetchone(self):
return self._row
def close(self):
pass
class FakeConn:
def __init__(self, rows, update_rowcount=1):
self.db = {"rows": rows, "update_rowcount": update_rowcount, "pending": {}}
self.rolled_back = self.committed = False
def cursor(self):
return FakeCursor(self.db)
def commit(self):
for row in self.db["rows"].values():
row.update(self.db["pending"])
self.committed = True
def rollback(self):
self.db["pending"].clear(); self.rolled_back = True
ALLOWED = r"D:\PROJETOS\GTISISTEMAS\Projeto\Banco\CONSTRUCAO.FDB"
def test_executor_allowlist_is_exact_and_field_set_is_the_contract():
ex = load_executor()
assert ex._LOCAL_COMPLETION_FIELDS == set(WRITE_FIELDS)
allow = ex.load_local_allowlist()
assert len(allow) == 5
for path in (ALLOWED, r"D:\PROJETOS\GTISISTEMAS\Projeto\TESTESOFICIAIS.FDB"):
ex.assert_local_completion_target(path, allow)
for bad in (r"D:\PROJETOS\GTISISTEMAS\Banco\GTI.FDB", r"D:\PROJETOS\GTISISTEMAS\Projeto\Banco\OUTRA.FDB", r"D:\PROJETOS\GTISISTEMAS\Projeto\Banco\CONSTRUCAO.FDB.bak", r"D:\PROJETOS\GTISISTEMAS\Projeto\Banco"):
with pytest.raises(ex.WriteRefused):
ex.assert_local_completion_target(bad, allow)
def test_guarded_product_update_success_drift_rowcount_and_refusals():
ex = load_executor()
allow = ex.load_local_allowlist()
conn = FakeConn({"000001": {"IPI": None, "CEST": "1234567"}})
rec = ex.execute_guarded_product_update(conn, database_path=ALLOWED, product_code="000001", changes={"IPI": (None, 3.9), "CEST": ("1234567", "7654321")}, now="t", allowlist=allow)
assert rec["rowcount"] == 1 and rec["fields"]["IPI"]["after"] == 3.9 and conn.committed
with pytest.raises(ex.WriteRefused, match="drift"):
ex.execute_guarded_product_update(FakeConn({"000001": {"IPI": 1.0}}), database_path=ALLOWED, product_code="000001", changes={"IPI": (None, 3.9)}, now="t", allowlist=allow)
c2 = FakeConn({"000001": {"IPI": None}}, update_rowcount=2)
with pytest.raises(ex.WriteRefused, match="rowcount"):
ex.execute_guarded_product_update(c2, database_path=ALLOWED, product_code="000001", changes={"IPI": (None, 3.9)}, now="t", allowlist=allow)
assert c2.rolled_back
with pytest.raises(ex.WriteRefused, match="allowlist"):
ex.execute_guarded_product_update(conn, database_path=r"D:\PROJETOS\GTISISTEMAS\Banco\GTI.FDB", product_code="000001", changes={"IPI": (None, 1)}, now="t", allowlist=allow)
with pytest.raises(ex.WriteRefused, match="contract write target"):
ex.execute_guarded_product_update(conn, database_path=ALLOWED, product_code="000001", changes={"CODIGO": ("000001", "9")}, now="t", allowlist=allow)
with pytest.raises(ex.WriteRefused, match="null"):
ex.execute_guarded_product_update(conn, database_path=ALLOWED, product_code="000001", changes={"IPI": (None, None)}, now="t", allowlist=allow)
with pytest.raises(ex.WriteRefused, match="only C000025"):
ex.execute_guarded_product_update(conn, database_path=ALLOWED, product_code="000001", changes={"IPI": (None, 1)}, now="t", allowlist=allow, table="NFCE_ITENS")
+45
View File
@@ -0,0 +1,45 @@
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from central.app.context_keys import validate_entry
from central.app.main import create_app
from central.app.models import Base
H = {"Authorization": "Bearer test-token"}
def client():
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
return TestClient(create_app(session_factory=lambda: Session(engine), bootstrap_token="test-token"))
def test_validation_rules():
ok, err = validate_entry({"scope": "group", "scope_key": "000019", "key": "product_role", "value": "resale"})
assert err is None and ok["value"] == "RESALE" and ok["scope"] == "GROUP"
for bad in ({"scope": "GROUP", "key": "product_role", "value": "RESALE"}, # group without key
{"scope": "COMPANY", "key": "product_role", "value": "BOSS"}, # not in enum
{"scope": "GROUP", "scope_key": "1", "key": "ncm", "value": "22030000"}, # ncm is product scope
{"scope": "PRODUCT", "scope_key": "1", "key": "ncm", "value": "2203"}, # not 8 digits
{"scope": "COMPANY", "key": "pis_cofins_profile", "value": "{\"x\": 1}"}, # unknown profile key
{"scope": "COMPANY", "key": "icms_rate", "value": "abc"}, {"scope": "COMPANY", "key": "nope", "value": "1"}):
assert validate_entry(bad)[1]
assert validate_entry({"scope": "COMPANY", "key": "pis_cofins_profile", "value": "{\"pis_out_cst\": \"49\"}"})[1] is None
def test_import_is_all_or_nothing_upserting_and_listed():
c = client()
body = {"company_key": "abc123", "entries": [{"scope": "GROUP", "scope_key": "000019", "key": "product_role", "value": "RESALE", "reason": "revenda"},
{"scope": "COMPANY", "key": "entry_scope", "value": "INTRA"}]}
assert c.post("/v1/context/import", json=body, headers=H).json() == {"created": 2, "updated": 0}
body["entries"][0]["value"] = "OWN_PRODUCTION"
assert c.post("/v1/context/import", json=body, headers=H).json() == {"created": 0, "updated": 2}
listed = c.get("/v1/context", params={"company_key": "abc123"}, headers=H).json()["entries"]
assert {(e["scope"], e["key"], e["value"]) for e in listed} == {("GROUP", "product_role", "OWN_PRODUCTION"), ("COMPANY", "entry_scope", "INTRA")}
bad = {"company_key": "abc123", "entries": [{"scope": "COMPANY", "key": "rounding", "value": "A"}, {"scope": "COMPANY", "key": "rounding", "value": "Z"}]}
r = c.post("/v1/context/import", json=bad, headers=H)
assert r.status_code == 422
assert len(c.get("/v1/context", params={"company_key": "abc123"}, headers=H).json()["entries"]) == 2 # nothing partially stored
assert c.get("/v1/context", params={"company_key": "other"}, headers=H).json()["entries"] == []
+71
View File
@@ -0,0 +1,71 @@
from central.app.fiscal_decision import ERP_FIELD_MAP, decide_product
REFS = {"cfop_valid": {"5102"}, "csosn": {"102", "500"}, "cst_icms": {"00", "40", "60"}, "cst_pis": {"01"}, "cst_cofins": {"01"},
"origem": set("012345678"), "fcp_uf": {"BA": {"aliq_1": "Fixo:2.00"}}, "cbs_rate_2026": 0.009, "cclasstrib_count": 164}
COMPANY = {"uf": "BA", "crt": "1"}
def product(**kw):
base = {"CODIGO": "1", "PRODUTO": "X", "CLASSIFICACAO_FISCAL": "22030000", "CFOP": "5102", "CST": "040", "CSOSN": "102",
"CEST": None, "IPI": None, "EX_TIPI": None, "ORIGEM": None, "COD_SAIDA_PIS": None, "COD_SAIDA_COFINS": None, "ALIQ_PIS": None}
base.update(kw)
return base
def decision(**kw):
base = {"status": "EXACT_NCM", "ipi_status": "IPI_RESOLVED", "cest_status": "CEST_CANDIDATES", "ba_st_mva_status": "MVA_CANDIDATES",
"dataset_versions": {}, "classification": {"ncm": "22030000", "ipi": {"rate_kind": "NUMERIC", "rate_numeric": 3.9}, "cest_candidates": [1, 2]}}
base.update(kw)
return base
def test_numeric_ipi_change_is_the_only_auto_apply():
out = decide_product(product(IPI=5102.0), decision(), COMPANY, REFS)
assert out["IPI"]["action_class"] == "AUTO_APPLY_SAFE" and out["IPI"]["write_eligible"] and out["IPI"]["proposed_value"] == 3.9
assert [d for d, r in out.items() if r["write_eligible"]] == ["IPI"]
def test_same_ipi_is_already_correct_not_write():
out = decide_product(product(IPI=3.9), decision(), COMPANY, REFS)
assert out["IPI"]["action_class"] == "ALREADY_CORRECT" and not out["IPI"]["write_eligible"]
def test_non_numeric_and_blank_ipi_never_write():
d = decision(classification={"ipi": {"rate_kind": "NON_NUMERIC", "rate_classification": "NT"}})
assert not decide_product(product(), d, COMPANY, REFS)["IPI"]["write_eligible"]
d = decision(classification={"ipi": {"rate_kind": "BLANK"}})
r = decide_product(product(), d, COMPANY, REFS)["IPI"]
assert not r["write_eligible"] and r["status"] == "RULE_UNRESOLVED"
def test_operation_dependent_fields_never_resolved_or_written():
out = decide_product(product(), decision(), COMPANY, REFS)
for dom in ("CFOP", "CSOSN", "CST_ICMS", "PIS_CST", "COFINS_CST", "FCP", "RTC_CCLASSTRIB", "RTC_CBS_RATE"):
assert out[dom]["status"] == "OPERATION_CONTEXT_REQUIRED" and not out[dom]["write_eligible"]
assert out["CFOP"]["domain_valid"] is True and out["FCP"]["fcp_rate_available"] is True
assert out["RTC_CBS_RATE"]["proposed_value"] is None and out["RTC_CBS_RATE"]["reference_rate_2026"] == 0.009
def test_ncm_legacy_is_review_and_never_write():
out = decide_product(product(), decision(status="LEGACY_NCM"), COMPANY, REFS)
assert out["NCM"]["action_class"] == "REVIEW_REQUIRED" and not any(r["write_eligible"] for r in out.values())
def test_origin_only_candidate_and_unconfirmed_mapping():
out = decide_product(product(), decision(), COMPANY, REFS)
assert out["ORIGEM"]["status"] == "RULE_CANDIDATE" and not out["ORIGEM"]["write_eligible"]
assert {f["ERP_FIELD"] for f in ERP_FIELD_MAP if f["MAPPING"] == "MAPPING_UNCONFIRMED"} >= {"ORIGEM", "CFOP_ENTRADA", "CST_ENTRADA"}
def test_mva_never_written_even_when_resolved():
d = decision(ba_st_mva_status="MVA_RESOLVED", classification={"ipi": {"rate_kind": "NUMERIC", "rate_numeric": 1}, "ba_st_mva": {"mva_original": "140%"}})
r = decide_product(product(IPI=1), d, COMPANY, REFS)["MVA"]
assert r["status"] == "RULE_RESOLVED" and not r["write_eligible"]
def test_single_ex_without_description_evidence_is_candidate_not_write():
cls = {"ipi": {"rate_kind": "NUMERIC", "rate_numeric": 3.9}, "ipi_candidates": [{"ex": "1", "description": "Chope"}]}
out = decide_product(product(PRODUTO="CERVEJA LATA", IPI=3.9), decision(classification=cls), COMPANY, REFS)
assert out["EX_TIPI"]["status"] == "RULE_CANDIDATE" and not out["EX_TIPI"]["write_eligible"]
out = decide_product(product(PRODUTO="CHOPE ESCURO", IPI=3.9), decision(classification=cls), COMPANY, REFS)
assert out["EX_TIPI"]["status"] == "RULE_RESOLVED" and out["EX_TIPI"]["write_eligible"]
@@ -0,0 +1,9 @@
from central.app.fiscal_determination import FiscalDetermination
def test_returns_unresolved_csosn_and_cfop_without_official_rule():
result = FiscalDetermination().determine({"ncm": "08043000", "cest_candidates": []})
assert result["csosn"] is None
assert result["cfop"] is None
assert "OFFICIAL_RULE_NOT_IMPLEMENTED" in result["reason_codes"]
+29
View File
@@ -0,0 +1,29 @@
from fastapi.testclient import TestClient
from central.app.main import create_app
def test_health_reports_database_dependency():
client = TestClient(create_app(database_probe=lambda: True))
assert client.get("/health").json() == {"status": "ok"}
def test_health_is_unavailable_when_database_is_down():
client = TestClient(create_app(database_probe=lambda: False))
assert client.get("/health").status_code == 503
def test_version_endpoint_reports_release_and_fiscal_versions():
body = TestClient(create_app(database_probe=lambda: True)).get("/version").json()
assert body["version"] == "1.0.0-rc1" and body["api_compat"] == "1.0" and body["engine_version"] and body["decision_version"]
def test_production_refuses_the_dev_token(monkeypatch):
import pytest
from central.app import main as main_module
monkeypatch.setattr(main_module.settings.__class__, "environment", "production", raising=False) if False else None
monkeypatch.setattr(main_module, "settings", type("S", (), {"environment": "production", "agent_dev_token": "dev", "log_level": "INFO"})())
with pytest.raises(RuntimeError):
create_app(database_probe=lambda: True)
+58
View File
@@ -0,0 +1,58 @@
from central.app.icms_context import csosn_v2, product_role, st_conflict_class, st_status, withheld_status
DOM = {"102", "500", "101", "400"}
def test_cest_candidate_never_confirms_st():
assert st_status("EXACT_NCM", "MVA_CANDIDATES", "CEST_CANDIDATES", "", None, 4)[0] == "ST_CANDIDATE"
assert st_status("EXACT_NCM", "MVA_RESOLVED", "CEST_CANDIDATES", "", "03.021.03", 4)[0] == "ST_CANDIDATE"
def test_st_confirmed_needs_erp_cest_corroboration():
assert st_status("EXACT_NCM", "MVA_RESOLVED", "CEST_CANDIDATES", "0302103", "03.021.03", 4)[0] == "ST_CONFIRMED"
assert st_status("EXACT_NCM", "MVA_RESOLVED", "CEST_CONFIRMED", "", "03.021.03", 4)[0] == "ST_CONFIRMED"
def test_st_not_applicable_needs_both_lists_silent_and_valid_ncm():
assert st_status("EXACT_NCM", "NO_MVA_MAPPING_FOUND", "NO_CEST_MAPPING_FOUND", None, None, None)[0] == "ST_NOT_APPLICABLE"
assert st_status("EXACT_NCM", "NO_MVA_MAPPING_FOUND", "CEST_CANDIDATES", None, None, None)[0] == "ST_UNKNOWN"
assert st_status("LEGACY_NCM", "NO_MVA_MAPPING_FOUND", "NO_CEST_MAPPING_FOUND", None, None, None)[0] == "ST_UNKNOWN"
def test_withholding_needs_positive_purchase_evidence():
assert withheld_status([])[0] == "ST_WITHHOLDING_UNKNOWN"
assert withheld_status([{"icms_retido": "N", "valor_retido": 0, "sub_valor": 0}])[0] == "ST_ALREADY_WITHHELD_NOT_CONFIRMED"
assert withheld_status([{"icms_retido": "S", "valor_retido": 0, "sub_valor": 0}])[0] == "ST_ALREADY_WITHHELD_CONFIRMED"
assert withheld_status([{"icms_retido": "N", "valor_retido": 5, "sub_valor": 0}])[0] == "ST_ALREADY_WITHHELD_CONFIRMED"
def test_role_uses_objective_evidence_only():
assert product_role("MATERIA-PRIMA", False, False, False, False, False)[0] == "INPUT"
assert product_role("VENDA", True, False, False, False, False)[0] == "OWN_PRODUCTION"
assert product_role("VENDA", False, False, False, False, True)[0] == "RESALE"
assert product_role("VENDA", False, False, False, False, False)[0] == "UNKNOWN"
assert product_role("VENDA", True, False, False, False, True)[0] == "UNKNOWN"
def test_csosn_never_assumes_102_and_never_writes():
for st in ("ST_CANDIDATE", "ST_UNKNOWN"):
r = csosn_v2("102", "102", "EXACT_NCM", st, "ST_WITHHOLDING_UNKNOWN", "RESALE", DOM)
assert r["status"] == "CSOSN_CONTEXT_REQUIRED" and r["proposed_csosn"] is None
r = csosn_v2("102", "102", "EXACT_NCM", "ST_NOT_APPLICABLE", "ST_WITHHOLDING_UNKNOWN", "RESALE", DOM)
assert r["status"] == "CSOSN_CANDIDATE" and not r["write_eligible"]
assert csosn_v2("102", "102", "EXACT_NCM", "ST_NOT_APPLICABLE", "ST_WITHHOLDING_UNKNOWN", "UNKNOWN", DOM)["status"] == "CSOSN_CONTEXT_REQUIRED"
assert csosn_v2("102", "102", "LEGACY_NCM", "ST_NOT_APPLICABLE", "ST_WITHHOLDING_UNKNOWN", "RESALE", DOM)["status"] == "CSOSN_UNRESOLVED"
def test_csosn_resolved_only_with_st_withholding_and_role_proven():
r = csosn_v2("102", "102", "EXACT_NCM", "ST_CONFIRMED", "ST_ALREADY_WITHHELD_CONFIRMED", "RESALE", DOM)
assert r["status"] == "CSOSN_RESOLVED" and r["proposed_csosn"] == "500" and r["write_eligible"] is False
assert csosn_v2("102", "102", "EXACT_NCM", "ST_CONFIRMED", "ST_WITHHOLDING_UNKNOWN", "RESALE", DOM)["status"] == "CSOSN_CONTEXT_REQUIRED"
assert csosn_v2("500", "102", "EXACT_NCM", "ST_CONFIRMED", "ST_ALREADY_WITHHELD_NOT_CONFIRMED", "RESALE", DOM)["status"] == "CSOSN_CONFLICT"
def test_conflict_classes():
assert st_conflict_class("CEST_CANDIDATES", "MVA_RESOLVED", 4, "", "03.021.03", "5102", True, False)[0] == "ERP_HISTORY_CONFLICT"
assert st_conflict_class(None, "NO_MVA_MAPPING_FOUND", None, "", None, "5405", False, True)[0] == "BA_ST_RULE_CONFLICT"
assert st_conflict_class("CEST_DESCRIPTION_MISMATCH", "MVA_RESOLVED", 6, "", None, "5102", False, False)[0] == "DESCRIPTION_MISMATCH"
assert st_conflict_class(None, "MVA_RESOLVED", 6, "", None, "5102", False, False)[0] == "NO_EVIDENCE"
+132
View File
@@ -0,0 +1,132 @@
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from central.app.jobs import claim_next_job, complete_job, create_job, fail_job
from central.app.main import create_app
from central.app.models import Agent, Base, Job, Tenant
def _make_agent(session):
tenant = Tenant(name="development")
session.add(tenant); session.flush()
agent = Agent(tenant_id=tenant.id, name="agent-a", token_hash="hash-a")
other = Agent(tenant_id=tenant.id, name="agent-b", token_hash="hash-b")
session.add_all([agent, other]); session.commit()
return agent, other
def test_claim_is_scoped_to_owning_agent_and_marks_running():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
agent, other = _make_agent(session)
job = create_job(session, agent, "REPROCESS_ALL")
assert claim_next_job(session, other) is None # other agent never sees it
claimed = claim_next_job(session, agent)
assert claimed.id == job.id
assert claimed.status == "RUNNING"
assert claimed.attempts == 1
def test_claim_is_not_reentrant_once_running():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
agent, _ = _make_agent(session)
create_job(session, agent, "REPROCESS_ALL")
first = claim_next_job(session, agent)
second = claim_next_job(session, agent) # repeated polling must not duplicate consumption
assert first is not None
assert second is None
def test_completed_job_can_never_run_again():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
agent, _ = _make_agent(session)
create_job(session, agent, "REPROCESS_ALL")
job = claim_next_job(session, agent)
assert complete_job(session, job, {"writes": 0}) is True
assert session.get(Job, job.id).status == "COMPLETED"
assert claim_next_job(session, agent) is None
assert complete_job(session, job, {"writes": 1}) is False # already terminal
def test_failed_job_is_terminal_with_sanitized_error():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
agent, _ = _make_agent(session)
create_job(session, agent, "REPROCESS_ALL")
job = claim_next_job(session, agent)
assert fail_job(session, job, "boom " * 1000) is True
stored = session.get(Job, job.id)
assert stored.status == "FAILED"
assert len(stored.error) <= 2000
def _client():
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
app = create_app(session_factory=lambda: Session(engine), bootstrap_token="test-token")
return TestClient(app), engine
def test_job_api_end_to_end_flow():
client, engine = _client()
headers = {"Authorization": "Bearer test-token"}
heartbeat = client.post("/v1/agents/heartbeat", json={"status": "IDLE", "schema_fingerprint": "abc", "agent_version": "0.1.0"}, headers=headers)
assert heartbeat.status_code == 200
assert heartbeat.json()["enabled"] is True
created = client.post("/v1/jobs", json={"kind": "REPROCESS_PRODUCTS", "payload": {"codigos": ["000026"]}}, headers=headers)
assert created.status_code == 200
job_id = created.json()["job_id"]
assert created.json()["status"] == "PENDING"
claimed = client.get("/v1/jobs/next", headers=headers)
assert claimed.json()["job_id"] == job_id
assert claimed.json()["status"] == "RUNNING"
empty = client.get("/v1/jobs/next", headers=headers)
assert empty.json() is None # no more pending work; not the same job again
completed = client.post(f"/v1/jobs/{job_id}/complete", json={"result_summary": {"writes_succeeded": 1}}, headers=headers)
assert completed.json()["status"] == "COMPLETED"
assert completed.json()["result_summary"]["writes_succeeded"] == 1
fetched = client.get(f"/v1/jobs/{job_id}", headers=headers)
assert fetched.json()["status"] == "COMPLETED"
def test_agent_status_derives_online_offline():
client, engine = _client()
headers = {"Authorization": "Bearer test-token"}
offline = client.get("/v1/agents/me", headers=headers)
assert offline.json()["status"] == "OFFLINE" # never heartbeated yet
client.post("/v1/agents/heartbeat", json={"status": "IDLE"}, headers=headers)
online = client.get("/v1/agents/me", headers=headers)
body = online.json()
assert body["status"] == "ONLINE"
assert body["enabled"] is True
assert "company_id" in body
def test_job_creation_rejects_unknown_kind():
client, _ = _client()
headers = {"Authorization": "Bearer test-token"}
response = client.post("/v1/jobs", json={"kind": "DELETE_EVERYTHING"}, headers=headers)
assert response.status_code == 400
def test_reprocess_products_requires_codigos():
client, _ = _client()
headers = {"Authorization": "Bearer test-token"}
response = client.post("/v1/jobs", json={"kind": "REPROCESS_PRODUCTS", "payload": {}}, headers=headers)
assert response.status_code == 400
+38
View File
@@ -0,0 +1,38 @@
from central.app.field_contract import ALREADY, CHANGE, MANUAL, NA, sped_pis_cofins_match
from central.tests.test_field_contract import CO1, CO3, EV, decision, product, run, st
UNUSED = {**CO1, "pis_cofins_unused_by_emission": True}
def test_sped_table_lookup_is_prefix_based_and_active_only():
hits = sped_pis_cofins_match("10063021")
assert hits and {h[1] for h in hits} == {"06"} and hits[0][0] == "4.3.13"
assert sped_pis_cofins_match("99999999") == []
def test_simples_pis_cofins_written_only_from_official_table_and_never_assumed_zero():
r = run(p=product(CLASSIFICACAO_FISCAL="10063021"), co=UNUSED)
assert st(r, "COD_SAIDA_PIS") == (CHANGE, "06") and st(r, "COD_SAIDA_COFINS") == (CHANGE, "06")
assert r["ALIQ_PIS"]["state"] == NA and r["COD_ENTRADA_PIS"]["state"] == NA
plain = run(co=UNUSED) # NCM without any SPED special regime: SGV does not consume the field, nothing is invented
assert all(plain[f]["state"] == NA and plain[f]["proposed"] is None for f in ("COD_SAIDA_PIS", "ALIQ_PIS", "COD_ENTRADA_COFINS"))
assert run(co=CO1)["COD_SAIDA_PIS"]["state"] == MANUAL # without emission evidence the company question remains
assert run(co={**CO3, "pis_cofins_unused_by_emission": True})["COD_SAIDA_PIS"]["state"] == MANUAL # evidence only relaxes CRT 1
def test_cfop_never_contradicts_the_erp_st_declaration():
r = run(p=product(CFOP="5405", CSOSN="500", CST="060", SITUACAO_TRIBUTARIA="T"))
assert r["CFOP"]["state"] != CHANGE or r["CFOP"]["proposed"] != "5102"
def test_kitchen_flag_alone_and_cst_digit_never_prove_role_or_origin():
r = run(p=product(PROD_COZINHA=1, COD_ORIGEM_MERCADORIA=None, CST="040"))
assert r["COD_ORIGEM_MERCADORIA"]["state"] == MANUAL and r["COD_ORIGEM_MERCADORIA"]["reason"] == "ORIGIN_NO_EVIDENCE"
assert r["IPPT"]["proposed"] != "P" or r["IPPT"]["state"] != CHANGE
def test_store_ipi_profile_is_a_company_decision_never_defaulted():
undecided = run(ipi_profile=None)
assert undecided["IPI"]["state"] == MANUAL and undecided["IPI"]["input_key"] == "store_ipi_profile"
assert run(ipi_profile={"scope": "COMPANY", "scope_key": "", "key": "store_ipi_profile", "value": "LEAVE_NOT_APPLICABLE"})["IPI"]["state"] == NA
assert run()["IPI"]["state"] == CHANGE # POPULATE_REFERENCE_RATE keeps the TIPI rule
+66
View File
@@ -0,0 +1,66 @@
from datetime import datetime, timezone
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from central.app.datasets.ncm import parse_ncm_payload
PAYLOAD = b'{"Data_Ultima_Atualizacao_NCM":"2026-09-17","Ato":"Ato","Nomenclaturas":[{"Codigo":"08043000","Descricao":"Abacaxis frescos","Data_Inicio":"2022-01-01","Data_Fim":"9999-12-31"}]}'
def test_import_promotes_and_is_idempotent():
from central.app.datasets.service import DatasetService
from central.app.models import Base, Dataset, NcmEntry
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
service = DatasetService(session)
first = service.import_payload(parse_ncm_payload(PAYLOAD), "https://source", datetime.now(timezone.utc), minimum_entries=1)
second = service.import_payload(parse_ncm_payload(PAYLOAD), "https://source", datetime.now(timezone.utc), minimum_entries=1)
assert first.id == second.id
assert session.get(Dataset, first.id).status == "ACTIVE"
assert session.query(NcmEntry).filter_by(dataset_id=first.id).count() == 1
def test_classifier_validates_ncm_and_never_proposes_fiscal_fields():
from central.app.classification import Classifier
class Repository:
def active_entries(self):
return [type("Entry", (), {"code": "08043000", "description": "Abacaxis frescos"})()]
def dataset_versions(self):
return {"ncm": "dataset-1"}
result = Classifier(Repository()).classify({"description": "abacaxi", "current_ncm": "0804.30.00"})
assert result["status"] == "EXACT_NCM"
assert result["classification"]["ncm"] == "08043000"
assert result["classification"]["cest"] is None
assert result["can_auto_apply"] is False
def test_api_auth_and_cache():
from central.app.main import create_app
from central.app.models import Base, Dataset, NcmEntry
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
with Session(engine) as session:
dataset = Dataset(kind="NCM", provider="Siscomex", sha256="a" * 64, version_label="v1", act="act", source_url="url", status="ACTIVE", record_count=1)
session.add(dataset)
session.flush()
session.add(NcmEntry(dataset_id=dataset.id, code="08043000", description="Abacaxis frescos", valid_from="2022", valid_to="9999"))
session.commit()
app = create_app(session_factory=lambda: Session(engine), bootstrap_token="test-token")
client = TestClient(app)
payload = {"product": {"product_id": "1", "description": "abacaxi", "current_ncm": "08043000"}}
assert client.post("/v1/classify", json=payload).status_code == 401
headers = {"Authorization": "Bearer test-token"}
first = client.post("/v1/classify", json=payload, headers=headers).json()
second = client.post("/v1/classify", json=payload, headers=headers).json()
assert first["request_fingerprint"] == second["request_fingerprint"]
assert second["provenance"]["cache_hit"] is True
+172
View File
@@ -0,0 +1,172 @@
from datetime import datetime, timezone
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
CEST_HTML = b"""
<html><body>
<table><tr><td>Ignored</td></tr></table>
<h2>ANEXO II</h2>
<table>
<tr><th>ITEM</th><th>CEST</th><th>NCM/SH</th><th>DESCRICAO</th></tr>
<tr><td>1.0</td><td>01.001.00</td><td>0804.30.00</td><td>Abacaxis</td></tr>
<tr><td>2.0</td><td>01.002.00</td><td>0804.30.00<br>0207.14.00</td><td>Frutas e aves</td></tr>
</table>
<h2>ANEXO XXVII</h2>
<table><tr><th>CEST</th><th>NCM</th></tr><tr><td>99.999.99</td><td>9999.99.99</td></tr></table>
</body></html>
"""
def test_cest_parser_accepts_only_covered_annex_tables_and_hashes_raw_html():
from central.app.datasets.cest import parse_cest_html
parsed = parse_cest_html(CEST_HTML)
assert parsed.version == "CV142_18"
assert parsed.sha256
assert parsed.entries[0].annex == "II"
assert parsed.entries[1].ncm_codes == ("08043000", "02071400")
assert len(parsed.entries) == 2
def test_cest_parser_fails_closed_when_an_annex_table_has_no_required_columns():
from central.app.datasets.cest import parse_cest_html
with pytest.raises(ValueError, match="required columns"):
parse_cest_html(b"<h2>ANEXO II</h2><table><tr><th>CEST</th></tr><tr><td>01.001.00</td></tr></table>")
def test_cest_parser_accepts_official_four_digit_ncm_headings():
from central.app.datasets.cest import parse_cest_html
parsed = parse_cest_html(b"<h2>ANEXO III</h2><table><tr><th>CEST</th><th>NCM/SH</th></tr><tr><td>02.001.00</td><td>2205</td></tr></table>")
assert parsed.entries[0].ncm_codes == ("2205",)
def test_cest_parser_ignores_official_editorial_rows_without_cest_data():
from central.app.datasets.cest import parse_cest_html
parsed = parse_cest_html(b"<h2>ANEXO II</h2><table><tr><th>CEST</th><th>NCM/SH</th></tr><tr><td>Nova redacao dada ao item.</td></tr><tr><td>01.001.00</td><td>3815.12.10</td></tr></table>")
assert [entry.code for entry in parsed.entries] == ["01.001.00"]
def test_cest_parser_preserves_chapter_ncm_prefixes_and_empty_official_ncm_cells():
from central.app.datasets.cest import parse_cest_html
parsed = parse_cest_html(b"<h2>ANEXO XXVI</h2><table><tr><th>CEST</th><th>NCM/SH</th></tr><tr><td>28.055.00</td><td>Capitulo 33</td></tr><tr><td>28.056.00</td><td></td></tr></table>")
assert parsed.entries[0].ncm_codes == ("33",)
assert parsed.entries[1].ncm_codes == ()
def test_classifier_distinguishes_exact_legacy_and_invalid_ncm_and_uses_cest_matches():
from central.app.classification import Classifier
class Repository:
def active_entries(self):
return [type("Entry", (), {"code": "08043000", "description": "Abacaxis"})()]
def cest_for_ncm(self, code):
return [type("Cest", (), {"code": "01.001.00", "description": "Abacaxis"})()] if code == "08043000" else []
def legacy_ncm(self, code):
return {"code": code, "source": "Siscomex", "source_date": "2026-09-17", "reason": "NCM not present in current official nomenclature; no official successor."} if code == "02071400" else None
def dataset_versions(self):
return {"ncm": "ncm-version", "cest": "cest-version"}
classifier = Classifier(Repository())
exact = classifier.classify({"current_ncm": "0804.30.00", "description": "abacaxi"})
legacy = classifier.classify({"current_ncm": "0207.14.00"})
invalid = classifier.classify({"current_ncm": "0000.00.00"})
assert exact["status"] == "EXACT_NCM"
assert exact["classification"]["cest"] == ["01.001.00"]
assert legacy["status"] == "LEGACY_NCM"
assert legacy["classification"]["ncm"] == "02071400"
assert legacy["legacy_ncm"]["reason"].endswith("no official successor.")
assert invalid["status"] == "INVALID_NCM"
def test_classifier_reports_confirmed_cest_only_for_one_distinct_official_candidate():
from central.app.classification import Classifier
class Repository:
def active_entries(self):
return [type("Entry", (), {"code": "08043000", "description": "Abacaxi"})()]
def cest_for_ncm(self, code):
return [type("Cest", (), {"code": "01.001.00", "description": "Abacaxi"})()]
def legacy_ncm(self, code): return None
def dataset_versions(self): return {"ncm": "n", "cest": "c"}
result = Classifier(Repository()).classify({"current_ncm": "08043000", "description": "Abacaxi"})
assert result["cest_status"] == "CEST_CONFIRMED"
def test_classifier_reports_candidates_for_multiple_distinct_cest_codes():
from central.app.classification import Classifier
class Repository:
def active_entries(self):
return [type("Entry", (), {"code": "08043000", "description": "Abacaxi"})()]
def cest_for_ncm(self, code):
return [type("Cest", (), {"code": "01.001.00", "description": "Abacaxi"})(), type("Cest", (), {"code": "01.002.00", "description": "Frutas"})()]
def legacy_ncm(self, code): return None
def dataset_versions(self): return {"ncm": "n", "cest": "c"}
result = Classifier(Repository()).classify({"current_ncm": "08043000", "description": "Abacaxi"})
assert result["cest_status"] == "CEST_CANDIDATES"
assert result["classification"]["cest"] == ["01.001.00", "01.002.00"]
def test_cest_import_creates_many_to_many_ncm_links_and_stores_html_metadata():
from central.app.datasets.cest import parse_cest_html
from central.app.datasets.service import DatasetService
from central.app.models import Base, CestEntry, CestNcmEntry, Dataset
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
dataset = DatasetService(session).import_cest_payload(
parse_cest_html(CEST_HTML), "https://www.confaz.fazenda.gov.br/legislacao/convenios/2018/CV142_18", datetime.now(timezone.utc)
)
assert dataset.kind == "CEST"
assert dataset.raw_sha256 == dataset.sha256
assert session.query(CestEntry).filter_by(dataset_id=dataset.id).count() == 2
assert session.query(CestNcmEntry).count() == 3
def test_cest_lookup_matches_official_ncm_prefix_links():
from central.app.datasets.cest import parse_cest_html
from central.app.datasets.service import DatasetService
from central.app.models import Base
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
service = DatasetService(session)
service.import_cest_payload(parse_cest_html(b"<h2>ANEXO III</h2><table><tr><th>CEST</th><th>NCM</th></tr><tr><td>02.001.00</td><td>2205</td></tr></table>"), "https://source", datetime.now(timezone.utc))
assert [entry.code for entry in service.cest_for_ncm("22051000")] == ["02.001.00"]
def test_cest_import_unions_repeated_official_cest_codes_into_one_link_set():
from central.app.datasets.cest import parse_cest_html
from central.app.datasets.service import DatasetService
from central.app.models import Base, CestEntry, CestNcmEntry
payload = parse_cest_html(b"<h2>ANEXO II</h2><table><tr><th>CEST</th><th>NCM</th></tr><tr><td>01.042.00</td><td>8421.32.00</td></tr><tr><td>01.042.00</td><td>8421.39.20</td></tr></table>")
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
dataset = DatasetService(session).import_cest_payload(payload, "https://source", datetime.now(timezone.utc))
assert session.query(CestEntry).filter_by(dataset_id=dataset.id).count() == 1
assert {link.ncm_code for link in session.query(CestNcmEntry).all()} == {"84213200", "84213920"}
+17
View File
@@ -0,0 +1,17 @@
import pytest
from central.app.datasets.ncm import parse_ncm_payload
def test_parser_accepts_verified_siscomex_payload_shape():
payload = b'{"Data_Ultima_Atualizacao_NCM":"Vigente em 17/09/2026","Ato":"Resolucao Gecex 926/2026","Nomenclaturas":[{"Codigo":"08043000","Descricao":"Abacaxis.","Data_Inicio":"01/04/2022","Data_Fim":"31/12/9999"}]}'
parsed = parse_ncm_payload(payload)
assert parsed.version == "Vigente em 17/09/2026"
assert parsed.entries[0].code == "08043000"
def test_parser_rejects_unknown_payload_shape():
with pytest.raises(ValueError, match="Nomenclaturas"):
parse_ncm_payload(b'{"items": []}')
+93
View File
@@ -0,0 +1,93 @@
from datetime import datetime, timezone
from functools import lru_cache
from pathlib import Path
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from central.app.datasets.nfe_moc_tables import parse_moc_tables
from central.app.datasets.service import DatasetService
from central.app.models import Base
SOURCE = Path(__file__).parents[2] / "sources" / "raw" / "bootstrap_v1" / "moc7-anexo-i-leiaute-e-rv.pdf"
pytestmark = pytest.mark.skipif(not SOURCE.exists(), reason="official MOC PDF not present locally")
@lru_cache(maxsize=1)
def _payload():
# Parsing this 153-page PDF is expensive (~40s); every test in this module
# shares one parse instead of re-running it per test.
return parse_moc_tables(SOURCE.read_bytes())
def test_parses_all_five_domains_with_expected_minimum_coverage():
payload = _payload()
from collections import Counter
counts = Counter(e.domain for e in payload.entries)
assert counts["ORIGEM_MERCADORIA"] == 9
assert counts["CST_ICMS"] >= 11
assert counts["CSOSN"] >= 10
assert counts["CST_PIS"] >= 29
assert counts["CST_COFINS"] >= 29
def test_every_entry_has_provenance_and_no_invented_text():
payload = _payload()
for entry in payload.entries:
assert entry.source_section.startswith("MOC7 p.")
assert entry.description.strip()
assert entry.code.strip()
def test_origem_codes_are_0_through_8():
payload = _payload()
codes = sorted(e.code for e in payload.entries if e.domain == "ORIGEM_MERCADORIA")
assert codes == [str(n) for n in range(9)]
def test_cst_icms_includes_split_group_40_41_50():
payload = _payload()
by_code = {e.code: e for e in payload.entries if e.domain == "CST_ICMS"}
assert "isenta" in by_code["40"].description.lower()
assert "tributada" in by_code["41"].description.lower()
assert "suspens" in by_code["50"].description.lower()
def test_reimport_is_idempotent():
payload = _payload()
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
service = DatasetService(session)
first = service.import_moc_tables(payload, "file://moc7.pdf", datetime.now(timezone.utc))
second = service.import_moc_tables(payload, "file://moc7.pdf", datetime.now(timezone.utc))
assert first.id == second.id
assert second.status == "ACTIVE"
def test_lookup_smoke_for_each_domain():
payload = _payload()
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
service = DatasetService(session)
service.import_moc_tables(payload, "file://moc7.pdf", datetime.now(timezone.utc))
assert len(service.fiscal_codes("ORIGEM_MERCADORIA")) == 9
assert service.fiscal_codes("ORIGEM_MERCADORIA", code="0")[0].code == "0"
assert service.fiscal_codes("CST_ICMS", code="00")
assert service.fiscal_codes("CSOSN", code="101")
assert service.fiscal_codes("CST_PIS", code="01")
assert service.fiscal_codes("CST_COFINS", code="01")
assert service.fiscal_codes("CST_ICMS", code="99") == []
def test_dataset_versions_includes_nfe_moc_tables_and_changes_hash_on_reimport():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
service = DatasetService(session)
assert service.dataset_versions()["nfe_moc_tables"] is None
service.import_moc_tables(_payload(), "file://moc7.pdf", datetime.now(timezone.utc))
assert service.dataset_versions()["nfe_moc_tables"] is not None
+73
View File
@@ -0,0 +1,73 @@
import json
from pathlib import Path
import pytest
from central.app.product_defaults import cfop_default, cst_status, csosn_default, validate_against_history
CFOPS = {"5102", "5405", "5656", "1102"}
CSOSNS = {"101", "102", "103", "500", "400"}
def P(**kw):
return {"CFOP": "5102", "CSOSN": "102", "CST": "040", **kw}
def test_cfop_consistent_non_st_is_resolved_but_never_a_write():
r = cfop_default(P(), "EXACT_NCM", "NO_MVA_MAPPING_FOUND", CFOPS)
assert r["status"] == "CFOP_DEFAULT_RESOLVED" and r["action_class"] == "ALREADY_CORRECT" and not r["write_eligible"]
def test_cfop_st_conflict_is_candidate_review_not_write():
r = cfop_default(P(), "EXACT_NCM", "MVA_RESOLVED", CFOPS)
assert r["status"] == "CFOP_DEFAULT_CANDIDATE" and r["proposed_value"] == "5405" and r["action_class"] == "REVIEW_REQUIRED" and not r["write_eligible"]
def test_cfop_insufficient_context_never_resolved():
assert cfop_default(P(), "EXACT_NCM", "MVA_CANDIDATES", CFOPS)["status"] == "CFOP_OPERATION_CONTEXT_REQUIRED"
assert cfop_default(P(CFOP=None), "EXACT_NCM", "NO_MVA_MAPPING_FOUND", CFOPS)["status"] == "CFOP_OPERATION_CONTEXT_REQUIRED"
assert cfop_default(P(CFOP="6102"), "EXACT_NCM", "NO_MVA_MAPPING_FOUND", CFOPS | {"6102"})["status"] == "CFOP_OPERATION_CONTEXT_REQUIRED"
assert cfop_default(P(), "LEGACY_NCM", "NO_MVA_MAPPING_FOUND", CFOPS)["status"] == "CFOP_UNRESOLVED"
assert cfop_default(P(CFOP="9999"), "EXACT_NCM", "NO_MVA_MAPPING_FOUND", CFOPS)["status"] == "CFOP_UNRESOLVED"
def test_csosn_is_never_resolved_and_never_universal_102():
for mva in ("MVA_RESOLVED", "MVA_CANDIDATES", "NO_MVA_MAPPING_FOUND"):
r = csosn_default(P(), "EXACT_NCM", mva, CSOSNS, "102")
assert r["status"] != "CSOSN_DEFAULT_RESOLVED" and not r["write_eligible"]
r = csosn_default(P(CSOSN="101"), "EXACT_NCM", "NO_MVA_MAPPING_FOUND", CSOSNS, "102")
assert r["proposed_value"] is None
def test_csosn_st_subject_flags_conflict_and_requires_retention_context():
r = csosn_default(P(), "EXACT_NCM", "MVA_RESOLVED", CSOSNS, "102")
assert r["status"] == "CSOSN_OPERATION_CONTEXT_REQUIRED" and r["consistency_flag"] == "ST_SUBJECT_BUT_CSOSN_NOT_500"
def test_history_validates_but_does_not_create_rules():
assert validate_against_history("5102", ["5102", "5102"]) == "MATCH"
assert validate_against_history("5102", ["5102", "5405"]) == "MISMATCH"
assert validate_against_history("5102", []) == "UNVALIDATED"
assert validate_against_history(None, ["5102"]) == "UNVALIDATED" # history alone never proposes a value
def test_cst_is_reference_only_under_crt1():
r = cst_status(P(), {"40", "00"}, set("012345678"))
assert r["status"] == "CST_REFERENCE_ONLY" and r["origin_digit"] == "0" and not r["write_eligible"]
assert cst_status(P(CST="99"), {"40"}, set("0"))["status"] == "CST_INVALID_REVIEW"
def test_engine_is_deterministic_idempotent():
a = cfop_default(P(), "EXACT_NCM", "MVA_RESOLVED", CFOPS)
assert a == cfop_default(P(), "EXACT_NCM", "MVA_RESOLVED", CFOPS)
REC = Path(__file__).resolve().parents[2] / "docs" / "NCM_HISTORICAL_RECONCILIATION_V1.json"
@pytest.mark.skipif(not REC.exists(), reason="reconciliation artifact not generated")
def test_reconciliation_accounts_for_every_mismatch_and_finds_no_technical_bug():
d = json.loads(REC.read_text(encoding="utf-8"))
assert sum(d["classification"].values()) == d["mismatches_total"]
assert d["classification"].get("NORMALIZATION_BUG", 0) == 0
assert d["trusted_corpus"]["TRUSTED_HISTORICAL_ITEMS"] > 0
+53
View File
@@ -0,0 +1,53 @@
from datetime import datetime, timezone
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from central.app.datasets.service import DatasetService
from central.app.main import create_app
from central.app.models import AnpProductCode, Base, CfopEntry, Dataset, FcpRate, NcmUtribEntry
def _client_with_reference_data():
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
with Session(engine) as session:
dataset = Dataset(kind="CFOP", provider="p", sha256="a" * 64, version_label="v", act="a", source_url="u", status="ACTIVE", record_count=1)
session.add(dataset); session.flush()
session.add(CfopEntry(dataset_id=dataset.id, code="1101", title="Compra", description="desc"))
d2 = Dataset(kind="NCM_UTRIB", provider="p", sha256="b" * 64, version_label="v", act="a", source_url="u", status="ACTIVE", record_count=1)
session.add(d2); session.flush()
session.add(NcmUtribEntry(dataset_id=d2.id, ncm="01012100", utrib_abbreviation="UN", utrib_description="Unidade"))
d3 = Dataset(kind="ANP", provider="p", sha256="c" * 64, version_label="v", act="a", source_url="u", status="ACTIVE", record_count=1)
session.add(d3); session.flush()
session.add(AnpProductCode(dataset_id=d3.id, cprod_anp="110203073"))
d4 = Dataset(kind="FCP", provider="p", sha256="d" * 64, version_label="v", act="a", source_url="u", status="ACTIVE", record_count=1)
session.add(d4); session.flush()
session.add(FcpRate(dataset_id=d4.id, uf_code="29", uf="BA", uf_name="BAHIA", aliq_1="Fixo:2.00", observacao="obs"))
session.commit()
app = create_app(session_factory=lambda: Session(engine), bootstrap_token="test-token")
return TestClient(app)
def test_reference_endpoints_found_and_not_found():
client = _client_with_reference_data()
headers = {"Authorization": "Bearer test-token"}
assert client.get("/v1/reference/cfop/1101", headers=headers).json()["found"] is True
assert client.get("/v1/reference/cfop/9999", headers=headers).json()["found"] is False
assert client.get("/v1/reference/ncm_utrib/01012100", headers=headers).json()["found"] is True
assert client.get("/v1/reference/ncm_utrib/99999999", headers=headers).json()["found"] is False
assert client.get("/v1/reference/anp/110203073", headers=headers).json()["found"] is True
assert client.get("/v1/reference/anp/000000000", headers=headers).json()["found"] is False
fcp = client.get("/v1/reference/fcp/BA", headers=headers).json()
assert fcp["found"] is True
assert fcp["aliq_1"] == "Fixo:2.00"
assert client.get("/v1/reference/fcp/ZZ", headers=headers).json()["found"] is False
+77
View File
@@ -0,0 +1,77 @@
import importlib.util
import sys
from pathlib import Path
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from central.app.auth import authenticate, token_hash
from central.app.models import Base
SCRIPT = Path(__file__).parents[1] / "scripts" / "register_agent.py"
def load_module():
spec = importlib.util.spec_from_file_location("register_agent", SCRIPT)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
register_agent_module = load_module()
def test_register_agent_creates_tenant_and_hashed_token_only():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
info, token = register_agent_module.register_agent(session, "Restaurante X", "loja-01")
found = authenticate(session, token)
assert found is not None
assert found.id == info["id"]
assert found.token_hash == token_hash(token)
assert found.token_hash != token # only the hash is ever persisted
# Mirrors the real CLI's main(): reading the returned info AFTER the
# session (and its `with` block) has closed. This is exactly the scenario
# that broke when register_agent() returned live ORM objects instead of
# plain values (DetachedInstanceError) — must keep working unattached.
assert info["enabled"] is True
assert isinstance(info["tenant_id"], int)
def test_register_agent_reuses_existing_tenant():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
info1, _ = register_agent_module.register_agent(session, "Restaurante X", "loja-01")
info2, _ = register_agent_module.register_agent(session, "Restaurante X", "loja-02")
assert info1["tenant_id"] == info2["tenant_id"]
assert info1["id"] != info2["id"]
def test_register_agent_generates_unique_tokens():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
_, token1 = register_agent_module.register_agent(session, "A", "a1")
_, token2 = register_agent_module.register_agent(session, "A", "a2")
assert token1 != token2
def test_disabled_agent_cannot_authenticate():
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from central.app.auth import authenticate, token_hash
from central.app.models import Agent, Base, Tenant
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as s:
tenant = Tenant(name="t"); s.add(tenant); s.flush()
agent = Agent(tenant_id=tenant.id, name="a", token_hash=token_hash("secret-token")); s.add(agent); s.commit()
assert authenticate(s, "secret-token").id == agent.id
agent.enabled = False; s.commit()
assert authenticate(s, "secret-token") is None
assert authenticate(s, "wrong") is None
+62
View File
@@ -0,0 +1,62 @@
from datetime import datetime, timezone
from functools import lru_cache
from pathlib import Path
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from central.app.datasets import bootstrap_v1_extra as parsers
from central.app.datasets.service import DatasetService
from central.app.models import Base, RtcCstIbsCbsEntry
ROOT = Path(__file__).parents[2] / "sources" / "raw" / "bootstrap_v1"
CCLASS = ROOT / "cClassTrib 2026-06-22.xlsx"
CBS = ROOT / "IT 2026.002 v.1.00 - Aliquotas da CBS.xlsx"
pytestmark = pytest.mark.skipif(not (CCLASS.exists() and CBS.exists()), reason="RTC bootstrap files not present locally")
@lru_cache(maxsize=None)
def _cclass():
return parsers.parse_rtc_cclasstrib(CCLASS.read_bytes())
def _session():
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
return Session(engine)
def test_cclasstrib_keys_unique_and_rich_fields_kept():
p = _cclass()
codes = [e["cclasstrib"] for e in p.entries]
assert len(codes) == len(set(codes)) >= 100
assert all(len(c) == 6 for c in codes)
assert p.entries[0]["indicators"] and p.entries[0]["d_ini_vig"]
assert {e["cst"] for e in p.entries} <= {e["cst"] for e in p.extra_entries}
def test_cbs_rates_2026_numeric_and_2027_pending():
p = parsers.parse_rtc_cbs_rates(CBS.read_bytes())
by_year = {e["year"]: e for e in p.entries}
assert by_year[2026]["rate"] == pytest.approx(0.009)
assert by_year[2027]["rate"] is None and by_year[2027]["rate_text"]
def test_import_idempotent_lookup_and_versions():
with _session() as s:
svc = DatasetService(s)
assert svc.dataset_versions()["rtc_cclasstrib"] is None
now = datetime.now(timezone.utc)
a = svc.import_rtc_cclasstrib(_cclass(), "file://x", now)
b = svc.import_rtc_cclasstrib(_cclass(), "file://x", now)
assert a.id == b.id and b.status == "ACTIVE" and b.record_count == len(_cclass().entries)
assert s.query(RtcCstIbsCbsEntry).count() == len(_cclass().extra_entries)
assert svc.rtc_cclasstrib(code="000001")
cbs_payload = parsers.parse_rtc_cbs_rates(CBS.read_bytes())
c = svc.import_rtc_cbs_rates(cbs_payload, "file://y", now)
assert svc.import_rtc_cbs_rates(cbs_payload, "file://y", now).id == c.id
assert svc.rtc_cbs_rate(2026).rate == pytest.approx(0.009)
v = svc.dataset_versions()
assert v["rtc_cclasstrib"] and v["rtc_cbs_rates"]
+29
View File
@@ -0,0 +1,29 @@
from io import BytesIO
import openpyxl
def test_tipi_parser_requires_official_columns_and_reads_ncm_rows():
from central.app.datasets.tipi import parse_tipi_xlsx
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.append(["NCM", "EX", "DESCRIÇÃO", "ALÍQUOTA (%)"])
sheet.append(["0101.21.00", None, "Reprodutores", "0"])
raw = BytesIO(); workbook.save(raw)
payload = parse_tipi_xlsx(raw.getvalue())
assert payload.entries[0].ncm == "01012100"
assert payload.entries[0].rate == "0"
def test_tipi_parser_preserves_ex_in_the_ncm_key():
from central.app.datasets.tipi import parse_tipi_xlsx
workbook = openpyxl.Workbook(); sheet = workbook.active
sheet.append(["NCM", "EX", "DESCRIÇÃO", "ALÍQUOTA (%)"])
sheet.append(["0101.21.00", "01", "Com EX", "NT"])
raw = BytesIO(); workbook.save(raw)
entry = parse_tipi_xlsx(raw.getvalue()).entries[0]
assert entry.ex == "01"
assert entry.rate == "NT"