"""Read-only fiscal coverage report for a set of products (used by the Agent's REPROCESS_ALL result and by the multi-database tooling). Pure computation over Hub decisions + product rows + local evidence. It reuses the shipped pure engines in central.app (fiscal_decision, product_defaults, icms_context) — no fiscal rule lives here, only guards for the company context: the BA Anexo 1 ST/MVA dataset is applied to UF=BA only and CSOSN logic only under CRT=1. """ from collections import Counter PRODUCT_COLUMNS = ("CODIGO", "PRODUTO", "CLASSIFICACAO_FISCAL", "CFOP", "CSOSN", "CST", "CEST", "IPI", "EX_TIPI", "TIPO", "PROD_COZINHA", "PRODUTO_SERVICO", "SITUACAO_TRIBUTARIA") def _s(v): return None if v is None else str(v).strip() def compute_coverage(products, decisions, company, company_default, refs, evidence): """products/decisions aligned lists. company: {"uf","crt"} (resolved). evidence: {"recipes","composed","purchases","stock_entry"}.""" from central.app.fiscal_decision import decide_product from central.app.icms_context import csosn_v2, product_role, st_status, withheld_status from central.app.product_defaults import cfop_default uf_ba = company.get("uf") == "BA" crt1 = company.get("crt") == "1" recipes, composed = evidence.get("recipes", set()), evidence.get("composed", set()) purchases, stock_entry = evidence.get("purchases", {}), evidence.get("stock_entry", {}) m, cfop_values, situ = Counter(), Counter(), Counter() for p, d in zip(products, decisions): p = {c: p.get(c) for c in PRODUCT_COLUMNS} code = _s(p["CODIGO"]); p["CODIGO"] = code cls = d.get("classification") or {} rec = decide_product(p, d, {"uf": company.get("uf") or "", "crt": company.get("crt") or ""}, refs) ncm_status = d.get("status"); raw_ncm = _s(p["CLASSIFICACAO_FISCAL"]) m["NCM_MISSING" if not raw_ncm else ("NCM_VALID" if ncm_status == "EXACT_NCM" else ("NCM_LEGACY" if ncm_status == "LEGACY_NCM" else "NCM_INVALID"))] += 1 ipi = rec["IPI"]; rk = (cls.get("ipi") or {}).get("rate_kind"); ist = d.get("ipi_status") if ist == "IPI_RESOLVED": m[{"NUMERIC": "IPI_NUMERIC", "NON_NUMERIC": "IPI_NON_NUMERIC", "BLANK": "IPI_SOURCE_BLANK"}.get(rk, "IPI_NO_MATCH")] += 1 elif ist == "IPI_CANDIDATES": m["IPI_AMBIGUOUS"] += 1 elif ist != "LEGACY_NCM" and raw_ncm: m["IPI_NO_MATCH"] += 1 if ipi["action_class"] == "ALREADY_CORRECT": m["IPI_ALREADY_CORRECT"] += 1 if ipi["write_eligible"]: m["IPI_CHANGE_REQUIRED"] += 1; m["IPI_WRITE_ELIGIBLE"] += 1 cs_ = d.get("cest_status") if cs_ == "CEST_CONFIRMED": m["CEST_CONFIRMED"] += 1 elif cs_ == "CEST_CANDIDATES": m["CEST_CANDIDATES"] += 1 cf = cfop_default(p, ncm_status, d.get("ba_st_mva_status") if uf_ba else None, refs["cfop_valid"]) cfop_values[_s(p["CFOP"])] += 1 m["CFOP_RESOLVED" if cf["status"] == "CFOP_DEFAULT_RESOLVED" else "CFOP_CONTEXT_REQUIRED"] += 1 ba = cls.get("ba_st_mva") or {} if uf_ba: st, _ = st_status(ncm_status, d.get("ba_st_mva_status"), cs_, p["CEST"], ba.get("cest"), None) else: st = "ST_UNKNOWN" m[st] += 1 wh, _ = withheld_status(purchases.get(code, [])) m[{"ST_ALREADY_WITHHELD_CONFIRMED": "ST_WITHHOLDING_CONFIRMED", "ST_ALREADY_WITHHELD_NOT_CONFIRMED": "ST_WITHHOLDING_NOT_CONFIRMED"}.get(wh, "ST_WITHHOLDING_UNKNOWN")] += 1 role, _ = product_role(p["TIPO"], p["PROD_COZINHA"] == 1, code in recipes, code in composed, bool(_s(p["PRODUTO_SERVICO"])), bool(purchases.get(code)) or stock_entry.get(code, False)) m["PRODUCT_ROLE_KNOWN" if role != "UNKNOWN" else "PRODUCT_ROLE_UNKNOWN"] += 1 m["ROLE_" + role] += 1 state = csosn_v2(p["CSOSN"], company_default, ncm_status, st if uf_ba else "ST_UNKNOWN", wh, role, refs["csosn"])["status"] if crt1 else "CSOSN_CONTEXT_REQUIRED" m["CSOSN_RESOLVED" if state == "CSOSN_RESOLVED" else ("CSOSN_CANDIDATES" if state == "CSOSN_CANDIDATE" else "CSOSN_CONTEXT_REQUIRED")] += 1 situ[_s(p["SITUACAO_TRIBUTARIA"])] += 1 n = len(products) fill = lambda f: sum(1 for p in products if _s(p.get(f)) not in (None, "")) # noqa: E731 return {"TOTAL_PRODUCTS": n, "metrics": dict(m), "IPI_RESOLVED": m["IPI_NUMERIC"] + m["IPI_NON_NUMERIC"] + m["IPI_SOURCE_BLANK"], "quality": {"ncm_valid_share": round(m["NCM_VALID"] / n, 4) if n else None, "cest_filled": fill("CEST"), "csosn_filled": fill("CSOSN"), "cfop_filled": fill("CFOP"), "ipi_filled": fill("IPI"), "cfop_distinct": len(cfop_values), "cfop_top": cfop_values.most_common(6), "situacao_tributaria": dict(situ.most_common(6)), "purchase_items_C000088": sum(len(v) for v in purchases.values()), "products_with_purchase_evidence": len(purchases), "recipes": len(recipes), "composed_products": len(composed)}, "guards_applied": {"st_dataset_ba_only": not uf_ba, "csosn_requires_crt1": not crt1}} def build_refs(get, products, company_uf): """Reference-data snapshot from the Hub (`get(path) -> json`). Used by the engines for domain validity only.""" refs = {} for key, domain in (("csosn", "CSOSN"), ("cst_icms", "CST_ICMS"), ("cst_pis", "CST_PIS"), ("cst_cofins", "CST_COFINS"), ("origem", "ORIGEM_MERCADORIA")): refs[key] = set(get(f"/v1/reference/fiscal_codes/{domain}")["codes"]) valid = set() for code in {_s(p.get(f)) for p in products for f in ("CFOP", "CFOP_ENTRADA") if _s(p.get(f))}: if get(f"/v1/reference/cfop/{code}")["found"]: valid.add(code) refs["cfop_valid"] = valid refs["fcp_uf"] = {} fcp = get(f"/v1/reference/fcp/{company_uf}") if fcp.get("found"): refs["fcp_uf"][company_uf] = fcp refs["cbs_rate_2026"] = get("/v1/reference/rtc_cbs_rate/2026").get("rate") refs["cclasstrib_count"] = sum(d["record_count"] for d in get("/v1/datasets/status") if d["kind"] == "RTC_CCLASSTRIB" and d["status"] == "ACTIVE") return refs