fix: focus_areas column name + goal progress calculation
Fixed 2 critical placeholder issues:
1. focus_areas_weighted_json was empty:
- Query used 'area_key' but column is 'key' in focus_area_definitions
- Changed to SELECT key, not area_key
2. Goal progress placeholders showed "nicht verfügbar":
- progress_pct in goals table is NULL (not auto-calculated)
- Added manual calculation in all 3 formatter functions:
* _format_goals_as_markdown() - shows % in table
* _format_goals_behind() - finds lowest progress
* _format_goals_on_track() - finds >= 50% progress
All placeholders should now return proper values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
112226938d
commit
befc310958
|
|
@ -686,11 +686,11 @@ def _get_focus_areas_weighted_json(profile_id: str) -> str:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT area_key, name_de, name_en, category
|
SELECT key, name_de, name_en, category
|
||||||
FROM focus_area_definitions
|
FROM focus_area_definitions
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
""")
|
""")
|
||||||
definitions = {row['area_key']: row for row in cur.fetchall()}
|
definitions = {row['key']: row for row in cur.fetchall()}
|
||||||
|
|
||||||
# Build weighted list
|
# Build weighted list
|
||||||
result = []
|
result = []
|
||||||
|
|
@ -726,12 +726,33 @@ def _format_goals_as_markdown(profile_id: str) -> str:
|
||||||
|
|
||||||
for goal in goals:
|
for goal in goals:
|
||||||
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
||||||
current = f"{goal.get('current_value', '-')}"
|
current = goal.get('current_value')
|
||||||
target = f"{goal.get('target_value', '-')}"
|
target = goal.get('target_value')
|
||||||
progress = f"{goal.get('progress_pct', '-')}%" if goal.get('progress_pct') else '-'
|
start = goal.get('start_value')
|
||||||
|
|
||||||
|
# Calculate progress if possible
|
||||||
|
progress_str = '-'
|
||||||
|
if None not in [current, target, start]:
|
||||||
|
try:
|
||||||
|
current_f = float(current)
|
||||||
|
target_f = float(target)
|
||||||
|
start_f = float(start)
|
||||||
|
|
||||||
|
if target_f == start_f:
|
||||||
|
progress_pct = 100 if current_f == target_f else 0
|
||||||
|
else:
|
||||||
|
progress_pct = ((current_f - start_f) / (target_f - start_f)) * 100
|
||||||
|
progress_pct = max(0, min(100, progress_pct))
|
||||||
|
|
||||||
|
progress_str = f"{int(progress_pct)}%"
|
||||||
|
except (ValueError, ZeroDivisionError):
|
||||||
|
progress_str = '-'
|
||||||
|
|
||||||
|
current_str = f"{current}" if current is not None else '-'
|
||||||
|
target_str = f"{target}" if target is not None else '-'
|
||||||
status = '🎯' if goal.get('is_primary') else '○'
|
status = '🎯' if goal.get('is_primary') else '○'
|
||||||
|
|
||||||
lines.append(f"| {name} | {current} | {target} | {progress} | {status} |")
|
lines.append(f"| {name} | {current_str} | {target_str} | {progress_str} | {status} |")
|
||||||
|
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -793,19 +814,43 @@ def _format_goals_behind(profile_id: str, n: int = 3) -> str:
|
||||||
if not goals:
|
if not goals:
|
||||||
return 'Keine Ziele definiert'
|
return 'Keine Ziele definiert'
|
||||||
|
|
||||||
# Filter goals with progress_pct available, sort by lowest progress
|
# Calculate progress for each goal
|
||||||
goals_with_progress = [g for g in goals if g.get('progress_pct') is not None]
|
goals_with_progress = []
|
||||||
|
for g in goals:
|
||||||
|
current = g.get('current_value')
|
||||||
|
target = g.get('target_value')
|
||||||
|
start = g.get('start_value')
|
||||||
|
|
||||||
|
if None in [current, target, start]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate progress percentage
|
||||||
|
try:
|
||||||
|
current = float(current)
|
||||||
|
target = float(target)
|
||||||
|
start = float(start)
|
||||||
|
|
||||||
|
if target == start:
|
||||||
|
progress_pct = 100 if current == target else 0
|
||||||
|
else:
|
||||||
|
progress_pct = ((current - start) / (target - start)) * 100
|
||||||
|
progress_pct = max(0, min(100, progress_pct))
|
||||||
|
|
||||||
|
g['_calc_progress_pct'] = int(progress_pct)
|
||||||
|
goals_with_progress.append(g)
|
||||||
|
except (ValueError, ZeroDivisionError):
|
||||||
|
continue
|
||||||
|
|
||||||
if not goals_with_progress:
|
if not goals_with_progress:
|
||||||
return 'Keine Ziele mit Fortschritt'
|
return 'Keine Ziele mit Fortschritt'
|
||||||
|
|
||||||
# Sort by progress ascending (lowest first) and take top N
|
# Sort by progress ascending (lowest first) and take top N
|
||||||
sorted_goals = sorted(goals_with_progress, key=lambda x: x.get('progress_pct', 0))[:n]
|
sorted_goals = sorted(goals_with_progress, key=lambda x: x.get('_calc_progress_pct', 0))[:n]
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
for goal in sorted_goals:
|
for goal in sorted_goals:
|
||||||
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
||||||
progress = goal.get('progress_pct', 0)
|
progress = goal.get('_calc_progress_pct', 0)
|
||||||
lines.append(f"{name} ({progress}%)")
|
lines.append(f"{name} ({progress}%)")
|
||||||
|
|
||||||
return ', '.join(lines)
|
return ', '.join(lines)
|
||||||
|
|
@ -822,19 +867,46 @@ def _format_goals_on_track(profile_id: str, n: int = 3) -> str:
|
||||||
if not goals:
|
if not goals:
|
||||||
return 'Keine Ziele definiert'
|
return 'Keine Ziele definiert'
|
||||||
|
|
||||||
# Filter goals with progress >= 50%, sort by highest progress
|
# Calculate progress for each goal
|
||||||
goals_on_track = [g for g in goals if g.get('progress_pct') is not None and g.get('progress_pct', 0) >= 50]
|
goals_with_progress = []
|
||||||
|
for g in goals:
|
||||||
|
current = g.get('current_value')
|
||||||
|
target = g.get('target_value')
|
||||||
|
start = g.get('start_value')
|
||||||
|
|
||||||
|
if None in [current, target, start]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Calculate progress percentage
|
||||||
|
try:
|
||||||
|
current = float(current)
|
||||||
|
target = float(target)
|
||||||
|
start = float(start)
|
||||||
|
|
||||||
|
if target == start:
|
||||||
|
progress_pct = 100 if current == target else 0
|
||||||
|
else:
|
||||||
|
progress_pct = ((current - start) / (target - start)) * 100
|
||||||
|
progress_pct = max(0, min(100, progress_pct))
|
||||||
|
|
||||||
|
g['_calc_progress_pct'] = int(progress_pct)
|
||||||
|
goals_with_progress.append(g)
|
||||||
|
except (ValueError, ZeroDivisionError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Filter goals with progress >= 50%
|
||||||
|
goals_on_track = [g for g in goals_with_progress if g.get('_calc_progress_pct', 0) >= 50]
|
||||||
|
|
||||||
if not goals_on_track:
|
if not goals_on_track:
|
||||||
return 'Keine Ziele auf gutem Weg'
|
return 'Keine Ziele auf gutem Weg'
|
||||||
|
|
||||||
# Sort by progress descending (highest first) and take top N
|
# Sort by progress descending (highest first) and take top N
|
||||||
sorted_goals = sorted(goals_on_track, key=lambda x: x.get('progress_pct', 0), reverse=True)[:n]
|
sorted_goals = sorted(goals_on_track, key=lambda x: x.get('_calc_progress_pct', 0), reverse=True)[:n]
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
for goal in sorted_goals:
|
for goal in sorted_goals:
|
||||||
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
|
||||||
progress = goal.get('progress_pct', 0)
|
progress = goal.get('_calc_progress_pct', 0)
|
||||||
lines.append(f"{name} ({progress}%)")
|
lines.append(f"{name} ({progress}%)")
|
||||||
|
|
||||||
return ', '.join(lines)
|
return ', '.join(lines)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user