"""Estimation engine: trade rollup + preliminaries + contingency.""" from collections import defaultdict CONTINGENCY = 0.05 PRELIMINARIES = 0.08 # site establishment etc., reference only def estimate(rows): trades = defaultdict(lambda: {"qty": 0.0, "amount": 0.0, "count": 0}) total = 0.0 for r in rows: qty, rate = r.get("qty") or 0, r.get("rate") or 0 amt = qty * rate section = r.get("section") or "Unallocated" if not section.strip(): section = "Unallocated" trades[section]["qty"] += qty trades[section]["amount"] += amt trades[section]["count"] += 1 total += amt prelim = total * PRELIMINARIES contingency_amt = (total + prelim) * CONTINGENCY grand = total + prelim + contingency_amt return { "trades": {k: {"amount": v["amount"], "count": v["count"]} for k, v in trades.items()}, "items_total": total, "preliminaries": prelim, "contingency": contingency_amt, "grand_total": grand, "confidence": "Reference-based estimate; treat as a screening figure (+-20%), not a tender price.", }