From 6d4b6561e0b54f91fa53174b97cacd6f85ad703b Mon Sep 17 00:00:00 2001 From: sstent Date: Wed, 1 Oct 2025 08:52:49 -0700 Subject: [PATCH] fixing tracker food edits --- app/api/routes/tracker.py | 74 ++++++++++---------- app/database.py | 22 +++++- tests/test_save_template.py | 134 ++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 tests/test_save_template.py diff --git a/app/api/routes/tracker.py b/app/api/routes/tracker.py index dee5c77..8e3098c 100644 --- a/app/api/routes/tracker.py +++ b/app/api/routes/tracker.py @@ -154,56 +154,60 @@ async def tracker_remove_meal(tracked_meal_id: int, db: Session = Depends(get_db @router.post("/tracker/save_template") async def tracker_save_template(request: Request, db: Session = Depends(get_db)): - """Save current day's meals as a template""" + """save current day's meals as a new template""" try: form_data = await request.form() person = form_data.get("person") date_str = form_data.get("date") template_name = form_data.get("template_name") - - logging.info(f"DEBUG: Saving template - name={template_name}, person={person}, date={date_str}") - - # Parse date + + if not all([person, date_str, template_name]): + raise HTTPException(status_code=400, detail="Missing required form data.") + + logging.info(f"debug: saving template - name={template_name}, person={person}, date={date_str}") + + # 1. Check if template name already exists + existing_template = db.query(Template).filter(Template.name == template_name).first() + if existing_template: + return {"status": "error", "message": f"Template name '{template_name}' already exists."} + + # 2. Find the tracked day and its meals from datetime import datetime - date = datetime.fromisoformat(date_str).date() + target_date = datetime.fromisoformat(date_str).date() - # Get tracked day and meals tracked_day = db.query(TrackedDay).filter( - TrackedDay.person == person, - TrackedDay.date == date + TrackedDay.person == person, TrackedDay.date == target_date ).first() - + if not tracked_day: - return {"status": "error", "message": "No tracked day found"} - - tracked_meals = db.query(TrackedMeal).filter( - TrackedMeal.tracked_day_id == tracked_day.id - ).all() - + return {"status": "error", "message": "Tracked day not found for the given person and date."} + + tracked_meals = db.query(TrackedMeal).filter(TrackedMeal.tracked_day_id == tracked_day.id).all() + if not tracked_meals: - return {"status": "error", "message": "No meals to save as template"} - - # Create template - template = Template(name=template_name) - db.add(template) - db.flush() - - # Add template meals - for tracked_meal in tracked_meals: - template_meal = TemplateMeal( - template_id=template.id, - meal_id=tracked_meal.meal_id, - meal_time=tracked_meal.meal_time + return {"status": "error", "message": "No meals found on this day to save as a template."} + + # 3. Create the new template + new_template = Template(name=template_name) + db.add(new_template) + db.flush() # Use flush to get the new_template.id before commit + + # 4. Create template_meal entries for each tracked meal + for meal in tracked_meals: + template_meal_entry = TemplateMeal( + template_id=new_template.id, + meal_id=meal.meal_id, + meal_time=meal.meal_time ) - db.add(template_meal) + db.add(template_meal_entry) + db.commit() - - logging.info(f"DEBUG: Successfully saved template with {len(tracked_meals)} meals") - return {"status": "success"} - + logging.info(f"debug: successfully saved template '{template_name}' with {len(tracked_meals)} meals.") + return {"status": "success", "message": "Template saved successfully."} + except Exception as e: db.rollback() - logging.error(f"DEBUG: Error saving template: {e}") + logging.error(f"debug: error saving template: {e}") return {"status": "error", "message": str(e)} @router.post("/tracker/apply_template") diff --git a/app/database.py b/app/database.py index f67d276..2a863b4 100644 --- a/app/database.py +++ b/app/database.py @@ -455,4 +455,24 @@ def calculate_day_nutrition_tracked(tracked_meals, db: Session): day_totals['fat_pct'] = 0 day_totals['net_carbs'] = 0 - return day_totals \ No newline at end of file + return day_totals + + +def convert_grams_to_quantity(food_id: int, grams: float, db: Session) -> float: + """ + Converts a given amount in grams to the corresponding quantity multiplier + based on the food's serving size. + """ + food = db.query(Food).filter(Food.id == food_id).first() + if not food: + raise ValueError(f"Food with ID {food_id} not found.") + + try: + serving_size_value = float(food.serving_size) + except ValueError: + raise ValueError(f"Invalid serving size '{food.serving_size}' for food ID {food_id}. Must be a number.") + + if serving_size_value == 0: + raise ValueError(f"Serving size for food ID {food_id} cannot be zero.") + + return grams / serving_size_value \ No newline at end of file diff --git a/tests/test_save_template.py b/tests/test_save_template.py new file mode 100644 index 0000000..f963824 --- /dev/null +++ b/tests/test_save_template.py @@ -0,0 +1,134 @@ +import pytest +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session +from datetime import date, timedelta +from app.database import TrackedDay, TrackedMeal, Meal, Food, Template, TemplateMeal + +@pytest.fixture +def setup_tracker_data(db_session: Session, sample_food: Food): + """Set up tracked day and meals for testing template saving.""" + person_name = "Test Person" + today = date.today() + + # Create a TrackedDay + tracked_day = TrackedDay(person=person_name, date=today) + db_session.add(tracked_day) + db_session.commit() + db_session.refresh(tracked_day) + + # Create a Meal + meal = Meal(name="Test Meal", meal_type="breakfast", meal_time="08:00") + db_session.add(meal) + db_session.commit() + db_session.refresh(meal) + + # Link food to meal (assuming MealFood is handled by Meal creation or omitted for simplicity here) + # For now, let's assume sample_meal already has food linked or we don't need to test food details + # If detailed food linking is needed, we'd add MealFood entries here. + + # Create a TrackedMeal + tracked_meal = TrackedMeal(tracked_day_id=tracked_day.id, meal_id=meal.id, meal_time="08:00") + db_session.add(tracked_meal) + db_session.commit() + db_session.refresh(tracked_meal) + + return {"person": person_name, "date": today, "tracked_day_id": tracked_day.id, "meal_id": meal.id} + +def test_save_template_no_meals_found(client: TestClient, db_session: Session, setup_tracker_data: dict): + """ + Test that saving a template fails when no meals are found for the tracked day. + """ + person = setup_tracker_data["person"] + test_date = setup_tracker_data["date"] + template_name = "No Meals Template" + + # Clear meals for the tracked day created by the fixture + tracked_day = db_session.query(TrackedDay).filter_by(person=person, date=test_date).first() + if tracked_day: + db_session.query(TrackedMeal).filter_by(tracked_day_id=tracked_day.id).delete() + db_session.commit() + + response = client.post( + "/tracker/save_template", + data={ + "person": person, + "date": test_date.isoformat(), + "template_name": template_name + } + ) + + assert response.status_code == 200 + response_data = response.json() + assert response_data["status"] == "error" + assert "No meals found on this day to save as a template." in response_data["message"] + + # Verify that no template was created + templates = db_session.query(Template).filter(Template.name == template_name).all() + assert len(templates) == 0 + +def test_save_template_success(client: TestClient, db_session: Session, setup_tracker_data: dict): + """ + Test the "Save as Template" functionality after the fix is applied. + This test is expected to pass and create a new template and template meals. + """ + person = setup_tracker_data["person"] + test_date = setup_tracker_data["date"] + template_name = "Successful Template" + + response = client.post( + "/tracker/save_template", + data={ + "person": person, + "date": test_date.isoformat(), + "template_name": template_name + } + ) + + assert response.status_code == 200 + response_data = response.json() + assert response_data["status"] == "success" + assert response_data["message"] == "Template saved successfully." + + # Verify that the template was created + new_template = db_session.query(Template).filter(Template.name == template_name).first() + assert new_template is not None + assert new_template.name == template_name + + # Verify that template meals were created + template_meals = db_session.query(TemplateMeal).filter(TemplateMeal.template_id == new_template.id).all() + assert len(template_meals) > 0 + assert template_meals[0].meal_id == setup_tracker_data["meal_id"] + +def test_save_template_duplicate_name(client: TestClient, db_session: Session, setup_tracker_data: dict): + """ + Test saving a template with a duplicate name, expecting an error. + """ + person = setup_tracker_data["person"] + test_date = setup_tracker_data["date"] + template_name = "Duplicate Template" + + # First successful save + response = client.post( + "/tracker/save_template", + data={ + "person": person, + "date": test_date.isoformat(), + "template_name": template_name + } + ) + assert response.status_code == 200 + assert response.json()["status"] == "success" + + # Attempt to save again with the same name + response_duplicate = client.post( + "/tracker/save_template", + data={ + "person": person, + "date": test_date.isoformat(), + "template_name": template_name + } + ) + assert response_duplicate.status_code == 200 + response_data = response_duplicate.json() + assert response_data["status"] == "error" + assert f"Template name '{template_name}' already exists." in response_data["message"] \ No newline at end of file