mirror of
https://github.com/sstent/foodplanner.git
synced 2025-12-06 08:01:47 +00:00
updated the tracker to have more features
This commit is contained in:
@@ -285,8 +285,7 @@ async def use_template(template_id: int, request: Request, db: Session = Depends
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=template_meal.meal_id,
|
meal_id=template_meal.meal_id,
|
||||||
meal_time=template_meal.meal_time,
|
meal_time=template_meal.meal_time
|
||||||
quantity=1.0 # Default quantity when applying template
|
|
||||||
)
|
)
|
||||||
db.add(tracked_meal)
|
db.add(tracked_meal)
|
||||||
|
|
||||||
|
|||||||
@@ -87,9 +87,8 @@ async def tracker_add_meal(request: Request, db: Session = Depends(get_db)):
|
|||||||
date_str = form_data.get("date")
|
date_str = form_data.get("date")
|
||||||
meal_id = form_data.get("meal_id")
|
meal_id = form_data.get("meal_id")
|
||||||
meal_time = form_data.get("meal_time")
|
meal_time = form_data.get("meal_time")
|
||||||
quantity = 1.0 # Default quantity to 1.0 as the field is removed from the UI
|
|
||||||
|
|
||||||
logging.info(f"DEBUG: Adding meal to tracker - person={person}, date={date_str}, meal_id={meal_id}, meal_time={meal_time}, quantity={quantity}")
|
logging.info(f"DEBUG: Adding meal to tracker - person={person}, date={date_str}, meal_id={meal_id}, meal_time={meal_time}")
|
||||||
|
|
||||||
# Parse date
|
# Parse date
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -111,8 +110,7 @@ async def tracker_add_meal(request: Request, db: Session = Depends(get_db)):
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=int(meal_id),
|
meal_id=int(meal_id),
|
||||||
meal_time=meal_time,
|
meal_time=meal_time
|
||||||
quantity=quantity
|
|
||||||
)
|
)
|
||||||
db.add(tracked_meal)
|
db.add(tracked_meal)
|
||||||
|
|
||||||
@@ -259,8 +257,7 @@ async def tracker_apply_template(request: Request, db: Session = Depends(get_db)
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=template_meal.meal_id,
|
meal_id=template_meal.meal_id,
|
||||||
meal_time=template_meal.meal_time,
|
meal_time=template_meal.meal_time
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db.add(tracked_meal)
|
db.add(tracked_meal)
|
||||||
|
|
||||||
@@ -540,7 +537,6 @@ async def save_as_new_meal(data: dict = Body(...), db: Session = Depends(get_db)
|
|||||||
|
|
||||||
# Update the original tracked meal to point to the new meal
|
# Update the original tracked meal to point to the new meal
|
||||||
tracked_meal.meal_id = new_meal.id
|
tracked_meal.meal_id = new_meal.id
|
||||||
tracked_meal.quantity = 1.0 # Reset quantity to 1.0 as the new meal contains the correct quantities
|
|
||||||
|
|
||||||
# Clear custom tracked foods from the original tracked meal
|
# Clear custom tracked foods from the original tracked meal
|
||||||
for tf in tracked_meal.tracked_foods:
|
for tf in tracked_meal.tracked_foods:
|
||||||
@@ -611,8 +607,7 @@ async def tracker_add_food(data: dict = Body(...), db: Session = Depends(get_db)
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=new_meal.id,
|
meal_id=new_meal.id,
|
||||||
meal_time=meal_time,
|
meal_time=meal_time
|
||||||
quantity=1.0 # Quantity for single food meals is always 1.0, actual food quantity is in MealFood
|
|
||||||
)
|
)
|
||||||
db.add(tracked_meal)
|
db.add(tracked_meal)
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ class TrackedMeal(Base):
|
|||||||
tracked_day_id = Column(Integer, ForeignKey("tracked_days.id"))
|
tracked_day_id = Column(Integer, ForeignKey("tracked_days.id"))
|
||||||
meal_id = Column(Integer, ForeignKey("meals.id"))
|
meal_id = Column(Integer, ForeignKey("meals.id"))
|
||||||
meal_time = Column(String) # Breakfast, Lunch, Dinner, Snack 1, Snack 2, Beverage 1, Beverage 2
|
meal_time = Column(String) # Breakfast, Lunch, Dinner, Snack 1, Snack 2, Beverage 1, Beverage 2
|
||||||
quantity = Column(Float, default=1.0) # Quantity multiplier (e.g., 1.5 for 1.5 servings)
|
|
||||||
|
|
||||||
tracked_day = relationship("TrackedDay", back_populates="tracked_meals")
|
tracked_day = relationship("TrackedDay", back_populates="tracked_meals")
|
||||||
meal = relationship("Meal")
|
meal = relationship("Meal")
|
||||||
@@ -201,7 +200,6 @@ class TrackedDayCreate(BaseModel):
|
|||||||
class TrackedMealCreate(BaseModel):
|
class TrackedMealCreate(BaseModel):
|
||||||
meal_id: int
|
meal_id: int
|
||||||
meal_time: str
|
meal_time: str
|
||||||
quantity: float = 1.0
|
|
||||||
|
|
||||||
class FoodExport(FoodResponse):
|
class FoodExport(FoodResponse):
|
||||||
pass
|
pass
|
||||||
@@ -283,7 +281,6 @@ class TrackedMealFoodExport(BaseModel):
|
|||||||
class TrackedMealExport(BaseModel):
|
class TrackedMealExport(BaseModel):
|
||||||
meal_id: int
|
meal_id: int
|
||||||
meal_time: str
|
meal_time: str
|
||||||
quantity: float
|
|
||||||
tracked_foods: List[TrackedMealFoodExport] = []
|
tracked_foods: List[TrackedMealFoodExport] = []
|
||||||
|
|
||||||
class TrackedDayExport(BaseModel):
|
class TrackedDayExport(BaseModel):
|
||||||
@@ -382,12 +379,11 @@ def calculate_tracked_meal_nutrition(tracked_meal, db: Session):
|
|||||||
'fiber': 0, 'sugar': 0, 'sodium': 0, 'calcium': 0
|
'fiber': 0, 'sugar': 0, 'sodium': 0, 'calcium': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Base meal nutrition scaled by quantity
|
# Base meal nutrition
|
||||||
base_nutrition = calculate_meal_nutrition(tracked_meal.meal, db)
|
base_nutrition = calculate_meal_nutrition(tracked_meal.meal, db)
|
||||||
quantity = tracked_meal.quantity
|
|
||||||
for key in totals:
|
for key in totals:
|
||||||
if key in base_nutrition:
|
if key in base_nutrition:
|
||||||
totals[key] += base_nutrition[key] * quantity
|
totals[key] += base_nutrition[key]
|
||||||
|
|
||||||
# Add custom tracked foods
|
# Add custom tracked foods
|
||||||
for tracked_food in tracked_meal.tracked_foods:
|
for tracked_food in tracked_meal.tracked_foods:
|
||||||
|
|||||||
@@ -217,8 +217,7 @@ def sample_tracked_day(db_session, sample_meal):
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=sample_meal.id,
|
meal_id=sample_meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|||||||
@@ -4,4 +4,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8999:8999"
|
- "8999:8999"
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=sqlite:////app/meal_planner.db
|
- DATABASE_URL=sqlite:////app/meal_planner.db
|
||||||
|
volumes:
|
||||||
|
- ./alembic:/app/alembic
|
||||||
|
- ./meal_planner.db:/app/meal_planner.db
|
||||||
@@ -61,9 +61,6 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<div>
|
<div>
|
||||||
<strong>{{ tracked_meal.meal.name }}</strong>
|
<strong>{{ tracked_meal.meal.name }}</strong>
|
||||||
{% if tracked_meal.quantity != 1.0 %}
|
|
||||||
<span class="text-muted">({{ "%.1f"|format(tracked_meal.quantity) }}x)</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn btn-sm btn-outline-secondary me-1" onclick="editTrackedMeal('{{ tracked_meal.id }}')" title="Edit Meal">
|
<button class="btn btn-sm btn-outline-secondary me-1" onclick="editTrackedMeal('{{ tracked_meal.id }}')" title="Edit Meal">
|
||||||
@@ -78,7 +75,6 @@
|
|||||||
<!-- Food Breakdown -->
|
<!-- Food Breakdown -->
|
||||||
<div class="ms-3 row row-cols-2 g-1">
|
<div class="ms-3 row row-cols-2 g-1">
|
||||||
{% for meal_food in tracked_meal.meal.meal_foods %}
|
{% for meal_food in tracked_meal.meal.meal_foods %}
|
||||||
{% set effective_quantity = meal_food.quantity * tracked_meal.quantity %}
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
• {{ meal_food.food.name }}
|
• {{ meal_food.food.name }}
|
||||||
@@ -86,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col text-end">
|
<div class="col text-end">
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
{{ "%.1f"|format(effective_quantity) }} {{ meal_food.food.serving_unit }}
|
{{ "%.1f"|format(meal_food.quantity) }} {{ meal_food.food.serving_unit }}
|
||||||
{% if meal_food.food.serving_size %}
|
{% if meal_food.food.serving_size %}
|
||||||
({{ meal_food.food.serving_size }})
|
({{ meal_food.food.serving_size }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ def sample_chart_data(db_session):
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=meal.id,
|
meal_id=meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ def create_test_data(session: TestingSessionLocal):
|
|||||||
session.commit()
|
session.commit()
|
||||||
session.refresh(tracked_day)
|
session.refresh(tracked_day)
|
||||||
|
|
||||||
tracked_meal = TrackedMeal(tracked_day_id=tracked_day.id, meal_id=meal1.id, meal_time="Breakfast", quantity=1.0)
|
tracked_meal = TrackedMeal(tracked_day_id=tracked_day.id, meal_id=meal1.id, meal_time="Breakfast")
|
||||||
session.add(tracked_meal)
|
session.add(tracked_meal)
|
||||||
session.commit()
|
session.commit()
|
||||||
session.refresh(tracked_meal)
|
session.refresh(tracked_meal)
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class TestTrackerNutrition:
|
|||||||
def test_tracked_day_with_quantity_multiplier(self, client, sample_meal, db_session):
|
def test_tracked_day_with_quantity_multiplier(self, client, sample_meal, db_session):
|
||||||
"""Test nutrition calculation with quantity multiplier"""
|
"""Test nutrition calculation with quantity multiplier"""
|
||||||
|
|
||||||
# Create tracked day with meal at 2x quantity
|
# Create tracked day with meal
|
||||||
tracked_day = TrackedDay(
|
tracked_day = TrackedDay(
|
||||||
person="Sarah",
|
person="Sarah",
|
||||||
date=date.today(),
|
date=date.today(),
|
||||||
@@ -202,8 +202,7 @@ class TestTrackerNutrition:
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=sample_meal.id,
|
meal_id=sample_meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=2.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
@@ -211,7 +210,7 @@ class TestTrackerNutrition:
|
|||||||
tracked_meals = [tracked_meal]
|
tracked_meals = [tracked_meal]
|
||||||
nutrition = calculate_day_nutrition_tracked(tracked_meals, db_session)
|
nutrition = calculate_day_nutrition_tracked(tracked_meals, db_session)
|
||||||
|
|
||||||
# Should be double the base meal nutrition
|
# Should be the base meal nutrition
|
||||||
assert nutrition["calories"] > 0
|
assert nutrition["calories"] > 0
|
||||||
|
|
||||||
|
|
||||||
@@ -231,8 +230,7 @@ class TestTrackerView:
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=sample_meal.id,
|
meal_id=sample_meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
@@ -260,8 +258,7 @@ class TestTrackerEdit:
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=sample_meal.id,
|
meal_id=sample_meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
@@ -283,7 +280,8 @@ class TestTrackerEdit:
|
|||||||
# Update the food quantity via API
|
# Update the food quantity via API
|
||||||
response = client.post("/tracker/update_tracked_food", json={
|
response = client.post("/tracker/update_tracked_food", json={
|
||||||
"tracked_food_id": tracked_food.id,
|
"tracked_food_id": tracked_food.id,
|
||||||
"quantity": 3.0
|
"quantity": 3.0,
|
||||||
|
"is_custom": True
|
||||||
})
|
})
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
@@ -311,8 +309,7 @@ class TestTrackerSaveAsNewMeal:
|
|||||||
tracked_meal = TrackedMeal(
|
tracked_meal = TrackedMeal(
|
||||||
tracked_day_id=tracked_day.id,
|
tracked_day_id=tracked_day.id,
|
||||||
meal_id=sample_meal.id,
|
meal_id=sample_meal.id,
|
||||||
meal_time="Breakfast",
|
meal_time="Breakfast"
|
||||||
quantity=1.0
|
|
||||||
)
|
)
|
||||||
db_session.add(tracked_meal)
|
db_session.add(tracked_meal)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
@@ -388,7 +385,6 @@ class TestTrackerAddFood:
|
|||||||
|
|
||||||
tracked_meal = tracked_meals[0]
|
tracked_meal = tracked_meals[0]
|
||||||
assert tracked_meal.meal.name == sample_food.name # The meal name should be the food name
|
assert tracked_meal.meal.name == sample_food.name # The meal name should be the food name
|
||||||
assert tracked_meal.quantity == 1.0 # The meal quantity should be 1.0
|
|
||||||
|
|
||||||
# Verify the food is in the tracked meal's foods
|
# Verify the food is in the tracked meal's foods
|
||||||
assert len(tracked_meal.meal.meal_foods) == 1
|
assert len(tracked_meal.meal.meal_foods) == 1
|
||||||
@@ -423,8 +419,44 @@ class TestTrackerAddFood:
|
|||||||
|
|
||||||
tracked_meal = tracked_meals[0]
|
tracked_meal = tracked_meals[0]
|
||||||
assert tracked_meal.meal.name == sample_food.name
|
assert tracked_meal.meal.name == sample_food.name
|
||||||
assert tracked_meal.quantity == 1.0
|
|
||||||
|
|
||||||
assert len(tracked_meal.meal.meal_foods) == 1
|
assert len(tracked_meal.meal.meal_foods) == 1
|
||||||
assert tracked_meal.meal.meal_foods[0].food_id == sample_food.id
|
assert tracked_meal.meal.meal_foods[0].food_id == sample_food.id
|
||||||
assert tracked_meal.meal.meal_foods[0].quantity == 150.0
|
assert tracked_meal.meal.meal_foods[0].quantity == 150.0
|
||||||
|
|
||||||
|
|
||||||
|
class TestTrackedMealQuantity:
|
||||||
|
"""Test the quantity of a tracked meal"""
|
||||||
|
|
||||||
|
def test_add_meal_quantity_is_one(self, client, sample_meal, db_session):
|
||||||
|
"""Test that when a meal is added to the tracker, its quantity is 1.0"""
|
||||||
|
test_date = date.today().isoformat()
|
||||||
|
response = client.post("/tracker/add_meal", data={
|
||||||
|
"person": "Sarah",
|
||||||
|
"date": test_date,
|
||||||
|
"meal_id": str(sample_meal.id),
|
||||||
|
"meal_time": "Breakfast"
|
||||||
|
})
|
||||||
|
assert response.status_code == 200
|
||||||
|
data = response.json()
|
||||||
|
assert data["status"] == "success"
|
||||||
|
|
||||||
|
tracked_meal = db_session.query(TrackedMeal).order_by(TrackedMeal.id.desc()).first()
|
||||||
|
assert tracked_meal is not None
|
||||||
|
|
||||||
|
def test_add_food_quantity_is_one(self, client, sample_food, db_session):
|
||||||
|
"""Test that when a single food is added to the tracker, the underlying meal quantity is 1.0"""
|
||||||
|
test_date = date.today().isoformat()
|
||||||
|
response = client.post("/tracker/add_food", json={
|
||||||
|
"person": "Sarah",
|
||||||
|
"date": test_date,
|
||||||
|
"food_id": sample_food.id,
|
||||||
|
"quantity": 100.0,
|
||||||
|
"meal_time": "Snack 1"
|
||||||
|
})
|
||||||
|
assert response.status_code == 200
|
||||||
|
data = response.json()
|
||||||
|
assert data["status"] == "success"
|
||||||
|
|
||||||
|
tracked_meal = db_session.query(TrackedMeal).order_by(TrackedMeal.id.desc()).first()
|
||||||
|
assert tracked_meal is not None
|
||||||
|
|||||||
Reference in New Issue
Block a user