loopable / platform /modules /vendor.py
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
c14ceee verified
Raw
History Blame Contribute Delete
2.05 kB
"""Vendor module β€” per-vendor rollup + the multiple-vendor / cheapest-price view.
PURE: it takes the procurement recs (which already merge the curated supplier map + live Odoo
demand/stock + Odoo's alternative vendors via product.supplierinfo) and groups them by vendor, so
there is NO extra Odoo round-trip β€” the Procurement page and this page share one cached pull. Vendor
master-data edits (country / lead) persist through the procurement overrides store, applied to every
SKU of that vendor (the UI does the bulk write). READ-ONLY on Odoo.
"""
def rollup(recs):
"""[{vendor, country, lead, n_skus, n_buy, demand_units, buy_value, lines}], by SKU count desc."""
out = {}
for r in recs:
v = r.get('vendor') or '(no supplier)'
g = out.setdefault(v, {'vendor': v, 'country': r.get('country', ''), 'lead': r.get('lead', 0),
'n_skus': 0, 'n_buy': 0, 'demand_units': 0.0, 'buy_value': 0.0, 'lines': []})
g['n_skus'] += 1
if r.get('buy'):
g['n_buy'] += 1
g['demand_units'] += (r.get('demand_8m') or 0)
g['buy_value'] += (r.get('reorder_trend') or 0) * (r.get('unit_cost') or 0)
g['lines'].append(r)
if not g['country'] and r.get('country'):
g['country'] = r['country']
if not g['lead'] and r.get('lead'):
g['lead'] = r['lead']
return sorted(out.values(), key=lambda x: (-x['n_skus'], x['vendor'] or '~'))
def multi_vendor(recs):
"""SKUs Odoo lists with >1 vendor β€” current vendor/cost vs the cheapest alternative (price-shop)."""
out = []
for r in recs:
if (r.get('n_vendors') or 0) <= 1:
continue
cur = r.get('unit_cost') or 0
cheapest = r.get('cheapest_price')
cheaper = bool(cheapest is not None and cur > 0 and cheapest < cur - 1e-9)
out.append({**r, 'current_cost': cur,
'savings': (cur - cheapest) if cheaper else 0.0, 'cheaper': cheaper})
out.sort(key=lambda r: -r['savings'])
return out