mirror of
https://github.com/sstent/foodplanner.git
synced 2026-01-25 03:01:35 +00:00
adding macro details to tracker, changing charts to stacked bar chart of macros - fixed double count bug
This commit is contained in:
@@ -406,16 +406,50 @@ def calculate_tracked_meal_nutrition(tracked_meal, db: Session):
|
||||
'calories': 0, 'protein': 0, 'carbs': 0, 'fat': 0,
|
||||
'fiber': 0, 'sugar': 0, 'sodium': 0, 'calcium': 0
|
||||
}
|
||||
# Base meal nutrition
|
||||
base_nutrition = calculate_meal_nutrition(tracked_meal.meal, db)
|
||||
for key in totals:
|
||||
if key in base_nutrition:
|
||||
totals[key] += base_nutrition[key]
|
||||
|
||||
# Add custom tracked foods
|
||||
for tracked_food in tracked_meal.tracked_foods:
|
||||
food = tracked_food.food
|
||||
multiplier = tracked_food.quantity / food.serving_size if food.serving_size and food.serving_size != 0 else 0
|
||||
# 1. Get base foods from the meal
|
||||
# access via relationship, assume eager loading or lazy loading
|
||||
base_foods = {mf.food_id: mf for mf in tracked_meal.meal.meal_foods}
|
||||
|
||||
# 2. Get tracked foods (overrides, deletions, additions)
|
||||
tracked_foods = tracked_meal.tracked_foods
|
||||
|
||||
# 3. Determine effective foods
|
||||
# Start with base foods
|
||||
final_foods = {}
|
||||
for food_id, mf in base_foods.items():
|
||||
final_foods[food_id] = {
|
||||
'food': mf.food,
|
||||
'quantity': mf.quantity
|
||||
}
|
||||
|
||||
# Apply tracked changes
|
||||
for tf in tracked_foods:
|
||||
if tf.is_deleted:
|
||||
# If deleted, remove from final_foods if it exists
|
||||
if tf.food_id in final_foods:
|
||||
del final_foods[tf.food_id]
|
||||
else:
|
||||
# Overrides or Additions
|
||||
# This handles both:
|
||||
# - Overriding a base food (replaces entry with same food_id)
|
||||
# - Adding a new food (adds new entry with new food_id)
|
||||
final_foods[tf.food_id] = {
|
||||
'food': tf.food,
|
||||
'quantity': tf.quantity
|
||||
}
|
||||
|
||||
# 4. Calculate totals
|
||||
for food_id, item in final_foods.items():
|
||||
food = item['food']
|
||||
quantity = item['quantity']
|
||||
|
||||
try:
|
||||
serving_size = float(food.serving_size)
|
||||
multiplier = quantity / serving_size if serving_size > 0 else 0
|
||||
except (ValueError, TypeError):
|
||||
multiplier = 0
|
||||
|
||||
totals['calories'] += (food.calories or 0) * multiplier
|
||||
totals['protein'] += (food.protein or 0) * multiplier
|
||||
totals['carbs'] += (food.carbs or 0) * multiplier
|
||||
|
||||
@@ -11,11 +11,11 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
# Create test database directory if it doesn't exist
|
||||
test_db_dir = "/app/data"
|
||||
test_db_dir = "./test_data"
|
||||
os.makedirs(test_db_dir, exist_ok=True)
|
||||
|
||||
# Use the same database path as Docker container
|
||||
SQLALCHEMY_DATABASE_URL = "sqlite:////app/data/test_detailed.db"
|
||||
SQLALCHEMY_DATABASE_URL = f"sqlite:///{test_db_dir}/test_detailed.db"
|
||||
print(f"Using test database at: {SQLALCHEMY_DATABASE_URL}")
|
||||
|
||||
test_engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
|
||||
@@ -317,64 +317,4 @@ def test_detailed_serving_display_format(client, session):
|
||||
|
||||
# Assert the serving info shows just "2.5g" without rounding or extra info
|
||||
# Current implementation rounds to 3g and shows full breakdown, so this will fail
|
||||
assert '<div class="serving-info">2.5g</div>' in response.text
|
||||
def test_detailed_serving_display_format(client, session):
|
||||
"""Test that serving display shows just grams without rounding or serving breakdown."""
|
||||
# Create food with small serving size to get decimal grams
|
||||
food = Food(
|
||||
name="Test Powder",
|
||||
serving_size=2.5,
|
||||
serving_unit="g",
|
||||
calories=10,
|
||||
protein=1.0,
|
||||
carbs=0.5,
|
||||
fat=0.1,
|
||||
fiber=0.0,
|
||||
sugar=0.0,
|
||||
sodium=0.0,
|
||||
calcium=0.0,
|
||||
source="manual"
|
||||
)
|
||||
session.add(food)
|
||||
session.commit()
|
||||
session.refresh(food)
|
||||
|
||||
# Create meal
|
||||
meal = Meal(name="Test Meal", meal_type="snack", meal_time="Snack")
|
||||
session.add(meal)
|
||||
session.commit()
|
||||
session.refresh(meal)
|
||||
|
||||
# Add food to meal with quantity that results in decimal total_grams
|
||||
meal_food = MealFood(meal_id=meal.id, food_id=food.id, quantity=2.5) # 1 serving = 2.5g
|
||||
session.add(meal_food)
|
||||
session.commit()
|
||||
|
||||
# Create tracked meal via the endpoint
|
||||
test_date = date.today()
|
||||
response_add_meal = client.post(
|
||||
"/tracker/add_meal",
|
||||
data={
|
||||
"person": "Sarah",
|
||||
"date": test_date.isoformat(),
|
||||
"meal_id": meal.id,
|
||||
"meal_time": "Snack"
|
||||
}
|
||||
)
|
||||
assert response_add_meal.status_code == 200
|
||||
assert response_add_meal.json()["status"] == "success"
|
||||
|
||||
# Get detailed page for tracked day
|
||||
response = client.get(f"/detailed?person=Sarah&plan_date={test_date.isoformat()}")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Assert the serving info shows just "2.5g" without rounding or extra info
|
||||
# Current implementation shows full breakdown, so this will fail
|
||||
# Assert the serving info shows just "2.5g" without rounding or extra info
|
||||
# Current implementation shows full breakdown, so this will fail
|
||||
import re
|
||||
serving_pattern = r'<div class="serving-info">\s*2\.5g\s*</div>'
|
||||
assert re.search(serving_pattern, response.text), f"Expected serving info '2.5g' but found: {response.text}"
|
||||
# Also ensure no serving breakdown text is present
|
||||
assert "servings of" not in response.text
|
||||
assert '<div class="serving-info">2.5g</div>' in response.text
|
||||
Reference in New Issue
Block a user