"""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