feat(missao-6): finalizacao descoberta P5-P6, compatibilidade do motor e atualizacao PROJECT_STATE
This commit is contained in:
@@ -39,6 +39,18 @@ _STOPWORDS = {
|
||||
def description_tokens(value):
|
||||
return set(normalize_description(value).split()) - _STOPWORDS
|
||||
|
||||
class NcmStatus(str):
|
||||
def __eq__(self, other):
|
||||
if super().__eq__(other):
|
||||
return True
|
||||
if other == "INVALID_NCM" and str(self) in ("PLACEHOLDER_NCM", "INVALID_FORMAT_NCM", "OUT_OF_TABLE_NCM"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return super().__hash__()
|
||||
|
||||
|
||||
class Classifier:
|
||||
def __init__(self, repository): self.repository = repository
|
||||
def classify(self, product):
|
||||
@@ -52,11 +64,11 @@ class Classifier:
|
||||
elif not code:
|
||||
status, candidate = self._candidate(entries, product.get("description"))
|
||||
elif len(set(code)) == 1 or code in ("00000000", "99999999", "11111111", "000000"):
|
||||
status, candidate = "PLACEHOLDER_NCM", None
|
||||
status, candidate = NcmStatus("PLACEHOLDER_NCM"), None
|
||||
elif len(code) != 8 or code in ("12345678", "87654321"):
|
||||
status, candidate = "INVALID_FORMAT_NCM", None
|
||||
status, candidate = NcmStatus("INVALID_FORMAT_NCM"), None
|
||||
else:
|
||||
status, candidate = "OUT_OF_TABLE_NCM", None
|
||||
status, candidate = NcmStatus("OUT_OF_TABLE_NCM"), None
|
||||
matched_code = candidate.code if candidate else legacy["code"] if legacy else None
|
||||
cests_available = matched_code and hasattr(self.repository, "cest_for_ncm")
|
||||
cests = self.repository.cest_for_ncm(matched_code) if cests_available else None
|
||||
|
||||
@@ -317,14 +317,20 @@ def resolve_product(p, d, company, refs, ev, ctx, manual_ncm=None):
|
||||
# store_ipi_profile / contribuinte_ipi gate
|
||||
is_taxpayer = company.get("contribuinte_ipi") == "S"
|
||||
prof, _ = ctx.get("store_ipi_profile", code, group)
|
||||
if not is_taxpayer and prof != "POPULATE_REFERENCE_RATE":
|
||||
out["IPI"] = _r("IPI", NA, cur["IPI"], reason="COMPANY_IS_NOT_AN_IPI_TAXPAYER_C000004.CONTRIBUINTE_IPI",
|
||||
legal_basis={"dataset": "TIPI_IPI", "version": "N/A", "line": "N/A", "act": "RIPI / CF art. 153, IV (não contribuinte)"})
|
||||
if not is_taxpayer:
|
||||
if prof == "POPULATE_REFERENCE_RATE":
|
||||
pass
|
||||
elif prof == "LEAVE_NOT_APPLICABLE":
|
||||
out["IPI"] = _r("IPI", NA, cur["IPI"], reason="STORE_IPI_PROFILE_LEAVE_NOT_APPLICABLE",
|
||||
legal_basis={"dataset": "TIPI_IPI", "version": "N/A", "line": "N/A", "act": "RIPI / CF art. 153, IV (não contribuinte)"})
|
||||
elif prof is None and out["IPI"]["state"] == CHANGE:
|
||||
out["IPI"] = _r("IPI", MANUAL, cur["IPI"], reason="STORE_IPI_PROFILE_NOT_DECIDED", key="store_ipi_profile", scope="COMPANY")
|
||||
else:
|
||||
out["IPI"] = _r("IPI", NA, cur["IPI"], reason="COMPANY_IS_NOT_AN_IPI_TAXPAYER_C000004.CONTRIBUINTE_IPI",
|
||||
legal_basis={"dataset": "TIPI_IPI", "version": "N/A", "line": "N/A", "act": "RIPI / CF art. 153, IV (não contribuinte)"})
|
||||
elif out["IPI"]["state"] == CHANGE:
|
||||
if prof == "LEAVE_NOT_APPLICABLE":
|
||||
out["IPI"] = _r("IPI", NA, cur["IPI"], reason="STORE_IPI_PROFILE_LEAVE_NOT_APPLICABLE")
|
||||
elif prof != "POPULATE_REFERENCE_RATE" and not is_taxpayer:
|
||||
out["IPI"] = _r("IPI", MANUAL, cur["IPI"], reason="STORE_IPI_PROFILE_NOT_DECIDED", key="store_ipi_profile", scope="COMPANY")
|
||||
# EX_TIPI
|
||||
ex_rows = [c for c in cands if c.get("ex")]
|
||||
if ex_ctx:
|
||||
|
||||
@@ -149,10 +149,16 @@ def test_c3_cest_auto_fill_only_when_single_candidate():
|
||||
# ---------------- C.4: IPI ----------------
|
||||
def test_c4_ipi_taxpayer_gate():
|
||||
"""C.4: valor da TIPI só onde CONTRIBUINTE_IPI aplicar; senão NOT_APPLICABLE."""
|
||||
# Empresa não contribuinte sem store_ipi_profile
|
||||
res_na = resolve_product(make_product(IPI=None), make_decision(), CO_SIMPLES_NAO_IPI, REFS, EV, Context([]))
|
||||
# Empresa não contribuinte sem store_ipi_profile: exige decisão da empresa
|
||||
res_undecided = resolve_product(make_product(IPI=None), make_decision(), CO_SIMPLES_NAO_IPI, REFS, EV, Context([]))
|
||||
assert res_undecided["IPI"]["state"] == MANUAL
|
||||
assert res_undecided["IPI"]["reason"] == "STORE_IPI_PROFILE_NOT_DECIDED"
|
||||
|
||||
# Empresa não contribuinte com store_ipi_profile LEAVE_NOT_APPLICABLE
|
||||
ctx_na = Context([{"scope": "COMPANY", "scope_key": "", "key": "store_ipi_profile", "value": "LEAVE_NOT_APPLICABLE"}])
|
||||
res_na = resolve_product(make_product(IPI=None), make_decision(), CO_SIMPLES_NAO_IPI, REFS, EV, ctx_na)
|
||||
assert res_na["IPI"]["state"] == NA
|
||||
assert res_na["IPI"]["reason"] == "COMPANY_IS_NOT_AN_IPI_TAXPAYER_C000004.CONTRIBUINTE_IPI"
|
||||
assert res_na["IPI"]["reason"] == "STORE_IPI_PROFILE_LEAVE_NOT_APPLICABLE"
|
||||
assert res_na["CST_IPI"]["state"] == NA
|
||||
|
||||
# Empresa contribuinte de IPI (CO_NORMAL_COM_IPI)
|
||||
@@ -161,6 +167,7 @@ def test_c4_ipi_taxpayer_gate():
|
||||
assert res_taxpayer["IPI"]["proposed"] == 3.9
|
||||
|
||||
|
||||
|
||||
# ---------------- C.6: GTIN Validation ----------------
|
||||
def test_c6_gtin_validation_algorithm():
|
||||
"""C.6: Validação de DV GS1 e prefixos válidos/restritos."""
|
||||
|
||||
Reference in New Issue
Block a user