git-subtree-dir: fiscal git-subtree-mainline:d95165fc8fgit-subtree-split:102ba84500
241 lines
16 KiB
Python
241 lines
16 KiB
Python
from datetime import date
|
|
|
|
from central.app.operational_state import classify_product_state, summarize_operational_states
|
|
from central.app.unified_fiscal_coverage import (blocker_category, canonical_cst, evaluate_product, incidence_kind, legal_effective_context, pis_cofins_applicability, rtc_enabled,
|
|
validate_cclasstrib, validate_cst)
|
|
|
|
CATALOG = {"classes": {"000001": "000", "200003": "200", "410004": "410", "999999": None, "555555": "555"}, "cst": {"000", "200", "410"}, "duplicates": 0}
|
|
ON = {"enabled": True, "catalog": CATALOG, "catalog_valid": True}
|
|
OFF = {"enabled": False, "catalog": CATALOG, "catalog_valid": True}
|
|
SIMPLES, NORMAL = {"crt": "1"}, {"crt": "3"}
|
|
EMPTY = {"CODIGO": "1", "PISCOFINS": "N", "INCIDENCIA_PISCOFINS": "NENHUMA"}
|
|
FIELDS = ("COD_ENTRADA_PIS", "COD_SAIDA_PIS", "ALIQ_PIS", "COD_ENTRADA_COFINS", "COD_SAIDA_COFINS", "ALIQ_COFINS")
|
|
|
|
|
|
def kinds(result):
|
|
return {b["type"] for b in result["blockers"]}
|
|
|
|
|
|
def warns(result):
|
|
return {w["type"] for w in result["warnings"]}
|
|
|
|
|
|
# ---------------------------------------------------------------- RTC on / off
|
|
def test_rtc_off_ignores_cclasstrib_completely():
|
|
for value in (None, "", "12x", "999999", "000001"):
|
|
r = evaluate_product({**EMPTY, "CCLASSTRIB": value}, SIMPLES, OFF)
|
|
assert r["blockers"] == [] and r["applicability"]["RTC"] == "NOT_APPLICABLE" and "CCLASSTRIB" not in r["mandatory_fields"]
|
|
assert evaluate_product(EMPTY, SIMPLES, None)["blockers"] == []
|
|
|
|
|
|
def test_rtc_on_requires_and_validates_cclasstrib():
|
|
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"}, NORMAL, {"enabled": True, "catalog": CATALOG, "catalog_valid": False})
|
|
assert kinds(r) == {"RTC_CATALOG_INVALID"}
|
|
|
|
|
|
def test_rtc_vigencia_is_used_only_when_the_catalog_carries_it():
|
|
cat = {**CATALOG, "validity": {"200003": (date(2027, 1, 1), None), "410004": (date(2025, 1, 1), date(2025, 12, 31))}}
|
|
assert validate_cclasstrib("200003", cat, date(2026, 9, 24)) == "EXPIRED" and validate_cclasstrib("410004", cat, date(2026, 9, 24)) == "EXPIRED"
|
|
assert validate_cclasstrib("000001", cat, date(2026, 9, 24)) == "VALID" and validate_cclasstrib("200003", CATALOG, date(2026, 9, 24)) == "VALID"
|
|
|
|
|
|
def test_rtc_enabled_needs_schema_and_erp_switch():
|
|
caps = {"HAS_PRODUCT_CCLASSTRIB": True, "HAS_RTC_RELATIONSHIP": True, "RTC_ENABLED_BY_PARAM": True}
|
|
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"
|
|
# 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
|
|
def test_applicability_never_depends_on_whether_the_six_fields_are_empty():
|
|
typed = {f: "49" if "COD" in f else "0" for f in FIELDS}
|
|
for crt in ("1", "2", "4", "3", None):
|
|
for base in (EMPTY, {"CODIGO": "1", "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA"}, {"CODIGO": "1", "PISCOFINS": "", "INCIDENCIA_PISCOFINS": ""}):
|
|
empty_state = pis_cofins_applicability(base, crt)
|
|
filled_state = pis_cofins_applicability({**base, **typed}, crt)
|
|
assert empty_state == filled_state, (crt, base) # same verdict with the fields empty or typed: emptiness proves nothing
|
|
|
|
|
|
def test_empty_fields_with_applicable_context_is_a_missing_blocker():
|
|
for crt in ("1", "3"):
|
|
r = evaluate_product({**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA"}, {"crt": crt}, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "REQUIRED" and kinds(r) == {"PIS_CST_MISSING", "COFINS_CST_MISSING"}
|
|
|
|
|
|
def test_empty_fields_with_provably_not_applicable_context_is_not_applicable():
|
|
for crt in ("1", "2", "4"):
|
|
r = evaluate_product(EMPTY, {"crt": crt}, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "NOT_APPLICABLE" and r["basis"]["PIS_COFINS"] == "SIMPLES_DAS_NO_SPECIAL_TREATMENT" and r["blockers"] == [] and not r["needs_review"]
|
|
assert evaluate_product({"CODIGO": "1"}, SIMPLES, OFF)["blockers"] == [] # columns absent in an old schema, Simples: nothing to require
|
|
|
|
|
|
def test_empty_fields_with_insufficient_context_need_review_and_never_default_to_complete():
|
|
for company in (NORMAL, {"crt": None}, None):
|
|
r = evaluate_product({"CODIGO": "1", "PISCOFINS": "", "INCIDENCIA_PISCOFINS": ""}, company, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "NEEDS_REVIEW" and r["needs_review"] and r["blockers"] == []
|
|
state = classify_product_state({"CODIGO": "1"}, {"status": "EXACT_NCM"}, fiscal=r)["state"]
|
|
assert state == "NEEDS_REVIEW" # counted as UNCLASSIFIED, never inflating coverage
|
|
|
|
|
|
def test_taxed_regime_with_explicit_no_special_treatment_is_optional_and_typed_values_must_be_valid():
|
|
r = evaluate_product(EMPTY, NORMAL, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "OPTIONAL" and r["blockers"] == []
|
|
assert kinds(evaluate_product({**EMPTY, "COD_SAIDA_PIS": "2x"}, NORMAL, OFF)) == {"PIS_CST_INVALID"}
|
|
|
|
|
|
def test_unknown_incidence_text_needs_review_in_every_regime():
|
|
for crt in ("1", "3"):
|
|
r = evaluate_product({**EMPTY, "INCIDENCIA_PISCOFINS": "OUTRA COISA"}, {"crt": crt}, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "NEEDS_REVIEW" and r["needs_review"] and r["blockers"] == []
|
|
|
|
|
|
def test_simples_typed_garbage_is_ignored_as_a_warning_not_a_blocker():
|
|
row = {**EMPTY, "COD_ENTRADA_PIS": "2", "COD_SAIDA_PIS": "2", "ALIQ_PIS": "2", "COD_ENTRADA_COFINS": "2", "COD_SAIDA_COFINS": "2", "ALIQ_COFINS": "2"}
|
|
r = evaluate_product(row, SIMPLES, OFF)
|
|
assert r["applicability"]["PIS_COFINS"] == "NOT_APPLICABLE" and r["blockers"] == []
|
|
assert warns(r) == {"CST_PIS_NON_CANONICAL_FORMAT", "CST_COFINS_NON_CANONICAL_FORMAT"} # "2" is one digit of official "02": normalisable
|
|
bad = evaluate_product({**EMPTY, "COD_ENTRADA_COFINS": "000", "COD_SAIDA_COFINS": "060"}, SIMPLES, OFF)
|
|
assert bad["blockers"] == [] and warns(bad) == {"CST_COFINS_INVALID_IGNORED"}
|
|
|
|
|
|
# ---------------------------------------------------------------- CST normalisation
|
|
def test_canonical_cst_accepts_only_one_digit_with_an_official_zero_padded_form():
|
|
assert canonical_cst("4") == "04" and canonical_cst("04") == "04" and canonical_cst(" 4 ") == "04" and canonical_cst("9") == "09" and canonical_cst("1") == "01"
|
|
for text in ("0", "049", "000", "060", "2x", "x", "", None, "10", "12", "00"):
|
|
assert canonical_cst(text) is None, text
|
|
assert validate_cst("4") == "VALID_AFTER_NORMALIZATION" and validate_cst("04") == "VALID" and validate_cst("049") == "INVALID" and validate_cst("") == "EMPTY"
|
|
|
|
|
|
def test_unpadded_cst_is_semantically_valid_warns_and_is_used_canonically_for_the_rules():
|
|
row = {**EMPTY, "COD_SAIDA_PIS": "4", "COD_SAIDA_COFINS": "4"}
|
|
r = evaluate_product(row, NORMAL, OFF)
|
|
assert r["blockers"] == [] and warns(r) == {"CST_PIS_NON_CANONICAL_FORMAT", "CST_COFINS_NON_CANONICAL_FORMAT"}
|
|
mono = {**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA", "COD_SAIDA_PIS": "4", "COD_SAIDA_COFINS": "4"}
|
|
assert kinds(evaluate_product(mono, NORMAL, OFF)) == set() # "4" -> "04" is compatible with MONOFASICA
|
|
assert kinds(evaluate_product({**mono, "COD_SAIDA_PIS": "1", "ALIQ_PIS": "1,65"}, NORMAL, OFF)) == {"PIS_CST_INCIDENCE_MISMATCH"} # "1" -> "01" is not
|
|
assert kinds(evaluate_product({**EMPTY, "COD_SAIDA_PIS": "049"}, NORMAL, OFF)) == {"PIS_CST_INVALID"} # ambiguous: still a blocker
|
|
|
|
|
|
# ---------------------------------------------------------------- PIS / COFINS rules
|
|
def test_declared_monophasic_product_requires_a_valid_exit_cst():
|
|
good = {**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA", "COD_SAIDA_PIS": "04", "COD_SAIDA_COFINS": "04"}
|
|
r = evaluate_product(good, SIMPLES, OFF)
|
|
assert r["blockers"] == [] and r["applicability"]["PIS_COFINS"] == "REQUIRED" and set(r["mandatory_fields"]) == {"COD_SAIDA_PIS", "COD_SAIDA_COFINS"}
|
|
assert kinds(evaluate_product({**good, "COD_SAIDA_PIS": None}, SIMPLES, OFF)) == {"PIS_CST_MISSING"}
|
|
assert kinds(evaluate_product({**good, "COD_SAIDA_COFINS": "01", "ALIQ_COFINS": "7,6"}, SIMPLES, OFF)) == {"COFINS_CST_INCIDENCE_MISMATCH"}
|
|
|
|
|
|
def test_st_incidence_with_taxable_cst_is_a_mismatch_and_pis_cofins_are_independent():
|
|
row = {**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "SUBST.TRIBUTÁRIA", "COD_ENTRADA_PIS": "73", "COD_SAIDA_PIS": "01", "ALIQ_PIS": "0,65", "COD_ENTRADA_COFINS": "73", "COD_SAIDA_COFINS": "05"}
|
|
assert kinds(evaluate_product(row, NORMAL, OFF)) == {"PIS_CST_INCIDENCE_MISMATCH"} # only PIS is wrong; COFINS 05 is right
|
|
|
|
|
|
def test_rate_rules_follow_the_cst():
|
|
base = {**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "NENHUMA"}
|
|
assert kinds(evaluate_product({**base, "COD_SAIDA_PIS": "01", "COD_SAIDA_COFINS": "01"}, NORMAL, OFF)) == {"PIS_RATE_MISSING", "COFINS_RATE_MISSING"}
|
|
assert kinds(evaluate_product({**base, "COD_SAIDA_PIS": "01", "ALIQ_PIS": "1,65", "COD_SAIDA_COFINS": "01", "ALIQ_COFINS": "7,6"}, NORMAL, OFF)) == set()
|
|
assert kinds(evaluate_product({**base, "COD_SAIDA_PIS": "49", "COD_SAIDA_COFINS": "49"}, SIMPLES, OFF)) == set()
|
|
assert kinds(evaluate_product({**base, "COD_SAIDA_PIS": "49", "ALIQ_PIS": "abc", "COD_SAIDA_COFINS": "49"}, SIMPLES, OFF)) == {"PIS_RATE_INVALID"}
|
|
assert kinds(evaluate_product({**base, "COD_SAIDA_PIS": "49", "ALIQ_PIS": "150", "COD_SAIDA_COFINS": "49"}, SIMPLES, OFF)) == {"PIS_RATE_INVALID"}
|
|
|
|
|
|
def test_inconsistent_flags():
|
|
assert "PIS_COFINS_FLAG_INCONSISTENT" in kinds(evaluate_product({**EMPTY, "PISCOFINS": "N", "INCIDENCIA_PISCOFINS": "MONOFÁSICA", "COD_SAIDA_PIS": "04", "COD_SAIDA_COFINS": "04"}, SIMPLES, OFF))
|
|
assert "PIS_COFINS_FLAG_INCONSISTENT" in kinds(evaluate_product({**EMPTY, "PISCOFINS": "S"}, SIMPLES, OFF))
|
|
|
|
|
|
def test_incidence_text_is_encoding_and_accent_tolerant():
|
|
for text in ("MONOFÁSICA", "MONOFASICA", "MONOF�SICA", "monofásica"):
|
|
assert incidence_kind(text) == "MONOFASICA"
|
|
assert incidence_kind("SUBST.TRIBUTÁRIA") == "SUBSTITUICAO" and incidence_kind(None) == "NONE" and incidence_kind(" nenhuma ") == "NONE" and incidence_kind("???") == "UNKNOWN"
|
|
|
|
|
|
# ---------------------------------------------------------------- ONE definition of complete, ONE queue
|
|
def test_blocker_categories_feed_the_single_dashboard_breakdown():
|
|
assert {blocker_category(t) for t in ("PIS_CST_INVALID", "PIS_COFINS_FLAG_INCONSISTENT")} == {"PIS"} and blocker_category("COFINS_RATE_MISSING") == "COFINS"
|
|
assert {blocker_category(t) for t in ("CCLASSTRIB_MISSING", "RTC_CST_MISSING", "RTC_CATALOG_INVALID")} == {"RTC"} and blocker_category("XYZ") == "OTHER"
|
|
|
|
|
|
def test_unified_coverage_invariant_and_rtc_toggle_changes_only_rtc_products():
|
|
products = [{**EMPTY, "CODIGO": "1"}, {**EMPTY, "CODIGO": "2", "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA"}, {**EMPTY, "CODIGO": "3", "CCLASSTRIB": "200003"},
|
|
{**EMPTY, "CODIGO": "4", "INCIDENCIA_PISCOFINS": "???"}]
|
|
|
|
def run(rtc):
|
|
states = [classify_product_state(p, {"status": "EXACT_NCM"}, fiscal=evaluate_product(p, SIMPLES, rtc)) for p in products]
|
|
return summarize_operational_states(states)
|
|
off, on = run(OFF), run(ON)
|
|
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"] == 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():
|
|
fiscal = evaluate_product({**EMPTY, "PISCOFINS": "S", "INCIDENCIA_PISCOFINS": "MONOFÁSICA"}, SIMPLES, OFF)
|
|
state = classify_product_state({"CODIGO": "1"}, {"status": "INVALID_NCM"}, fiscal=fiscal)
|
|
assert state["state"] == "BLOCKED_MISSING_EVIDENCE" # the NCM blocker stays the primary state
|
|
assert classify_product_state({"CODIGO": "1"}, {"status": "EXACT_NCM"}, fiscal=None)["state"] == "COMPLETE"
|