feat: Contexto Fiscal admin UI - reduces fiscal policy list to 3 real decisions
Adds an ADMIN-only "Contexto Fiscal" section to the Agent detail page: confirm/alter/clear the fiscal decisions
field_contract.resolve_product genuinely cannot derive from the ERP alone (icms_treatment, pis_cofins_profile,
entry_scope). Persists through the existing FiscalContextEntry table (the same one blocker_resolution already
writes operator answers into) - no new persistence model, no opaque JSON box. CSRF + RBAC + audit reuse the exact
mechanism already proven for /agents/{id}/features. Confirming or clearing flags every already-enriched product on
the installation for re-evaluation.
The list was reduced from 5 candidates to 3 by auditing real production data (Agent 2, 2026-09-27/28):
icms_rate/credit_rate and rounding were dropped - both proven NOT_APPLICABLE / ALREADY_DERIVED for this CRT=1
company from real field_contract dry-runs, not assumption. Real evidence surfaced in the UI is a dated, one-time
manual read-only measurement (disclosed in the card copy itself as such) - the Hub has no direct Firebird access,
so this is not a live query; a follow-up should pipe it through the heartbeat the same way CRT/CONTRIBUINTE_IPI
were wired.
Also found, during the same audit, that this client's NFC-e emission ignores the product's cadastral PIS/COFINS
CST/rate fields entirely (verified on the 3 real products that DO have them populated - the emitted documents never
carry the cadastral value) - documented as a strong OPEN recommendation for a future field_contract change, not
applied here, since changing canonical fiscal semantics needs accountant sign-off, not just my own inference.
1129 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.9 (single GTI_FISCAL_VERSION). Hub
only - Agent unchanged, no new installer this release.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Contexto Fiscal (Agent detail, ADMIN only): confirm/alter/clear one of the reduced set of real fiscal decisions
|
||||
(icms_treatment/pis_cofins_profile/entry_scope). CSRF, RBAC and audit reuse the exact same mechanism already proven for
|
||||
/agents/{id}/features; persistence reuses FiscalContextEntry, the same table blocker_resolution already writes to."""
|
||||
from sqlalchemy import select
|
||||
|
||||
from central.app.models import AuditEvent, FiscalContextEntry, Installation, ProductEnrichment
|
||||
from central.tests.test_control_panel_pages import _panel_client
|
||||
from central.tests.test_rtc_security import _become, _post
|
||||
|
||||
|
||||
def _company_key(client):
|
||||
with client._session_factory() as s:
|
||||
inst = s.scalars(select(Installation)).one()
|
||||
return (inst.company_code or inst.company_name or "").strip(), inst.tenant_id, inst.id
|
||||
|
||||
|
||||
def test_fiscal_context_tab_lists_only_the_three_reduced_decisions_with_evidence():
|
||||
client, agent_id, _ = _panel_client()
|
||||
_become(client, "ADMIN")
|
||||
page = client.get(f"/agents/{agent_id}").text
|
||||
assert "Contexto Fiscal" in page
|
||||
for title in ("Tratamento padrão de ICMS", "Perfil de PIS/COFINS", "CFOP de entrada padrão"):
|
||||
assert title in page
|
||||
assert "487 de 521" in page # real evidence shown, not a raw internal key name
|
||||
assert "<h3>Tratamento padrão de ICMS dos produtos comuns</h3>" in page # human title heads the card; internal key only appears as a hidden form field
|
||||
|
||||
|
||||
def test_fiscal_context_hidden_from_non_admin():
|
||||
client, agent_id, _ = _panel_client()
|
||||
_become(client, "PADRAO")
|
||||
page = client.get(f"/agents/{agent_id}").text
|
||||
assert "Contexto Fiscal" not in page
|
||||
|
||||
|
||||
def test_confirming_a_decision_is_csrf_admin_and_audited_and_flags_reevaluation():
|
||||
client, agent_id, _ = _panel_client()
|
||||
company_key, tenant_id, installation_id = _company_key(client)
|
||||
with client._session_factory() as s:
|
||||
s.add(ProductEnrichment(tenant_id=tenant_id, installation_id=installation_id, product_code="P1", status="RESOLVED", ui_status="PRONTO_PARA_PREENCHER"))
|
||||
s.commit()
|
||||
_become(client, "PADRAO")
|
||||
assert _post(client, f"/agents/{agent_id}/fiscal-context", key="icms_treatment", value="TAXED", fc_action="confirm").status_code == 403
|
||||
_become(client, "ADMIN")
|
||||
assert client.post(f"/agents/{agent_id}/fiscal-context", data={"csrf_token": "bad", "key": "icms_treatment", "value": "TAXED", "fc_action": "confirm"}, follow_redirects=False).status_code in (400, 403)
|
||||
assert _post(client, f"/agents/{agent_id}/fiscal-context", key="icms_treatment", value="TAXED", fc_action="confirm").status_code == 303
|
||||
with client._session_factory() as s:
|
||||
entry = s.scalars(select(FiscalContextEntry).where(FiscalContextEntry.key == "icms_treatment")).one()
|
||||
assert entry.scope == "COMPANY" and entry.value == "TAXED" and entry.source == "OPERATOR"
|
||||
acts = [e.action for e in s.scalars(select(AuditEvent))]
|
||||
assert "FISCAL_CONTEXT_DECISION" in acts
|
||||
row = s.scalars(select(ProductEnrichment)).one()
|
||||
assert row.reevaluate is True # existing products get a chance to pick up the new policy - never a silent no-op
|
||||
|
||||
|
||||
def test_clearing_a_decision_deletes_the_entry_never_a_default_value():
|
||||
client, agent_id, _ = _panel_client()
|
||||
company_key, tenant_id, installation_id = _company_key(client)
|
||||
_become(client, "ADMIN")
|
||||
assert _post(client, f"/agents/{agent_id}/fiscal-context", key="icms_treatment", value="TAXED", fc_action="confirm").status_code == 303
|
||||
assert _post(client, f"/agents/{agent_id}/fiscal-context", key="icms_treatment", fc_action="clear").status_code == 303
|
||||
with client._session_factory() as s:
|
||||
assert s.scalars(select(FiscalContextEntry).where(FiscalContextEntry.key == "icms_treatment")).first() is None
|
||||
|
||||
|
||||
def test_invalid_value_is_rejected_never_silently_stored():
|
||||
client, agent_id, _ = _panel_client()
|
||||
_become(client, "ADMIN")
|
||||
resp = client.post(f"/agents/{agent_id}/fiscal-context", data={"csrf_token": client.cookies.get("gti_csrf"), "key": "icms_treatment", "value": "NOT_A_REAL_TREATMENT", "fc_action": "confirm"}, follow_redirects=False)
|
||||
assert resp.status_code == 422
|
||||
with client._session_factory() as s:
|
||||
assert s.scalars(select(FiscalContextEntry)).first() is None
|
||||
|
||||
|
||||
def test_unknown_key_is_refused():
|
||||
client, agent_id, _ = _panel_client()
|
||||
_become(client, "ADMIN")
|
||||
resp = client.post(f"/agents/{agent_id}/fiscal-context", data={"csrf_token": client.cookies.get("gti_csrf"), "key": "not_a_real_key", "value": "x", "fc_action": "confirm"}, follow_redirects=False)
|
||||
assert resp.status_code == 422
|
||||
Reference in New Issue
Block a user