feat(bloco-c): motor fiscal com legal_basis obrigatorio, classificacao NCM, seguranca CEST/IPI e validador GTIN
This commit is contained in:
@@ -108,9 +108,28 @@ def _digits(v):
|
||||
return "".join(c for c in str(v or "") if c.isdigit())
|
||||
|
||||
|
||||
def _r(field, state, current, proposed=None, reason="", key=None, scope=None, **extra):
|
||||
def _default_legal_basis(field, value):
|
||||
contract = CONTRACT.get(field, {})
|
||||
src = contract.get("SOURCE_OF_TRUTH", "")
|
||||
prov = contract.get("PROVENANCE", "")
|
||||
val_str = str(value or "")
|
||||
if field == "CLASSIFICACAO_FISCAL":
|
||||
return {"dataset": "NCM", "version": "Siscomex", "line": val_str, "act": "Resolução Gecex / MDIC"}
|
||||
elif field in ("IPI", "EX_TIPI"):
|
||||
return {"dataset": "TIPI_IPI", "version": "tipi-xlsx-v1", "line": val_str, "act": "Decreto nº 11.158/2022"}
|
||||
elif field == "CEST":
|
||||
return {"dataset": "CEST", "version": "CV142_18", "line": val_str, "act": "Convênio ICMS 142/18"}
|
||||
elif "CFOP" in field:
|
||||
return {"dataset": "CFOP", "version": "cfop-xlsx-v1", "line": val_str, "act": "Informe Técnico 2023.002"}
|
||||
elif field in ("CST", "CST_ENTRADA", "CSOSN", "CST_IPI", "COD_ENTRADA_PIS", "COD_SAIDA_PIS", "COD_ENTRADA_COFINS", "COD_SAIDA_COFINS", "COD_ORIGEM_MERCADORIA"):
|
||||
return {"dataset": "NFE_MOC_TABLES", "version": "moc7-tables-v1", "line": val_str, "act": "MOC 7.0 Anexo I"}
|
||||
return {"dataset": "ERP_EVIDENCE", "version": "C000025", "line": val_str, "act": prov or src}
|
||||
|
||||
|
||||
def _r(field, state, current, proposed=None, reason="", key=None, scope=None, legal_basis=None, **extra):
|
||||
basis = legal_basis if legal_basis is not None else _default_legal_basis(field, proposed if proposed is not None else current)
|
||||
return {"field": field, "state": state, "current": current, "proposed": proposed, "reason": reason, "input_key": key, "input_scope": scope,
|
||||
"write_eligible": state == CHANGE and CONTRACT[field]["WRITE_ALLOWED"], **extra}
|
||||
"write_eligible": state == CHANGE and CONTRACT[field]["WRITE_ALLOWED"], "legal_basis": basis, **extra}
|
||||
|
||||
|
||||
# C000032.TIPO=COMPOSICAO evidence must be a deterministic MAJORITY of that product's own movement
|
||||
@@ -221,10 +240,24 @@ def resolve_product(p, d, company, refs, ev, ctx, manual_ncm=None):
|
||||
else:
|
||||
out["CLASSIFICACAO_FISCAL"] = _r("CLASSIFICACAO_FISCAL", CHANGE, cur["CLASSIFICACAO_FISCAL"], _digits(val), reason="OPERATOR_NCM_VALIDATED_BY_NCM_DATASET")
|
||||
elif ncm_ok:
|
||||
out["CLASSIFICACAO_FISCAL"] = _r("CLASSIFICACAO_FISCAL", ALREADY, cur["CLASSIFICACAO_FISCAL"], reason="NCM_VALID_IN_DATASET")
|
||||
out["CLASSIFICACAO_FISCAL"] = _r("CLASSIFICACAO_FISCAL", ALREADY, cur["CLASSIFICACAO_FISCAL"], reason="NCM_VALID_IN_DATASET",
|
||||
legal_basis={"dataset": "NCM", "version": refs.get("ncm_version") or "Siscomex", "line": cur["CLASSIFICACAO_FISCAL"], "act": "Resolução Gecex / MDIC"})
|
||||
else:
|
||||
why = "NCM_MISSING" if _blank(cur["CLASSIFICACAO_FISCAL"]) else ("NCM_LEGACY_NO_UNAMBIGUOUS_SUCCESSOR" if d.get("status") == "LEGACY_NCM" else "NCM_INVALID")
|
||||
out["CLASSIFICACAO_FISCAL"] = _r("CLASSIFICACAO_FISCAL", MANUAL, cur["CLASSIFICACAO_FISCAL"], reason=why, key="ncm", scope="PRODUCT")
|
||||
st_val = d.get("status")
|
||||
if _blank(cur["CLASSIFICACAO_FISCAL"]):
|
||||
why = "NCM_MISSING"
|
||||
elif st_val == "PLACEHOLDER_NCM":
|
||||
why = "NCM_PLACEHOLDER"
|
||||
elif st_val == "INVALID_FORMAT_NCM":
|
||||
why = "NCM_INVALID_FORMAT"
|
||||
elif st_val in ("LEGACY_NCM", "EXPIRED_LEGACY_NCM"):
|
||||
why = "NCM_LEGACY_NO_UNAMBIGUOUS_SUCCESSOR"
|
||||
elif st_val == "OUT_OF_TABLE_NCM":
|
||||
why = "NCM_OUT_OF_OFFICIAL_TABLE"
|
||||
else:
|
||||
why = "NCM_INVALID"
|
||||
out["CLASSIFICACAO_FISCAL"] = _r("CLASSIFICACAO_FISCAL", MANUAL, cur["CLASSIFICACAO_FISCAL"], reason=why, key="ncm", scope="PRODUCT",
|
||||
legal_basis={"dataset": "NCM", "version": refs.get("ncm_version") or "Siscomex", "line": cur["CLASSIFICACAO_FISCAL"], "act": "Resolução Gecex / MDIC"})
|
||||
|
||||
def blocked(field):
|
||||
return _r(field, MANUAL, cur[field], reason="BLOCKED_BY_NCM", key="ncm", scope="PRODUCT")
|
||||
@@ -281,12 +314,16 @@ def resolve_product(p, d, company, refs, ev, ctx, manual_ncm=None):
|
||||
choices=[{"ex": c.get("ex"), "rate": c.get("rate"), "description": c.get("description")} for c in cands])
|
||||
else:
|
||||
out["IPI"] = _r("IPI", NA, cur["IPI"], reason=("TIPI_RATE_BLANK_NEVER_ZERO" if "BLANK" in r["reason_code"] or "NO_DATA" in r["reason_code"] else "TIPI_NT_OR_NON_NUMERIC_NEVER_WRITTEN_TO_NUMERIC_FIELD"))
|
||||
# store_ipi_profile: whether the retailer's product cadastre stores the TIPI reference rate is a company policy the operator must decide
|
||||
if out["IPI"]["state"] == CHANGE:
|
||||
prof, _ = ctx.get("store_ipi_profile", code, group)
|
||||
# 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)"})
|
||||
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":
|
||||
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")]
|
||||
@@ -321,8 +358,15 @@ def resolve_product(p, d, company, refs, ev, ctx, manual_ncm=None):
|
||||
else:
|
||||
out["CEST"] = _r("CEST", MANUAL, cur["CEST"], reason="OPERATOR_CEST_NOT_OFFICIAL_FOR_NCM", key="cest", scope="PRODUCT")
|
||||
elif cs == "CEST_CONFIRMED":
|
||||
proposed = _digits((cls.get("cest") or [None])[0])
|
||||
out["CEST"] = _r("CEST", ALREADY if cur_cest == proposed else CHANGE, cur["CEST"], None if cur_cest == proposed else proposed, "SINGLE_DEFENSIBLE_OFFICIAL_CEST")
|
||||
cests_mapped = cls.get("cest") or []
|
||||
if len(cests_mapped) <= 1:
|
||||
proposed = _digits(cests_mapped[0] if cests_mapped else (cls.get("cest") or [None])[0])
|
||||
out["CEST"] = _r("CEST", ALREADY if cur_cest == proposed else CHANGE, cur["CEST"], None if cur_cest == proposed else proposed, "SINGLE_DEFENSIBLE_OFFICIAL_CEST",
|
||||
legal_basis={"dataset": "CEST", "version": refs.get("cest", "CV142_18"), "line": proposed, "act": "Convênio ICMS 142/18"})
|
||||
else:
|
||||
out["CEST"] = _r("CEST", MANUAL, cur["CEST"], reason="SEVERAL_OFFICIAL_CEST_FOR_NCM", key="cest", scope="PRODUCT",
|
||||
choices=[{"code": v["code"], "description": v["official_description"], "score": v.get("description_score")} for v in official.values()],
|
||||
legal_basis={"dataset": "CEST", "version": refs.get("cest", "CV142_18"), "line": "MULTIPLE_CANDIDATES", "act": "Convênio ICMS 142/18"})
|
||||
elif cur_cest and cur_cest in official:
|
||||
out["CEST"] = _r("CEST", ALREADY, cur["CEST"], reason="ERP_CEST_IS_OFFICIAL_FOR_NCM")
|
||||
elif cs == "NO_CEST_MAPPING_FOUND":
|
||||
|
||||
Reference in New Issue
Block a user