feat(meal-planner): merge mealList[] into get_meal_plan output (v0.10.2)
- dish entries (list[]) and meal entries (mealList[]) are now merged and returned together, sorted by date then type (BREAKFAST→LUNCH→SNACK→DINNER) - New output fields: note (free-text, meal entries only) and serves (int) - SPEC.md: document verified mealList[] response structure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
__version__ = "0.10.1"
|
||||
__version__ = "0.10.2"
|
||||
|
||||
@@ -2218,16 +2218,29 @@ def update_recipe(
|
||||
def get_meal_plan(date_from: str, date_to: str) -> str:
|
||||
"""Return meal plan entries for a date range.
|
||||
|
||||
The response merges two API lists:
|
||||
|
||||
* ``dish`` entries — planned meals, optionally linked to a recipe.
|
||||
* ``meal`` entries — free-text notes with an optional serving count.
|
||||
|
||||
Args:
|
||||
date_from: Start date in ISO format (e.g. ``"2026-04-13"``).
|
||||
date_to: End date in ISO format (e.g. ``"2026-04-19"``).
|
||||
|
||||
Returns:
|
||||
JSON list of meal plan entries with keys: id, date, type, name,
|
||||
recipe_id, can_update, can_delete. ``type`` is one of
|
||||
``BREAKFAST``, ``LUNCH``, ``SNACK``, ``DINNER``.
|
||||
``recipe_id`` is the linked recipe metaId or ``null`` when the
|
||||
entry is a free-text dish (not linked to a recipe).
|
||||
JSON list of meal plan entries sorted by date then meal type
|
||||
(BREAKFAST → LUNCH → SNACK → DINNER), with keys:
|
||||
|
||||
- ``id`` — metaId (``dish/…`` or ``meal/…``)
|
||||
- ``date`` — ISO date string
|
||||
- ``type`` — ``BREAKFAST``, ``LUNCH``, ``SNACK``, or ``DINNER``
|
||||
- ``name`` — dish name, or ``null`` for meal entries
|
||||
- ``recipe_id`` — linked recipe metaId, or ``null``
|
||||
- ``note`` — free-text note (meal entries only), or ``null``
|
||||
- ``serves`` — number of servings as int (meal entries only), or ``null``
|
||||
- ``can_update`` — whether the entry can be updated
|
||||
- ``can_delete`` — whether the entry can be deleted
|
||||
|
||||
Returns an error message string on failure.
|
||||
"""
|
||||
try:
|
||||
@@ -2236,9 +2249,9 @@ def get_meal_plan(date_from: str, date_to: str) -> str:
|
||||
return f"Error: {exc}"
|
||||
|
||||
try:
|
||||
raw_list = data["a00"]["r"]["r"]["list"]
|
||||
if not isinstance(raw_list, list):
|
||||
raise TypeError("a00.r.r.list is not a list")
|
||||
payload = data["a00"]["r"]["r"]
|
||||
if not isinstance(payload, dict):
|
||||
raise TypeError("a00.r.r is not a dict")
|
||||
except (KeyError, TypeError):
|
||||
return json.dumps(
|
||||
{"warning": "Unexpected mplistinterval response structure", "raw": data},
|
||||
@@ -2246,8 +2259,14 @@ def get_meal_plan(date_from: str, date_to: str) -> str:
|
||||
indent=2,
|
||||
)
|
||||
|
||||
result = []
|
||||
for dish in raw_list:
|
||||
raw_dishes: list[dict[str, Any]] = payload.get("list") or []
|
||||
raw_meals: list[dict[str, Any]] = payload.get("mealList") or []
|
||||
|
||||
_type_order = {"BREAKFAST": 0, "LUNCH": 1, "SNACK": 2, "DINNER": 3}
|
||||
|
||||
result: list[dict[str, Any]] = []
|
||||
|
||||
for dish in raw_dishes:
|
||||
rights = dish.get("rights") or {}
|
||||
result.append(
|
||||
{
|
||||
@@ -2256,11 +2275,32 @@ def get_meal_plan(date_from: str, date_to: str) -> str:
|
||||
"type": dish.get("type"),
|
||||
"name": dish.get("name"),
|
||||
"recipe_id": dish.get("recipeId") or None,
|
||||
"note": None,
|
||||
"serves": None,
|
||||
"can_update": rights.get("canUpdate") == "true",
|
||||
"can_delete": rights.get("canDelete") == "true",
|
||||
}
|
||||
)
|
||||
|
||||
for meal in raw_meals:
|
||||
rights = meal.get("rights") or {}
|
||||
raw_serves = meal.get("serves")
|
||||
result.append(
|
||||
{
|
||||
"id": meal.get("metaId"),
|
||||
"date": meal.get("date"),
|
||||
"type": meal.get("type"),
|
||||
"name": None,
|
||||
"recipe_id": None,
|
||||
"note": meal.get("note") or None,
|
||||
"serves": int(raw_serves) if raw_serves is not None else None,
|
||||
"can_update": rights.get("canUpdate") == "true",
|
||||
"can_delete": rights.get("canDelete") == "true",
|
||||
}
|
||||
)
|
||||
|
||||
result.sort(key=lambda e: (e.get("date") or "", _type_order.get(e.get("type") or "", 99)))
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user