mirror of
https://github.com/sstent/foodplanner.git
synced 2025-12-06 08:01:47 +00:00
270 lines
11 KiB
Python
270 lines
11 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Request, Form, Body
|
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
from sqlalchemy.orm import Session, joinedload
|
|
from datetime import date, datetime, timedelta
|
|
import logging
|
|
from typing import List, Optional
|
|
|
|
# Import from the database module
|
|
from app.database import get_db, Meal, Template, WeeklyMenu, WeeklyMenuDay, WeeklyMenuDetail, WeeklyMenuDayDetail, Plan
|
|
from main import templates
|
|
|
|
router = APIRouter()
|
|
|
|
#Weekly Menu tab
|
|
@router.get("/weeklymenu", response_class=HTMLResponse)
|
|
async def weekly_menu_page(request: Request, db: Session = Depends(get_db)):
|
|
weekly_menus = db.query(WeeklyMenu).all()
|
|
templates_list = db.query(Template).all()
|
|
|
|
# Convert WeeklyMenu objects to dictionaries for JSON serialization
|
|
weekly_menus_data = []
|
|
for wm in weekly_menus:
|
|
wm_dict = {
|
|
"id": wm.id,
|
|
"name": wm.name,
|
|
"weekly_menu_days": []
|
|
}
|
|
for wmd in wm.weekly_menu_days:
|
|
wm_dict["weekly_menu_days"].append({
|
|
"day_of_week": wmd.day_of_week,
|
|
"template_id": wmd.template_id,
|
|
"template_name": wmd.template.name if wmd.template else "Unknown"
|
|
})
|
|
weekly_menus_data.append(wm_dict)
|
|
|
|
logging.info(f"DEBUG: Loading weekly menu page with {len(weekly_menus_data)} weekly menus")
|
|
|
|
return templates.TemplateResponse("weeklymenu.html", {
|
|
"request": request,
|
|
"weekly_menus": weekly_menus_data,
|
|
"templates": templates_list
|
|
})
|
|
|
|
@router.get("/api/weeklymenus", response_model=List[WeeklyMenuDetail])
|
|
async def get_weekly_menus_api(db: Session = Depends(get_db)):
|
|
"""API endpoint to get all weekly menus with template details."""
|
|
weekly_menus = db.query(WeeklyMenu).options(joinedload(WeeklyMenu.weekly_menu_days).joinedload(WeeklyMenuDay.template)).all()
|
|
|
|
results = []
|
|
for wm in weekly_menus:
|
|
day_details = [
|
|
WeeklyMenuDayDetail(
|
|
day_of_week=wmd.day_of_week,
|
|
template_id=wmd.template_id,
|
|
template_name=wmd.template.name if wmd.template else "Unknown"
|
|
) for wmd in wm.weekly_menu_days
|
|
]
|
|
results.append(WeeklyMenuDetail(
|
|
id=wm.id,
|
|
name=wm.name,
|
|
weekly_menu_days=day_details
|
|
))
|
|
return results
|
|
|
|
|
|
@router.get("/weeklymenu/{weekly_menu_id}", response_model=WeeklyMenuDetail)
|
|
async def get_weekly_menu_detail(weekly_menu_id: int, db: Session = Depends(get_db)):
|
|
"""API endpoint to get a specific weekly menu with template details."""
|
|
weekly_menu = db.query(WeeklyMenu).options(joinedload(WeeklyMenu.weekly_menu_days).joinedload(WeeklyMenuDay.template)).filter(WeeklyMenu.id == weekly_menu_id).first()
|
|
|
|
if not weekly_menu:
|
|
raise HTTPException(status_code=404, detail="Weekly menu not found")
|
|
|
|
day_details = [
|
|
WeeklyMenuDayDetail(
|
|
day_of_week=wmd.day_of_week,
|
|
template_id=wmd.template_id,
|
|
template_name=wmd.template.name if wmd.template else "Unknown"
|
|
) for wmd in weekly_menu.weekly_menu_days
|
|
]
|
|
return WeeklyMenuDetail(
|
|
id=weekly_menu.id,
|
|
name=weekly_menu.name,
|
|
weekly_menu_days=day_details
|
|
)
|
|
|
|
@router.post("/weeklymenu/create")
|
|
async def create_weekly_menu(request: Request, db: Session = Depends(get_db)):
|
|
"""Create a new weekly menu with template assignments."""
|
|
try:
|
|
form_data = await request.form()
|
|
name = form_data.get("name")
|
|
template_assignments_str = form_data.get("template_assignments")
|
|
|
|
if not name:
|
|
return {"status": "error", "message": "Weekly menu name is required"}
|
|
|
|
# Check if weekly menu already exists
|
|
existing_weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.name == name).first()
|
|
if existing_weekly_menu:
|
|
return {"status": "error", "message": f"Weekly menu with name '{name}' already exists"}
|
|
|
|
weekly_menu = WeeklyMenu(name=name)
|
|
db.add(weekly_menu)
|
|
db.flush() # To get the weekly_menu.id
|
|
|
|
if template_assignments_str:
|
|
assignments = template_assignments_str.split(',')
|
|
for assignment in assignments:
|
|
day_of_week_str, template_id_str = assignment.split(':', 1)
|
|
day_of_week = int(day_of_week_str)
|
|
template_id = int(template_id_str)
|
|
|
|
# Check if template exists
|
|
template = db.query(Template).filter(Template.id == template_id).first()
|
|
if not template:
|
|
raise HTTPException(status_code=400, detail=f"Template with ID {template_id} not found.")
|
|
|
|
weekly_menu_day = WeeklyMenuDay(
|
|
weekly_menu_id=weekly_menu.id,
|
|
day_of_week=day_of_week,
|
|
template_id=template_id
|
|
)
|
|
db.add(weekly_menu_day)
|
|
|
|
db.commit()
|
|
return {"status": "success", "message": "Weekly menu created successfully"}
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
logging.error(f"Error creating weekly menu: {e}")
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
@router.post("/weeklymenu/{weekly_menu_id}/apply")
|
|
async def apply_weekly_menu(weekly_menu_id: int, request: Request, db: Session = Depends(get_db)):
|
|
"""Apply a weekly menu to a person's plan for a specific week."""
|
|
try:
|
|
from datetime import datetime, timedelta
|
|
form_data = await request.form()
|
|
person = form_data.get("person")
|
|
week_start_date_str = form_data.get("week_start_date")
|
|
confirm_overwrite = form_data.get("confirm_overwrite") == "true"
|
|
|
|
if not person or not week_start_date_str:
|
|
return {"status": "error", "message": "Person and week start date are required."}
|
|
|
|
week_start_date = datetime.fromisoformat(week_start_date_str).date()
|
|
|
|
weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.id == weekly_menu_id).first()
|
|
if not weekly_menu:
|
|
return {"status": "error", "message": "Weekly menu not found."}
|
|
|
|
# Check if there are existing plans for the target week
|
|
existing_plans = db.query(Plan).filter(
|
|
Plan.person == person,
|
|
Plan.date >= week_start_date,
|
|
Plan.date < (week_start_date + timedelta(days=7))
|
|
).all()
|
|
|
|
if existing_plans and not confirm_overwrite:
|
|
return {"status": "confirm_overwrite", "message": "Meals already planned for this week. Do you want to overwrite them?"}
|
|
|
|
# If confirmed or no existing plans, delete existing plans for the week
|
|
if existing_plans:
|
|
db.query(Plan).filter(
|
|
Plan.person == person,
|
|
Plan.date >= week_start_date,
|
|
Plan.date < (week_start_date + timedelta(days=7))
|
|
).delete()
|
|
db.flush()
|
|
|
|
# Apply each day of the weekly menu
|
|
for weekly_menu_day in weekly_menu.weekly_menu_days:
|
|
target_date = week_start_date + timedelta(days=weekly_menu_day.day_of_week)
|
|
template = weekly_menu_day.template
|
|
|
|
if template:
|
|
for template_meal in template.template_meals:
|
|
plan = Plan(
|
|
person=person,
|
|
date=target_date,
|
|
meal_id=template_meal.meal_id,
|
|
meal_time=template_meal.meal_time
|
|
)
|
|
db.add(plan)
|
|
|
|
db.commit()
|
|
return {"status": "success", "message": "Weekly menu applied successfully."}
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
logging.error(f"Error applying weekly menu: {e}")
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@router.put("/weeklymenu/{weekly_menu_id}")
|
|
async def update_weekly_menu(weekly_menu_id: int, request: Request, db: Session = Depends(get_db)):
|
|
"""Update an existing weekly menu with new template assignments."""
|
|
try:
|
|
form_data = await request.form()
|
|
name = form_data.get("name")
|
|
template_assignments_str = form_data.get("template_assignments")
|
|
|
|
weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.id == weekly_menu_id).first()
|
|
if not weekly_menu:
|
|
return {"status": "error", "message": "Weekly menu not found"}
|
|
|
|
if not name:
|
|
return {"status": "error", "message": "Weekly menu name is required"}
|
|
|
|
# Check for duplicate name if changed
|
|
if name != weekly_menu.name:
|
|
existing_weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.name == name).first()
|
|
if existing_weekly_menu:
|
|
return {"status": "error", "message": f"Weekly menu with name '{name}' already exists"}
|
|
|
|
weekly_menu.name = name
|
|
|
|
# Clear existing weekly menu days
|
|
db.query(WeeklyMenuDay).filter(WeeklyMenuDay.weekly_menu_id == weekly_menu_id).delete()
|
|
db.flush()
|
|
|
|
# Process new template assignments
|
|
if template_assignments_str:
|
|
assignments = template_assignments_str.split(',')
|
|
for assignment in assignments:
|
|
day_of_week_str, template_id_str = assignment.split(':', 1)
|
|
day_of_week = int(day_of_week_str)
|
|
template_id = int(template_id_str)
|
|
|
|
# Check if template exists
|
|
template = db.query(Template).filter(Template.id == template_id).first()
|
|
if not template:
|
|
raise HTTPException(status_code=400, detail=f"Template with ID {template_id} not found.")
|
|
|
|
weekly_menu_day = WeeklyMenuDay(
|
|
weekly_menu_id=weekly_menu.id,
|
|
day_of_week=day_of_week,
|
|
template_id=template_id
|
|
)
|
|
db.add(weekly_menu_day)
|
|
|
|
db.commit()
|
|
return {"status": "success", "message": "Weekly menu updated successfully"}
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
logging.error(f"Error updating weekly menu: {e}")
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@router.delete("/weeklymenu/{weekly_menu_id}")
|
|
async def delete_weekly_menu(weekly_menu_id: int, db: Session = Depends(get_db)):
|
|
"""Delete a weekly menu and its day assignments."""
|
|
try:
|
|
weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.id == weekly_menu_id).first()
|
|
if not weekly_menu:
|
|
return {"status": "error", "message": "Weekly menu not found"}
|
|
|
|
# Delete associated weekly menu days
|
|
db.query(WeeklyMenuDay).filter(WeeklyMenuDay.weekly_menu_id == weekly_menu_id).delete()
|
|
|
|
db.delete(weekly_menu)
|
|
db.commit()
|
|
|
|
return {"status": "success"}
|
|
except Exception as e:
|
|
db.rollback()
|
|
logging.error(f"Error deleting weekly menu: {e}")
|
|
return {"status": "error", "message": str(e)} |