Public Access
fix: resolve ingredient names from Ingredient table in email template
recipe.ingredients JSONB has ingredient_id but no name field; preload names in a single bulk query before the per-member loop so ing_rows, shopping preview, and cost lookup all render real ingredient names. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import html
|
import html
|
||||||
import logging
|
import logging
|
||||||
|
import uuid as _uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import TYPE_CHECKING
|
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.</p>"
|
"days old — the Friday scrape failed and stale data was used.</p>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 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)
|
# Build shopping list preview once (shared across all member emails)
|
||||||
all_ingredients: dict[str, tuple[str, str, str, str]] = {}
|
all_ingredients: dict[str, tuple[str, str, str, str]] = {}
|
||||||
for item in plan.items:
|
for item in plan.items:
|
||||||
if item.approval_status != MealPlanItemStatus.PENDING:
|
if item.approval_status != MealPlanItemStatus.PENDING:
|
||||||
continue
|
continue
|
||||||
for ing in (item.recipe.ingredients or [] if item.recipe else []):
|
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:
|
if not ing_name or ing_name in all_ingredients:
|
||||||
continue
|
continue
|
||||||
match = (
|
match = (
|
||||||
@@ -199,7 +215,7 @@ def step_email(run: "WeeklyRun", db: "Session") -> None:
|
|||||||
ing_rows = "".join(
|
ing_rows = "".join(
|
||||||
f"<li>{html.escape(str(ing.get('qty', '')))}"
|
f"<li>{html.escape(str(ing.get('qty', '')))}"
|
||||||
f" {html.escape(str(ing.get('unit', '')))}"
|
f" {html.escape(str(ing.get('unit', '')))}"
|
||||||
f" {html.escape(str(ing.get('name', '')))}</li>"
|
f" {html.escape(ingredient_names.get(str(ing.get('ingredient_id', '')), ing.get('name', 'unknown')))}</li>"
|
||||||
for ing in ingredients
|
for ing in ingredients
|
||||||
)
|
)
|
||||||
ing_block = (
|
ing_block = (
|
||||||
@@ -210,7 +226,7 @@ def step_email(run: "WeeklyRun", db: "Session") -> None:
|
|||||||
# Estimated cost: sum top-confidence grocery match prices
|
# Estimated cost: sum top-confidence grocery match prices
|
||||||
est_cost = 0.0
|
est_cost = 0.0
|
||||||
for ing in ingredients:
|
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 = (
|
match = (
|
||||||
db.query(IngredientGroceryMatch)
|
db.query(IngredientGroceryMatch)
|
||||||
.join(Ingredient, IngredientGroceryMatch.ingredient_id == Ingredient.id)
|
.join(Ingredient, IngredientGroceryMatch.ingredient_id == Ingredient.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user