fix: Part B protein placeholders - aggregate by date
All checks were successful
Deploy Development / deploy (push) Successful in 45s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s

Fixes calculate_protein_g_per_kg and calculate_protein_days_in_target:

**Problem:**
Both functions were treating individual nutrition_log entries as days,
causing incorrect calculations when multiple entries exist per day
(e.g., from CSV imports: 233 entries across 7 days).

**Solution:**
1. calculate_protein_g_per_kg:
   - Added GROUP BY date, SUM(protein_g) to aggregate by day
   - Now averages daily totals, not individual entries
   - Correct: 7 days → 7 values, not 233 entries → 233 values

2. calculate_protein_days_in_target:
   - Added GROUP BY date, SUM(protein_g) to aggregate by day
   - Calculates target range in absolute grams (not g/kg per entry)
   - Counts unique DAYS in range, not entries
   - Correct format: "5/7" (5 of 7 days), not "150/233" (entries)

**Impact:**
- protein_g_per_kg: was returning "nicht verfügbar" → now returns correct value
- protein_days_in_target: was returning "nicht verfügbar" → now returns correct format

**Root Cause:**
Functions expected 7 unique dates but got 233 entries.
With export date 2026-04-02 and last data 2026-03-26,
the 7-day window had insufficient unique dates.

Issue reported by user: Part B placeholders not showing correct values
in extended export (registry metadata was correct, but computed values failed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-04-02 12:43:33 +02:00
parent b00f6ac512
commit 0c19e0c0ed

View File

@ -575,22 +575,23 @@ def calculate_protein_g_per_kg(profile_id: str) -> Optional[float]:
weight = float(weight_row['weight']) weight = float(weight_row['weight'])
# Get protein intake # Get protein intake aggregated by day (SUM per day)
cur.execute(""" cur.execute("""
SELECT protein_g SELECT date, SUM(protein_g) as daily_protein
FROM nutrition_log FROM nutrition_log
WHERE profile_id = %s WHERE profile_id = %s
AND date >= CURRENT_DATE - INTERVAL '7 days' AND date >= CURRENT_DATE - INTERVAL '7 days'
AND protein_g IS NOT NULL AND protein_g IS NOT NULL
GROUP BY date
ORDER BY date DESC ORDER BY date DESC
""", (profile_id,)) """, (profile_id,))
protein_values = [row['protein_g'] for row in cur.fetchall()] daily_protein = [float(row['daily_protein']) for row in cur.fetchall()]
if len(protein_values) < 4: if len(daily_protein) < 4: # At least 4 days with data
return None return None
avg_protein = float(sum(protein_values) / len(protein_values)) avg_protein = sum(daily_protein) / len(daily_protein)
protein_per_kg = avg_protein / weight protein_per_kg = avg_protein / weight
return round(protein_per_kg, 2) return round(protein_per_kg, 2)
@ -619,28 +620,33 @@ def calculate_protein_days_in_target(profile_id: str, target_low: float = 1.6, t
weight = float(weight_row['weight']) weight = float(weight_row['weight'])
# Get protein intake last 7 days # Calculate protein target range (absolute values)
target_low_g = target_low * weight
target_high_g = target_high * weight
# Get protein intake aggregated by day (SUM per day)
cur.execute(""" cur.execute("""
SELECT protein_g, date SELECT date, SUM(protein_g) as daily_protein
FROM nutrition_log FROM nutrition_log
WHERE profile_id = %s WHERE profile_id = %s
AND date >= CURRENT_DATE - INTERVAL '7 days' AND date >= CURRENT_DATE - INTERVAL '7 days'
AND protein_g IS NOT NULL AND protein_g IS NOT NULL
GROUP BY date
ORDER BY date DESC ORDER BY date DESC
""", (profile_id,)) """, (profile_id,))
protein_data = cur.fetchall() daily_data = cur.fetchall()
if len(protein_data) < 4: if len(daily_data) < 4: # At least 4 days with data
return None return None
# Count days in target range # Count days in target range
days_in_target = 0 days_in_target = 0
total_days = len(protein_data) total_days = len(daily_data)
for row in protein_data: for row in daily_data:
protein_per_kg = float(row['protein_g']) / weight daily_protein = float(row['daily_protein'])
if target_low <= protein_per_kg <= target_high: if target_low_g <= daily_protein <= target_high_g:
days_in_target += 1 days_in_target += 1
return f"{days_in_target}/{total_days}" return f"{days_in_target}/{total_days}"