Files

71 lines
2.3 KiB
Python

"""Supplier scoring.
Weighted score (0-100):
40% price — cheaper supplier cost vs. the eligible pool
20% inventory — stock sufficiency for the requested qty
15% speed — shipping_time ('3-5 days' -> avg days)
10% fulfillment — supplier_performance.fulfillment_rate
10% returns — inverse of supplier_performance.return_rate
5% history — reliability_score blended with stock_accuracy
"""
import re
def _num(value, default=0.0):
try:
return float(value or 0)
except (TypeError, ValueError):
return default
def _shipping_days(sp):
text = (sp.shipping_time or "").strip()
numbers = re.findall(r"\d+", text)
if not numbers:
return 5.0
return float(sum(int(n) for n in numbers)) / len(numbers)
def score_supplier(db, supplier, sp, qty, price_pool=None):
perf = supplier.performance
# 1) price (40%) — cheaper than pool average is better
cost = _num(sp.supplier_cost)
if price_pool and price_pool.get("avg_cost"):
avg = price_pool["avg_cost"]
price_score = max(0.0, 100.0 - (cost / avg - 1.0) * 100.0)
else:
price_score = 50.0
# 2) inventory (20%) — can we fill the quantity?
inventory = int(sp.supplier_inventory or 0)
inv_score = 100.0 if inventory >= qty else max(0.0, (inventory / qty) * 100.0)
# 3) speed (15%) — fewer shipping days is better
days = _shipping_days(sp)
speed_score = max(0.0, 100.0 - days * 12.0)
# 4) fulfillment (10%)
fulfillment = 100.0 if perf is None else _num(perf.fulfillment_rate, 100.0)
# 5) returns (10%) — 0% returns = 100 points, 20% returns = 0 points
return_rate = 0.0 if perf is None else _num(perf.return_rate, 0.0)
returns_score = max(0.0, 100.0 - return_rate * 5.0)
# 6) history (5%) — reliability blended with stock accuracy
reliability = _num(supplier.reliability_score, 50.0)
if perf is None:
history_score = reliability
else:
history_score = 0.5 * reliability + 0.5 * _num(perf.stock_accuracy, 100.0)
total = (
0.40 * price_score
+ 0.20 * inv_score
+ 0.15 * speed_score
+ 0.10 * fulfillment
+ 0.10 * returns_score
+ 0.05 * history_score
)
return round(min(100.0, max(0.0, total)), 2)