feat: unified fiscal coverage - PIS/COFINS applicability + conditional RTC in one definition, one queue, one panel

- central/app/unified_fiscal_coverage.py: pure rules (PIS/COFINS NOT_APPLICABLE/REQUIRED/OPTIONAL/NEEDS_REVIEW, RTC only when the ERP switch is on)
- agent: read-only loader (unified_fiscal.py) replaces the legacy/expanded module; findings feed the single operational state, coverage and blocker queue
- hub: BLOCKED_FISCAL_DATA blockers (PIS/COFINS/RTC) share the queue; stale ones close on the next full pass; dashboard breakdown gains CEST/PIS/COFINS/RTC
- panel: legacy/expanded coverage block removed; discreet 'Reforma Tributaria: Ativa/Desativada'
- docs: unified_fiscal_completeness, pis_cofins_applicability, rtc_pis_cofins_model + official source manifests; read-only E2E script

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
gti
2026-09-24 16:39:53 -03:00
co-authored by Claude Sonnet 5
parent d897cceebb
commit b15dbea213
32 changed files with 3979 additions and 517 deletions
+42
View File
@@ -194,3 +194,45 @@ def test_panel_controls_require_login():
anon = TestClient(create_app(database_probe=lambda: True, session_factory=factory, bootstrap_token=None))
for action in ("sync-now", "pause", "resume"):
assert anon.post(f"/agents/{agent_id}/{action}", data={}, follow_redirects=False).status_code == 303 # bounced to login, nothing executed
def _fiscal_blocker(code, field, reason, fp):
return {"company": "", "product_code": code, "gtin": None, "description": "P" + code, "blocker_type": "BLOCKED_FISCAL_DATA", "field": field, "reason_code": reason, "evidence_summary": {}, "input_fingerprint": fp}
def test_fiscal_blockers_share_the_single_queue_and_are_resolved_by_the_next_full_pass():
"""PIS/COFINS/RTC blockers are ordinary blockers; when a later FULL pass no longer reports them (data fixed / RTC switched off) they close automatically."""
from central.app.models import BlockedProduct
client, engine = _client()
hb(client)
operational = {**OPERATIONAL, "COMPLETE": 519, "BLOCKED_MISSING_EVIDENCE": 0, "BLOCKED_CONFLICT": 0, "BLOCKED_FISCAL_DATA": 2, "SAFE_BLOCKED": 2, "TOTAL_PRODUCTS": 521}
first = {"operational": operational, "blocked_products": [_fiscal_blocker("10", "PIS", "PIS_CST_INVALID", "a"), _fiscal_blocker("11", "RTC", "CCLASSTRIB_MISSING", "b")], "resolved_products": [],
"fiscal_context": {"rtc_enabled": True, "evaluated_all": True}}
finish(client, engine, first)
with Session(engine) as s:
rows = s.scalars(select(BlockedProduct).where(BlockedProduct.resolved_at.is_(None))).all()
assert sorted((r.product_code, r.field) for r in rows) == [("10", "PIS"), ("11", "RTC")]
snap = s.scalars(select(AgentSnapshot)).one()
assert (snap.fiscally_complete, snap.safe_blocked, snap.total_products) == (519, 2, 521)
age_last_sync(engine, 4000)
hb(client)
second = {"operational": {**OPERATIONAL, "COMPLETE": 520, "BLOCKED_MISSING_EVIDENCE": 0, "BLOCKED_CONFLICT": 0, "BLOCKED_FISCAL_DATA": 1, "SAFE_BLOCKED": 1},
"blocked_products": [_fiscal_blocker("10", "PIS", "PIS_CST_INVALID", "a")], "resolved_products": [], "fiscal_context": {"rtc_enabled": False, "evaluated_all": True}}
finish(client, engine, second)
with Session(engine) as s:
open_rows = s.scalars(select(BlockedProduct).where(BlockedProduct.resolved_at.is_(None))).all()
assert [(r.product_code, r.field) for r in open_rows] == [("10", "PIS")] # RTC blocker closed because RTC is off now
closed = s.scalars(select(BlockedProduct).where(BlockedProduct.resolved_at.is_not(None))).all()
assert [(r.product_code, r.resolution_source) for r in closed] == [("11", "AUTO_REEVALUATION")]
def test_partial_reprocess_never_closes_fiscal_blockers_of_other_products():
from central.app.models import BlockedProduct
client, engine = _client()
hb(client)
finish(client, engine, {"operational": OPERATIONAL, "blocked_products": [_fiscal_blocker("10", "PIS", "PIS_CST_INVALID", "a")], "resolved_products": [], "fiscal_context": {"evaluated_all": True}})
age_last_sync(engine, 4000)
hb(client)
finish(client, engine, {"operational": OPERATIONAL, "blocked_products": [], "resolved_products": [], "fiscal_context": {"evaluated_all": False}})
with Session(engine) as s:
assert len(s.scalars(select(BlockedProduct).where(BlockedProduct.resolved_at.is_(None))).all()) == 1