diff --git a/backend/placeholder_resolver.py b/backend/placeholder_resolver.py index e8b8931..debc29f 100644 --- a/backend/placeholder_resolver.py +++ b/backend/placeholder_resolver.py @@ -898,25 +898,82 @@ def _format_goals_behind(profile_id: str, n: int = 3) -> str: print(f"[DEBUG] → Exception: {type(e).__name__}: {e}") continue - if not goals_with_deviation: - return 'Keine Ziele mit Zeitvorgabe' + # Also process goals WITHOUT target_date (simple progress) + goals_without_date = [] + print(f"[DEBUG] Processing goals without target_date for simple progress") - # Sort by deviation ascending (most negative first = most behind) - # Only include goals that are actually behind (deviation < 0) - behind_goals = [g for g in goals_with_deviation if g['_deviation'] < 0] + for g in goals: + if g.get('target_date'): + continue # Already processed above - if not behind_goals: - return 'Alle Ziele im Zeitplan' + goal_name = g.get('name') or g.get('goal_type', 'Unknown') + current = g.get('current_value') + target = g.get('target_value') + start = g.get('start_value') - sorted_goals = sorted(behind_goals, key=lambda x: x['_deviation'])[:n] + if None in [current, target, start]: + print(f"[DEBUG] Goal '{goal_name}' (no date): Skipped - missing values") + continue + + 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['_simple_progress'] = int(progress_pct) + goals_without_date.append(g) + print(f"[DEBUG] Goal '{goal_name}' (no date): Added with {int(progress_pct)}% progress") + except (ValueError, ZeroDivisionError, TypeError) as e: + print(f"[DEBUG] Goal '{goal_name}' (no date): Exception - {e}") + continue + + # Combine: Goals with negative deviation + Goals without date with low progress + behind_with_date = [g for g in goals_with_deviation if g['_deviation'] < 0] + behind_without_date = [g for g in goals_without_date if g['_simple_progress'] < 50] + + print(f"[DEBUG] Behind with date: {len(behind_with_date)}, Behind without date: {len(behind_without_date)}") + + # Create combined list with sort keys + combined = [] + for g in behind_with_date: + combined.append({ + 'goal': g, + 'sort_key': g['_deviation'], # Negative deviation (worst first) + 'has_date': True + }) + for g in behind_without_date: + # Map progress to deviation-like scale: 0% = -100, 50% = -50 + combined.append({ + 'goal': g, + 'sort_key': g['_simple_progress'] - 100, # Convert to negative scale + 'has_date': False + }) + + if not combined: + return 'Alle Ziele im Zeitplan oder erreicht' + + # Sort by sort_key (most negative first) + sorted_combined = sorted(combined, key=lambda x: x['sort_key'])[:n] lines = [] - for goal in sorted_goals: - name = goal.get('name') or goal.get('goal_type', 'Unbekannt') - actual = goal['_actual_progress'] - expected = goal['_expected_progress'] - deviation = goal['_deviation'] - lines.append(f"{name} ({actual}% statt {expected}%, {deviation}%)") + for item in sorted_combined: + g = item['goal'] + name = g.get('name') or g.get('goal_type', 'Unbekannt') + + if item['has_date']: + actual = g['_actual_progress'] + expected = g['_expected_progress'] + deviation = g['_deviation'] + lines.append(f"{name} ({actual}% statt {expected}%, {deviation}%)") + else: + progress = g['_simple_progress'] + lines.append(f"{name} ({progress}% erreicht)") return ', '.join(lines) except Exception as e: @@ -1014,25 +1071,81 @@ def _format_goals_on_track(profile_id: str, n: int = 3) -> str: print(f"[DEBUG] → Exception: {type(e).__name__}: {e}") continue - if not goals_with_deviation: - return 'Keine Ziele mit Zeitvorgabe' + # Also process goals WITHOUT target_date (simple progress) + goals_without_date = [] + print(f"[DEBUG] Processing goals without target_date for simple progress") - # Sort by deviation descending (most positive first = most ahead) - # Only include goals that are ahead or on track (deviation >= 0) - ahead_goals = [g for g in goals_with_deviation if g['_deviation'] >= 0] + for g in goals: + if g.get('target_date'): + continue # Already processed above - if not ahead_goals: + goal_name = g.get('name') or g.get('goal_type', 'Unknown') + current = g.get('current_value') + target = g.get('target_value') + start = g.get('start_value') + + if None in [current, target, start]: + print(f"[DEBUG] Goal '{goal_name}' (no date): Skipped - missing values") + continue + + 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['_simple_progress'] = int(progress_pct) + goals_without_date.append(g) + print(f"[DEBUG] Goal '{goal_name}' (no date): Added with {int(progress_pct)}% progress") + except (ValueError, ZeroDivisionError, TypeError) as e: + print(f"[DEBUG] Goal '{goal_name}' (no date): Exception - {e}") + continue + + # Combine: Goals with positive deviation + Goals without date with high progress + ahead_with_date = [g for g in goals_with_deviation if g['_deviation'] >= 0] + ahead_without_date = [g for g in goals_without_date if g['_simple_progress'] >= 50] + + print(f"[DEBUG] Ahead with date: {len(ahead_with_date)}, Ahead without date: {len(ahead_without_date)}") + + # Create combined list with sort keys + combined = [] + for g in ahead_with_date: + combined.append({ + 'goal': g, + 'sort_key': g['_deviation'], # Positive deviation (best first) + 'has_date': True + }) + for g in ahead_without_date: + # Map progress to deviation-like scale: 50% = 0, 100% = +50 + combined.append({ + 'goal': g, + 'sort_key': g['_simple_progress'] - 50, # Convert to positive scale + 'has_date': False + }) + + if not combined: return 'Keine Ziele im Zeitplan' - sorted_goals = sorted(ahead_goals, key=lambda x: x['_deviation'], reverse=True)[:n] + # Sort by sort_key descending (most positive first) + sorted_combined = sorted(combined, key=lambda x: x['sort_key'], reverse=True)[:n] lines = [] - for goal in sorted_goals: - name = goal.get('name') or goal.get('goal_type', 'Unbekannt') - actual = goal['_actual_progress'] - expected = goal['_expected_progress'] - deviation = goal['_deviation'] - lines.append(f"{name} ({actual}%, +{deviation}% voraus)") + for item in sorted_combined: + g = item['goal'] + name = g.get('name') or g.get('goal_type', 'Unbekannt') + + if item['has_date']: + actual = g['_actual_progress'] + deviation = g['_deviation'] + lines.append(f"{name} ({actual}%, +{deviation}% voraus)") + else: + progress = g['_simple_progress'] + lines.append(f"{name} ({progress}% erreicht)") return ', '.join(lines) except Exception as e: