74 lines
3.5 KiB
Python
74 lines
3.5 KiB
Python
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
|