diff --git a/backend/app/services/orchestrator/steps.py b/backend/app/services/orchestrator/steps.py index 9625779..1d979ec 100644 --- a/backend/app/services/orchestrator/steps.py +++ b/backend/app/services/orchestrator/steps.py @@ -12,6 +12,7 @@ from __future__ import annotations import html import logging +import uuid as _uuid from datetime import datetime, timezone from typing import TYPE_CHECKING @@ -122,13 +123,28 @@ def step_email(run: "WeeklyRun", db: "Session") -> None: "days old — the Friday scrape failed and stale data was used.

" ) + # Preload ingredient names for all pending items + ing_ids: set = set() + for _item in plan.items: + if _item.approval_status == MealPlanItemStatus.PENDING and _item.recipe: + for _ing in (_item.recipe.ingredients or []): + if "ingredient_id" in _ing: + ing_ids.add(_ing["ingredient_id"]) + + ingredient_names: dict = {} + if ing_ids: + _ing_rows = db.query(Ingredient).filter( + Ingredient.id.in_([_uuid.UUID(str(i)) for i in ing_ids]) + ).all() + ingredient_names = {str(r.id): r.name for r in _ing_rows} + # Build shopping list preview once (shared across all member emails) all_ingredients: dict[str, tuple[str, str, str, str]] = {} for item in plan.items: if item.approval_status != MealPlanItemStatus.PENDING: continue for ing in (item.recipe.ingredients or [] if item.recipe else []): - ing_name = ing.get("name", "").strip() + ing_name = ingredient_names.get(str(ing.get("ingredient_id", "")), ing.get("name", "unknown")).strip() if not ing_name or ing_name in all_ingredients: continue match = ( @@ -199,7 +215,7 @@ def step_email(run: "WeeklyRun", db: "Session") -> None: ing_rows = "".join( f"
  • {html.escape(str(ing.get('qty', '')))}" f" {html.escape(str(ing.get('unit', '')))}" - f" {html.escape(str(ing.get('name', '')))}
  • " + f" {html.escape(ingredient_names.get(str(ing.get('ingredient_id', '')), ing.get('name', 'unknown')))}" for ing in ingredients ) ing_block = ( @@ -210,7 +226,7 @@ def step_email(run: "WeeklyRun", db: "Session") -> None: # Estimated cost: sum top-confidence grocery match prices est_cost = 0.0 for ing in ingredients: - ing_name = ing.get("name", "").lower() + ing_name = ingredient_names.get(str(ing.get("ingredient_id", "")), ing.get("name", "")).lower() match = ( db.query(IngredientGroceryMatch) .join(Ingredient, IngredientGroceryMatch.ingredient_id == Ingredient.id)