Spaces:
No application file
No application file
import pandas as pd | |
import numpy as np | |
from config import WEIGHTS | |
REQUIRED_COLS = [ | |
"Name of Product", | |
"Components Used", | |
"Quantity of Each Component", | |
"Oldest Product Required First", | |
"Priority Assigned", | |
] | |
def _normalize_columns(df: pd.DataFrame) -> pd.DataFrame: | |
df = df.copy() | |
df.columns = [str(c).strip() for c in df.columns] | |
return df | |
def _component_count(series: pd.Series) -> pd.Series: | |
def _count(x): | |
if pd.isna(x): | |
return 0 | |
parts = [p.strip() for p in str(x).split(",") if str(p).strip()] | |
return len(set(parts)) if parts else 0 | |
return series.apply(_count) | |
def compute_priority(df: pd.DataFrame, min_qty: int = 50) -> pd.DataFrame: | |
df = _normalize_columns(df) | |
missing = [c for c in REQUIRED_COLS if c not in df.columns] | |
if missing: | |
raise ValueError(f"Missing required columns: {missing}") | |
out = df.copy() | |
out["Oldest Product Required First"] = pd.to_datetime(out["Oldest Product Required First"], errors="coerce") | |
today = pd.Timestamp.now().normalize() | |
out["OrderAgeDays"] = (today - pd.to_datetime(out["Oldest Product Required First"], errors="coerce")).dt.days | |
out["OrderAgeDays"] = out["OrderAgeDays"].fillna(0).clip(lower=0) | |
if out["OrderAgeDays"].max() > 0: | |
age_score_01 = out["OrderAgeDays"] / out["OrderAgeDays"].max() | |
else: | |
age_score_01 = 0 | |
qty = pd.to_numeric(out["Quantity of Each Component"], errors="coerce").fillna(0) | |
age_score_01 = np.where(qty >= min_qty, age_score_01, 0) | |
comp_count = _component_count(out["Components Used"]) | |
if comp_count.max() > 0: | |
comp_simplicity_01 = 1 - (comp_count / comp_count.max()) | |
else: | |
comp_simplicity_01 = 0 | |
def manual_to01(x): | |
if pd.isna(x): | |
return 0.0 | |
s = str(x).strip().lower() | |
if s in {"high", "urgent", "yes", "y", "true"}: | |
return 1.0 | |
try: | |
return 1.0 if float(s) > 0 else 0.0 | |
except: | |
return 0.0 | |
manual_01 = out["Priority Assigned"].apply(manual_to01) | |
w_age = WEIGHTS["AGE_WEIGHT"] / 100.0 | |
w_comp = WEIGHTS["COMPONENT_WEIGHT"] / 100.0 | |
w_man = WEIGHTS["MANUAL_WEIGHT"] / 100.0 | |
out["AgeScore"] = age_score_01 * w_age | |
if isinstance(comp_simplicity_01, pd.Series): | |
out["SimplicityScore"] = comp_simplicity_01 * w_comp | |
else: | |
out["SimplicityScore"] = comp_simplicity_01 | |
out["ManualScore"] = manual_01 * w_man | |
out["PriorityScore"] = out["AgeScore"] + out["SimplicityScore"] + out["ManualScore"] | |
out["ComponentCount"] = comp_count | |
out["QtyThresholdOK"] = qty >= min_qty | |
out = out.sort_values(["PriorityScore", "OrderAgeDays"], ascending=[False, False]) | |
return out |