fix: gate cClassTrib applicability by CRT and date

This commit is contained in:
gti
2026-09-25 17:47:04 -03:00
parent 95605c2ff5
commit 4a12640031
25 changed files with 498 additions and 72 deletions
+14
View File
@@ -690,6 +690,20 @@ def test_panel_shows_rtc_products_summary_and_the_pending_message_only_when_rtc_
for legacy in ("Escopo anterior", "Escopo ampliado"):
assert legacy not in on
_complete_sync(client, agent_id, {
"rtc_enabled": True,
"rtc_supported": True,
"rtc_catalog_valid": True,
"cclasstrib_applicability": {"state": "NOT_APPLICABLE", "basis": "SIMPLES_CCLASSTRIB_NOT_EFFECTIVE"},
"rtc_resolution": {"total": 521, "valid_existing": 0, "ready_to_apply": 0, "insufficient": 521},
})
not_applicable = client.get(f"/agents/{agent_id}").text
assert "cClassTrib: Não utilizado neste cliente" in not_applicable
assert "cClassTrib pendente em 521 produtos" not in not_applicable
rtc_page = client.get(f"/agents/{agent_id}/rtc").text
assert "cClassTrib: Não utilizado neste cliente" in rtc_page
assert "cClassTrib pendente em 521 produtos" not in rtc_page
def test_rtc_control_page_shows_human_labels_and_a_catalog_column_never_raw_enums():
from central.app.panel_presentation import abort_reason_label, audit_outcome_label, candidate_status_label, catalog_state_label, blocker_reason_label, blocker_type_label, rtc_rule_label
+1 -1
View File
@@ -17,7 +17,7 @@ def test_health_is_unavailable_when_database_is_down():
def test_version_endpoint_reports_release_and_fiscal_versions():
body = TestClient(create_app(database_probe=lambda: True)).get("/version").json()
assert body["version"] == "1.2.4" and body["api_compat"] == "1.0" and body["engine_version"] and body["decision_version"]
assert body["version"] == "1.2.5" and body["api_compat"] == "1.0" and body["engine_version"] and body["decision_version"]
def test_production_refuses_the_dev_token(monkeypatch):
@@ -606,3 +606,18 @@ def test_rtc_status_view_is_discreet_and_optional():
assert on["label"] == "Ativa" and on["enabled"] and on["catalog_valid"]
assert blocker_type_label("RTC_CST_MISSING") == "CST IBS/CBS ausente no catálogo" and blocker_type_label("COFINS_RATE_INVALID") == "Alíquota COFINS inválida"
assert blocker_type_label("PIS_CST_INCIDENCE_MISMATCH") == "CST PIS incompatível com a incidência"
def test_rtc_status_view_hides_product_pending_when_cclasstrib_is_not_applicable():
from central.app.panel_presentation import rtc_status_view
result = rtc_status_view({"fiscal_context": {
"rtc_enabled": True,
"rtc_resolution": {"total": 521, "valid_existing": 0, "ready_to_apply": 0, "insufficient": 521},
"cclasstrib_applicability": {"state": "NOT_APPLICABLE", "basis": "SIMPLES_CCLASSTRIB_NOT_EFFECTIVE"},
}})
assert result["enabled"] is True
assert result["products"]["applicable"] is False
assert result["products"]["label"] == "cClassTrib: Não utilizado neste cliente"
assert "pendente" not in result["products"].get("headline", "").lower()
+56 -10
View File
@@ -29,17 +29,17 @@ def test_rtc_off_ignores_cclasstrib_completely():
def test_rtc_on_requires_and_validates_cclasstrib():
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, ON)) == {"CCLASSTRIB_MISSING"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "12x"}, SIMPLES, ON)) == {"CCLASSTRIB_INVALID_FORMAT"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "123456"}, SIMPLES, ON)) == {"CCLASSTRIB_NOT_IN_CATALOG"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "999999"}, SIMPLES, ON)) == {"RTC_CST_MISSING"} # class without CST
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "555555"}, SIMPLES, ON)) == {"RTC_CST_MISSING"} # class points to a CST that is not in RTC_CST (orphan)
ok = evaluate_product({**EMPTY, "CCLASSTRIB": "200003"}, SIMPLES, ON)
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, NORMAL, ON)) == {"CCLASSTRIB_MISSING"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "12x"}, NORMAL, ON)) == {"CCLASSTRIB_INVALID_FORMAT"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "123456"}, NORMAL, ON)) == {"CCLASSTRIB_NOT_IN_CATALOG"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "999999"}, NORMAL, ON)) == {"RTC_CST_MISSING"} # class without CST
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": "555555"}, NORMAL, ON)) == {"RTC_CST_MISSING"} # class points to a CST that is not in RTC_CST (orphan)
ok = evaluate_product({**EMPTY, "CCLASSTRIB": "200003"}, NORMAL, ON)
assert ok["blockers"] == [] and ok["applicability"]["RTC"] == "REQUIRED" and "CCLASSTRIB" in ok["mandatory_fields"]
def test_rtc_on_with_invalid_catalog_blocks_with_a_single_clear_reason():
r = evaluate_product({**EMPTY, "CCLASSTRIB": "200003"}, SIMPLES, {"enabled": True, "catalog": CATALOG, "catalog_valid": False})
r = evaluate_product({**EMPTY, "CCLASSTRIB": "200003"}, NORMAL, {"enabled": True, "catalog": CATALOG, "catalog_valid": False})
assert kinds(r) == {"RTC_CATALOG_INVALID"}
@@ -54,13 +54,59 @@ def test_rtc_enabled_needs_schema_and_erp_switch():
assert rtc_enabled(caps) and not rtc_enabled({**caps, "RTC_ENABLED_BY_PARAM": False}) and not rtc_enabled({**caps, "HAS_RTC_RELATIONSHIP": False}) and not rtc_enabled({})
def test_cclasstrib_is_not_applicable_for_simples_before_its_effective_date_even_when_rtc_is_on():
result = evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, ON, date(2026, 9, 25))
assert result["applicability"]["RTC"] == "NOT_APPLICABLE"
assert result["basis"]["RTC"] == "SIMPLES_CCLASSTRIB_NOT_EFFECTIVE"
assert "CCLASSTRIB" not in result["mandatory_fields"]
assert not [blocker for blocker in result["blockers"] if blocker["category"] == "RTC"]
def test_not_applicable_cclasstrib_ignores_any_existing_value():
for value in (None, "", "12x", "999999", "200003"):
result = evaluate_product({**EMPTY, "CCLASSTRIB": value}, SIMPLES, ON, date(2026, 9, 25))
assert result["applicability"]["RTC"] == "NOT_APPLICABLE"
assert "CCLASSTRIB" not in result["mandatory_fields"]
assert not [blocker for blocker in result["blockers"] if blocker["category"] == "RTC"]
def test_cclasstrib_becomes_applicable_on_each_regime_effective_date():
for crt in ("1", "2", "4"):
before = evaluate_product({**EMPTY, "CCLASSTRIB": None}, {"crt": crt}, ON, date(2026, 12, 31))
effective = evaluate_product({**EMPTY, "CCLASSTRIB": None}, {"crt": crt}, ON, date(2027, 1, 1))
assert before["applicability"]["RTC"] == "NOT_APPLICABLE"
assert "CCLASSTRIB_MISSING" in kinds(effective)
normal_before = evaluate_product({**EMPTY, "CCLASSTRIB": None}, NORMAL, ON, date(2026, 8, 2))
normal_effective = evaluate_product({**EMPTY, "CCLASSTRIB": None}, NORMAL, ON, date(2026, 8, 3))
assert normal_before["applicability"]["RTC"] == "NOT_APPLICABLE"
assert "CCLASSTRIB_MISSING" in kinds(normal_effective)
def test_cclasstrib_is_not_applicable_when_company_regime_is_unresolved():
for company in (None, {"crt": None}, {"crt": "9"}):
result = evaluate_product({**EMPTY, "CCLASSTRIB": None}, company, ON, date(2026, 9, 25))
assert result["applicability"]["RTC"] == "NOT_APPLICABLE"
assert not [blocker for blocker in result["blockers"] if blocker["category"] == "RTC"]
def test_non_applicable_cclasstrib_does_not_mask_other_fiscal_blockers():
product = {**EMPTY, "CCLASSTRIB": None, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA"}
result = evaluate_product(product, SIMPLES, ON, date(2026, 9, 25))
assert kinds(result) == {"PIS_CST_MISSING", "COFINS_CST_MISSING"}
def test_legal_context_is_informational_and_never_creates_a_blocker():
simples, normal = legal_effective_context("1"), legal_effective_context("3")
assert simples["informational_only"] and simples["ibs_cbs_in_documents"] == "MANDATORY_FROM_2027-01-01" and normal["ibs_cbs_in_documents"] == "MANDATORY_FROM_2026-08-03"
assert simples["cclasstrib_orientation"] == "PENDING_OFFICIAL_NT" and any("Ato Conjunto RFB/CGIBS n 4/2026" in x for x in simples["sources"])
assert legal_effective_context(None)["ibs_cbs_in_documents"] == "UNKNOWN_REGIME"
# the operational rule is the ERP switch only: a Simples company with RTC on is validated, one with RTC off is not, whatever the legal timing says
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, ON)) == {"CCLASSTRIB_MISSING"} and kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, OFF)) == set()
# Global RTC support does not make Simples cClassTrib mandatory before its effective date.
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, ON, date(2026, 9, 25))) == set()
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, NORMAL, ON, date(2026, 9, 25))) == {"CCLASSTRIB_MISSING"}
assert kinds(evaluate_product({**EMPTY, "CCLASSTRIB": None}, SIMPLES, OFF, date(2026, 9, 25))) == set()
# ---------------------------------------------------------------- PIS / COFINS applicability is NOT circular
@@ -184,7 +230,7 @@ def test_unified_coverage_invariant_and_rtc_toggle_changes_only_rtc_products():
for s in (off, on):
assert s["TOTAL_PRODUCTS"] == s["COMPLETE_PRODUCTS"] + s["SAFE_BLOCKED"] + s["FAILED_TECHNICAL"] + s["UNCLASSIFIED"] == 4
assert off["COMPLETE_PRODUCTS"] == 2 and off["BLOCKED_FISCAL_DATA"] == 1 and off["UNCLASSIFIED"] == 1 # RTC off: cClassTrib never counts
assert on["COMPLETE_PRODUCTS"] == 1 and on["BLOCKED_FISCAL_DATA"] == 3 and on["UNCLASSIFIED"] == 0 # RTC on: only product 3 has a valid cClassTrib; a real blocker outranks NEEDS_REVIEW
assert on["COMPLETE_PRODUCTS"] == 2 and on["BLOCKED_FISCAL_DATA"] == 1 and on["UNCLASSIFIED"] == 1 # RTC on, but Simples cClassTrib is not effective yet
def test_fiscal_blockers_never_hide_or_override_a_decision_blocker():