"""Halal meat sales opportunity scoring for export market entities.""" from __future__ import annotations import json import re from typing import Any # Land-basis: vraag naar halal vlees / moslim markt (0–100 proxy) COUNTRY_HALAL_MARKET: dict[str, float] = { "SA": 98, "AE": 97, "QA": 97, "KW": 96, "BH": 96, "OM": 95, "EG": 92, "MA": 90, "DZ": 90, "TN": 89, "LY": 88, "SD": 91, "SO": 93, "TR": 85, "ID": 94, "MY": 93, "PK": 95, "BD": 94, "AF": 96, "IR": 94, "IQ": 93, "JO": 90, "LB": 88, "SY": 89, "YE": 95, "PS": 91, "NG": 82, "SN": 92, "ML": 93, "NE": 95, "BF": 90, "CI": 85, "GH": 78, "KE": 72, "TZ": 78, "UG": 70, "ET": 68, "ZA": 55, "GB": 52, "FR": 54, "DE": 50, "NL": 58, "BE": 56, "SE": 42, "NO": 38, "DK": 40, "FI": 35, "AT": 48, "CH": 45, "IT": 46, "ES": 48, "PT": 42, "GR": 45, "CY": 55, "BA": 82, "AL": 85, "XK": 88, "MK": 75, "RS": 72, "BG": 58, "RO": 55, "US": 45, "CA": 48, "AU": 38, "NZ": 35, "MX": 40, "BR": 42, "AR": 38, "SG": 72, "TH": 55, "PH": 65, "IN": 70, "CN": 35, "JP": 30, "KR": 32, "RU": 48, "KZ": 62, "UZ": 75, "AZ": 80, "GE": 55, } TYPE_BASE: dict[str, float] = { "butcher": 92, "doner_shoarma": 90, "wholesaler": 86, "distributor": 85, "importer": 84, "contract_caterer": 78, "restaurant": 72, "foodservice": 65, "logistics": 45, } HALAL_KEYWORDS = re.compile( r"halal|helal|kebab|döner|doner|shoarma|shawarma|moslim|muslim|islamic|" r"middle\s*east|turkish|türk|arab|pakistani|moroccan|marok|syrian|lebanese|" r"peri\s*peri|grill|bbq|meat|vlees|slager|butcher|wholesale|groothandel|" r"cash\s*&\s*carry|horeca|ethnic|kosher", re.I, ) EXPLICIT_HALAL = re.compile(r"\bhalal\b|\bhelal\b", re.I) def _product_interest_text(val: Any) -> str: if not val: return "" if isinstance(val, str): try: val = json.loads(val) except json.JSONDecodeError: return val if isinstance(val, list): return " ".join(str(x) for x in val) return str(val) def score_entity(row: dict[str, Any]) -> tuple[float, list[str]]: """Return (score 0–100, reason tags).""" reasons: list[str] = [] country = (row.get("country_iso2") or "").upper() etype = row.get("entity_type") or "" name = row.get("name") or "" notes = row.get("halal_cert_notes") or "" interest = _product_interest_text(row.get("product_interest")) score = TYPE_BASE.get(etype, 50) reasons.append(f"type:{etype}") market = COUNTRY_HALAL_MARKET.get(country, 40) score = score * 0.55 + market * 0.45 if market >= 80: reasons.append("sterke_halal_markt") blob = f"{name} {notes} {interest}".lower() if EXPLICIT_HALAL.search(blob): score += 18 reasons.append("halal_in_naam") elif HALAL_KEYWORDS.search(blob): score += 10 reasons.append("halal_signaal") if etype in ("butcher", "doner_shoarma"): reasons.append("direct_vlees_kanaal") elif etype in ("wholesaler", "distributor", "importer"): reasons.append("B2B_kanaal") conf = int(row.get("confidence") or 50) score += (conf - 50) * 0.08 if row.get("email") or row.get("contact_email"): score += 3 if int(row.get("contact_count") or 0) > 0: score += 4 reasons.append("heeft_contact") return round(min(100, max(0, score)), 1), reasons def halal_pin_tier(score: float) -> str: if score >= 75: return "hot" if score >= 55: return "warm" if score >= 40: return "mild" return "low"