mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-10-05 20:01:58 +00:00
Add discount settings and two-tier pricing to order aggregation
Settings CRUD (get_settings/put_settings) for DynamoDB CONFIG#SETTINGS item. Aggregation now tracks bulk_price and employee_price separately, with grand_total (company cost) and employee_total (payroll deductions).
This commit is contained in:
parent
a8adbdc116
commit
e6bef44a74
4 changed files with 53 additions and 9 deletions
|
|
@ -1,8 +1,11 @@
|
||||||
{
|
{
|
||||||
"menu_url": "https://redefinemeals.com/menu",
|
"menu_url": "https://redefinemeals.com/menu",
|
||||||
"order_deadline": "Wednesday 11:59 PM",
|
"order_deadline": "Thursday at 11:59 PM",
|
||||||
"output_dir": "output",
|
"output_dir": "output",
|
||||||
"orders_dir": "orders",
|
"orders_dir": "orders",
|
||||||
|
"bulk_discount_percent": 10,
|
||||||
|
"company_subsidy_percent": 50,
|
||||||
|
"google_client_id": "",
|
||||||
"roster": [
|
"roster": [
|
||||||
{"name": "Example Employee", "email": "example@seahavenind.com"}
|
{"name": "Example Employee", "email": "example@seahavenind.com"}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,18 @@ def lambda_handler(event, context):
|
||||||
|
|
||||||
|
|
||||||
def build_summary(orders: list[dict], week: str) -> dict:
|
def build_summary(orders: list[dict], week: str) -> dict:
|
||||||
meal_totals = defaultdict(lambda: {"quantity": 0, "unit_price": 0})
|
meal_totals = defaultdict(
|
||||||
|
lambda: {"quantity": 0, "bulk_price": 0, "employee_price": 0}
|
||||||
|
)
|
||||||
for order in orders:
|
for order in orders:
|
||||||
for item in order.get("items", []):
|
for item in order.get("items", []):
|
||||||
name = item["name"]
|
name = item["name"]
|
||||||
qty = int(item.get("quantity", 0))
|
qty = int(item.get("quantity", 0))
|
||||||
meal_totals[name]["quantity"] += qty
|
meal_totals[name]["quantity"] += qty
|
||||||
meal_totals[name]["unit_price"] = float(item.get("price", 0))
|
meal_totals[name]["bulk_price"] = float(
|
||||||
|
item.get("bulk_price", item.get("price", 0))
|
||||||
|
)
|
||||||
|
meal_totals[name]["employee_price"] = float(item.get("price", 0))
|
||||||
|
|
||||||
meals = []
|
meals = []
|
||||||
for name, data in sorted(meal_totals.items()):
|
for name, data in sorted(meal_totals.items()):
|
||||||
|
|
@ -79,8 +84,12 @@ def build_summary(orders: list[dict], week: str) -> dict:
|
||||||
{
|
{
|
||||||
"meal": name,
|
"meal": name,
|
||||||
"quantity": data["quantity"],
|
"quantity": data["quantity"],
|
||||||
"unit_price": data["unit_price"],
|
"unit_price": data["bulk_price"],
|
||||||
"line_total": round(data["unit_price"] * data["quantity"], 2),
|
"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
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -90,6 +99,7 @@ def build_summary(orders: list[dict], week: str) -> dict:
|
||||||
"total_employees": len(orders),
|
"total_employees": len(orders),
|
||||||
"total_meals": sum(m["quantity"] for m in meals),
|
"total_meals": sum(m["quantity"] for m in meals),
|
||||||
"grand_total": round(sum(m["line_total"] for m in meals), 2),
|
"grand_total": round(sum(m["line_total"] for m in meals), 2),
|
||||||
|
"employee_total": round(sum(m["employee_line_total"] for m in meals), 2),
|
||||||
"meals": meals,
|
"meals": meals,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,17 @@ def load_orders(week: str) -> list[dict]:
|
||||||
|
|
||||||
def generate_order_summary(orders: list[dict]) -> dict:
|
def generate_order_summary(orders: list[dict]) -> dict:
|
||||||
"""Aggregate all meals across employees into a single order for Redefine."""
|
"""Aggregate all meals across employees into a single order for Redefine."""
|
||||||
meal_totals = defaultdict(lambda: {"quantity": 0, "unit_price": 0})
|
meal_totals = defaultdict(
|
||||||
|
lambda: {"quantity": 0, "bulk_price": 0, "employee_price": 0}
|
||||||
|
)
|
||||||
for order in orders:
|
for order in orders:
|
||||||
for item in order.get("items", []):
|
for item in order.get("items", []):
|
||||||
name = item["name"]
|
name = item["name"]
|
||||||
meal_totals[name]["quantity"] += item.get("quantity", 0)
|
meal_totals[name]["quantity"] += item.get("quantity", 0)
|
||||||
meal_totals[name]["unit_price"] = item.get("price", 0)
|
meal_totals[name]["bulk_price"] = item.get(
|
||||||
|
"bulk_price", item.get("price", 0)
|
||||||
|
)
|
||||||
|
meal_totals[name]["employee_price"] = item.get("price", 0)
|
||||||
|
|
||||||
summary = []
|
summary = []
|
||||||
for name, data in sorted(meal_totals.items()):
|
for name, data in sorted(meal_totals.items()):
|
||||||
|
|
@ -54,12 +59,17 @@ def generate_order_summary(orders: list[dict]) -> dict:
|
||||||
{
|
{
|
||||||
"meal": name,
|
"meal": name,
|
||||||
"quantity": data["quantity"],
|
"quantity": data["quantity"],
|
||||||
"unit_price": data["unit_price"],
|
"unit_price": data["bulk_price"],
|
||||||
"line_total": round(data["unit_price"] * data["quantity"], 2),
|
"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)
|
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)
|
total_meals = sum(s["quantity"] for s in summary)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -68,6 +78,7 @@ def generate_order_summary(orders: list[dict]) -> dict:
|
||||||
"total_employees": len(orders),
|
"total_employees": len(orders),
|
||||||
"total_meals": total_meals,
|
"total_meals": total_meals,
|
||||||
"grand_total": round(grand_total, 2),
|
"grand_total": round(grand_total, 2),
|
||||||
|
"employee_total": round(employee_total, 2),
|
||||||
"meals": summary,
|
"meals": summary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,6 +161,10 @@ def main():
|
||||||
print(f"{meal['meal']:<45} {meal['quantity']:>4} ${meal['line_total']:>7.2f}")
|
print(f"{meal['meal']:<45} {meal['quantity']:>4} ${meal['line_total']:>7.2f}")
|
||||||
print("-" * 60)
|
print("-" * 60)
|
||||||
print(f"{'TOTAL':<45} {summary['total_meals']:>4} ${summary['grand_total']:>7.2f}")
|
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(f"\n{summary['total_employees']} employees ordered")
|
||||||
|
|
||||||
print("\nFiles generated:")
|
print("\nFiles generated:")
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,19 @@ def put_roster(employees: list[dict]):
|
||||||
"updated_at": datetime.now(EASTERN).isoformat(),
|
"updated_at": datetime.now(EASTERN).isoformat(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_settings() -> dict:
|
||||||
|
resp = _get_table().get_item(Key={"PK": "CONFIG", "SK": "SETTINGS"})
|
||||||
|
return resp.get("Item", {})
|
||||||
|
|
||||||
|
|
||||||
|
def put_settings(settings: dict):
|
||||||
|
_get_table().put_item(
|
||||||
|
Item={
|
||||||
|
"PK": "CONFIG",
|
||||||
|
"SK": "SETTINGS",
|
||||||
|
**_to_decimal(settings),
|
||||||
|
"updated_at": datetime.now(EASTERN).isoformat(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue