From 571f187abdff9679aa41040542fa41d1fd64de13 Mon Sep 17 00:00:00 2001 From: jableader Date: Mon, 28 Jul 2025 22:36:56 +1000 Subject: [PATCH] View purchased shopping lists --- main.py | 35 ++++++++++++++++------------------- shopping/__init__.py | 18 +++++++++++++++++- shopping/db.py | 3 +++ 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/main.py b/main.py index 25dc8fd..c7214d8 100644 --- a/main.py +++ b/main.py @@ -267,24 +267,10 @@ async def get_current_shopping_list(conn: sqlite3.Connection = Depends(get_db)) other_shopping_list_ids = {item.list_id for item in purchased_requests} shopping_list_lookup = { list_id: await shopping.load_shopping_list(conn, list_id) for list_id in other_shopping_list_ids } - meals_lookup = {} - ingredients_lookup = {} - recipes_lookup = {} # Reduce the data structure to items and lookups items = meal_requests + outstanding_requests + purchased_requests + [item for sl in shopping_list_lookup.values() for item in sl.items] - for item in items: - if item.meal and not item.meal.id in meals_lookup: - meals_lookup[item.meal.id] = item.meal - item.meal = None - - if item.ingredient and not item.ingredient.id in ingredients_lookup: - ingredients_lookup[item.ingredient.id] = item.ingredient - item.ingredient = None - - if item.recipe and not item.recipe.id in recipes_lookup: - recipes_lookup[item.recipe.id] = item.recipe - item.recipe = None + meals_lookup, recipes_lookup, ingredients_lookup = shopping.remove_references(items) return CurrentShoppingList( outstanding_items=outstanding_requests, @@ -296,18 +282,29 @@ async def get_current_shopping_list(conn: sqlite3.Connection = Depends(get_db)) recipes_lookup=recipes_lookup ) +class PurchasedShoppingList(BaseModel): + list: shopping.ShoppingList + meals_lookup: Dict[int, meals.Meal] = {} + ingredients_lookup: Dict[int, ingredients.Ingredient] = {} + recipes_lookup: Dict[int, recipes.Recipe] = {} + @app.get("/api/shopping/{list_id}") -async def get_shopping_list(list_id: int, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: - return await shopping.load_shopping_list(conn, list_id) +async def get_shopping_list(list_id: int, conn: sqlite3.Connection = Depends(get_db)) -> PurchasedShoppingList: + shopping_list = await shopping.load_shopping_list(conn, list_id) + result = PurchasedShoppingList(list=shopping_list) + shopping.remove_references(result.list.items, result.meals_lookup, result.recipes_lookup, result.ingredients_lookup) + return result @app.post("/api/shopping/") -async def purchase_ingredients(shopping_list: shopping.ShoppingList, conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> shopping.ShoppingList: +async def purchase_ingredients(shopping_list: shopping.ShoppingList, conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> PurchasedShoppingList: shopping_list = shopping.ShoppingList(purchased_by=person, items=shopping_list.items, store_name=shopping_list.store_name) await shopping.purchase(conn, shopping_list) await conn.commit() - return shopping_list + result = PurchasedShoppingList(list=shopping_list) + shopping.remove_references(shopping_list.items, result.meals_lookup, result.recipes_lookup, result.ingredients_lookup) + return result @app.get("/api/shopping/current/me/ingredients") async def get_my_shopping_list(conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> List[ingredients.Ingredient]: diff --git a/shopping/__init__.py b/shopping/__init__.py index 8e1ec32..3a9c61b 100644 --- a/shopping/__init__.py +++ b/shopping/__init__.py @@ -1,8 +1,24 @@ -from typing import AsyncIterator, Iterator, List, Tuple +from typing import Any, AsyncIterator, Dict, Iterator, List, Tuple from shopping.db import ShoppingList, ShoppingListItem, load_shopping_list, purchase, remove_request, request from shopping.db import find_items_by_list_id as _find_items_by_list_id, get_purchased_ingredients as _get_purchased_ingredients +def remove_references(items: List[ShoppingListItem], meals_lookup = {}, recipes_lookup = {}, ingredients_lookup = {}) -> Tuple[Dict[int, Any], Dict[int, Any], Dict[int, Any]]: + for item in items: + if item.meal and not item.meal.id in meals_lookup: + meals_lookup[item.meal.id] = item.meal + item.meal = None + + if item.ingredient and not item.ingredient.id in ingredients_lookup: + ingredients_lookup[item.ingredient.id] = item.ingredient + item.ingredient = None + + if item.recipe and not item.recipe.id in recipes_lookup: + recipes_lookup[item.recipe.id] = item.recipe + item.recipe = None + + return meals_lookup, recipes_lookup, ingredients_lookup + async def get_persons_requests(conn, person_id: int) -> AsyncIterator[ShoppingListItem]: async for item in _find_items_by_list_id(conn, None): if item.person_id == person_id and item.ingredient_id is not None: diff --git a/shopping/db.py b/shopping/db.py index b1d9ec2..e94da58 100644 --- a/shopping/db.py +++ b/shopping/db.py @@ -86,6 +86,9 @@ async def purchase(conn, shopping_list: ShoppingList) -> None: if shopping_list.items is None or len(shopping_list.items) == 0: raise ValueError('Shopping list must have items') + + if shopping_list.purchased_by_id < 0: + raise ValueError('Shopping list must have a valid person id') shopping_list.created_date = datetime.now().astimezone()