Files

110 lines
3.5 KiB
Python
Raw Permalink Normal View History

"""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 (0100 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 0100, 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"