""" Order aggregation script. Reads all submitted orders for a given week and produces: 1. Order summary — total quantity of each meal (for submitting to Redefine Meals) 2. Payroll deduction report — CSV with employee name, email, itemized meals, total amount """ import csv import json import sys from collections import defaultdict from datetime import datetime from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] CONFIG_PATH = PROJECT_ROOT / "config.json" ORDERS_DIR = PROJECT_ROOT / "orders" OUTPUT_DIR = PROJECT_ROOT / "output" def load_config(): with open(CONFIG_PATH) as f: return json.load(f) def current_week() -> str: return datetime.now().strftime("%Y-W%U") def load_orders(week: str) -> list[dict]: week_dir = ORDERS_DIR / week if not week_dir.exists(): return [] orders = [] for f in sorted(week_dir.glob("*.json")): with open(f) as fh: orders.append(json.load(fh)) return orders def generate_order_summary(orders: list[dict]) -> dict: """Aggregate all meals across employees into a single order for Redefine.""" meal_totals = defaultdict( lambda: {"quantity": 0, "bulk_price": 0, "employee_price": 0} ) for order in orders: for item in order.get("items", []): name = item["name"] meal_totals[name]["quantity"] += item.get("quantity", 0) meal_totals[name]["bulk_price"] = item.get( "bulk_price", item.get("price", 0) ) meal_totals[name]["employee_price"] = item.get("price", 0) summary = [] for name, data in sorted(meal_totals.items()): summary.append( { "meal": name, "quantity": data["quantity"], "unit_price": data["bulk_price"], "employee_unit_price": data["employee_price"], "line_total": round(data["bulk_price"] * data["quantity"], 2), "employee_line_total": round( data["employee_price"] * data["quantity"], 2 ), } ) grand_total = sum(s["line_total"] for s in summary) employee_total = sum(s["employee_line_total"] for s in summary) total_meals = sum(s["quantity"] for s in summary) return { "week": orders[0]["week"] if orders else "", "generated_at": datetime.now().isoformat(), "total_employees": len(orders), "total_meals": total_meals, "grand_total": round(grand_total, 2), "employee_total": round(employee_total, 2), "meals": summary, } def generate_payroll_csv(orders: list[dict], output_path: Path): """Write a CSV for payroll with one row per employee.""" with open(output_path, "w", newline="") as f: writer = csv.writer(f) writer.writerow( ["Employee Name", "Employee Email", "Items Ordered", "Total Deduction"] ) for order in sorted(orders, key=lambda o: o["employee_name"]): items_str = "; ".join( f"{item['name']} x{item['quantity']} (${item['subtotal']:.2f})" for item in order.get("items", []) ) writer.writerow( [ order["employee_name"], order["employee_email"], items_str, f"${order['total']:.2f}", ] ) def generate_order_summary_csv(summary: dict, output_path: Path): """Write a CSV of the aggregated order for submitting to Redefine.""" with open(output_path, "w", newline="") as f: writer = csv.writer(f) writer.writerow(["Meal", "Quantity", "Unit Price", "Line Total"]) for meal in summary["meals"]: writer.writerow( [ meal["meal"], meal["quantity"], f"${meal['unit_price']:.2f}", f"${meal['line_total']:.2f}", ] ) writer.writerow([]) writer.writerow( ["TOTAL", summary["total_meals"], "", f"${summary['grand_total']:.2f}"] ) def main(): week = sys.argv[1] if len(sys.argv) > 1 else current_week() orders = load_orders(week) if not orders: print(f"No orders found for week {week}") print(f" Expected directory: {ORDERS_DIR / week}") sys.exit(1) print(f"Processing {len(orders)} orders for week {week}") summary = generate_order_summary(orders) OUTPUT_DIR.mkdir(exist_ok=True) # Save order summary summary_json = OUTPUT_DIR / f"order-summary-{week}.json" with open(summary_json, "w") as f: json.dump(summary, f, indent=2) summary_csv = OUTPUT_DIR / f"order-summary-{week}.csv" generate_order_summary_csv(summary, summary_csv) # Save payroll report payroll_csv = OUTPUT_DIR / f"payroll-deductions-{week}.csv" generate_payroll_csv(orders, payroll_csv) # Print summary print(f"\n{'=' * 60}") print(f"ORDER SUMMARY — Week {week}") print(f"{'=' * 60}") print(f"{'Meal':<45} {'Qty':>4} {'Total':>8}") print("-" * 60) for meal in summary["meals"]: print(f"{meal['meal']:<45} {meal['quantity']:>4} ${meal['line_total']:>7.2f}") print("-" * 60) print(f"{'TOTAL':<45} {summary['total_meals']:>4} ${summary['grand_total']:>7.2f}") if ( summary.get("employee_total") is not None and summary["employee_total"] != summary["grand_total"] ): print(f"{'PAYROLL DEDUCTIONS':<45} ${summary['employee_total']:>7.2f}") subsidy = round(summary["grand_total"] - summary["employee_total"], 2) print(f"{'COMPANY SUBSIDY':<45} ${subsidy:>7.2f}") print(f"\n{summary['total_employees']} employees ordered") print("\nFiles generated:") print(f" Order summary: {summary_csv}") print(f" Payroll report: {payroll_csv}") print(f" Raw JSON: {summary_json}") if __name__ == "__main__": main()