File size: 2,907 Bytes
78f194c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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