Allowed for null products, move ingredient spreading server-side #1

Merged
jacob merged 7 commits from nullproducts into master 2025-07-28 23:23:10 +00:00
4 changed files with 26 additions and 33 deletions
Showing only changes of commit a9981005a4 - Show all commits

View file

@ -38,7 +38,7 @@ async def insert_ingredient(conn, ingredient: Ingredient):
ingredient.product_id = ingredient.product.id ingredient.product_id = ingredient.product.id
if ingredient.product_id < 0: if ingredient.product_id < 0:
raise ValueError('Product must be inserted before ingredient') ingredient.product_id = None
async with conn.execute(''' async with conn.execute('''
INSERT INTO Ingredient (name, line, preparation, unit, quantity, product_id, recipe_id, meal_id) INSERT INTO Ingredient (name, line, preparation, unit, quantity, product_id, recipe_id, meal_id)

23
main.py
View file

@ -109,10 +109,6 @@ async def create_recipe(recipe: recipes.Recipe, conn: sqlite3.Connection = Depen
if not recipe.ingredients: if not recipe.ingredients:
return JSONResponse(status_code=400, content={'message': 'Recipe must have at least one ingredient'}) return JSONResponse(status_code=400, content={'message': 'Recipe must have at least one ingredient'})
for ingredient in recipe.ingredients:
if not ingredient.product:
return JSONResponse(status_code=400, content={'message': 'Ingredient must have a product'})
if recipe.id >= 0: if recipe.id >= 0:
await recipes.hide_recipe(conn, recipe.id, user) await recipes.hide_recipe(conn, recipe.id, user)
recipe.based_on_recipe = recipe.id recipe.based_on_recipe = recipe.id
@ -122,7 +118,9 @@ async def create_recipe(recipe: recipes.Recipe, conn: sqlite3.Connection = Depen
await recipes.insert_recipe(conn, recipe) await recipes.insert_recipe(conn, recipe)
for ingredient in recipe.ingredients: for ingredient in recipe.ingredients:
ingredient.recipe_id = recipe.id ingredient.recipe_id = recipe.id
ingredient.product_id = ingredient.product.id if ingredient.product:
ingredient.product_id = ingredient.product.id
await ingredients.insert_ingredient(conn, ingredient) await ingredients.insert_ingredient(conn, ingredient)
await conn.commit() await conn.commit()
@ -275,20 +273,9 @@ async def get_current_shopping_list(conn: sqlite3.Connection = Depends(get_db))
async def get_shopping_list(list_id: int, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: 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) return await shopping.load_shopping_list(conn, list_id)
class ShoppingListPurchase(shopping.ShoppingList):
completed_requests: List[shopping.ShoppingListRequest] = []
@app.post("/api/shopping/") @app.post("/api/shopping/")
async def purchase_ingredients(lst: ShoppingListPurchase, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: async def purchase_ingredients(lst: shopping.ShoppingListPurchase, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList:
await shopping.insert_shopping_list(conn, lst) await shopping.purchase_ingredients(conn, lst)
for request in lst.completed_requests:
if request.meal_id:
meal = await meals.find_meal_by_id(conn, request.meal_id)
if meal:
await meals.mark_purchased(conn, meal)
await shopping.remove_request(conn, request)
await conn.commit() await conn.commit()
return lst return lst

View file

@ -1,2 +1,2 @@
from shopping.db import ShoppingList, ShoppingListRequest, ShoppingListResult, sync_persons_requested_ingredients, load_shopping_list, get_current_requests, request_meal, unrequest_meal, insert_shopping_list, get_shopping_list_with_meal, remove_request from shopping.db import ShoppingList, ShoppingListRequest, ShoppingListResult, ShoppingListPurchase, sync_persons_requested_ingredients, load_shopping_list, get_current_requests, request_meal, unrequest_meal, purchase_ingredients, get_shopping_list_with_meal, remove_request

View file

@ -50,6 +50,9 @@ class ShoppingList(BaseModel):
requests: List[ShoppingListRequest] = [] requests: List[ShoppingListRequest] = []
results: List[ShoppingListResult] = [] results: List[ShoppingListResult] = []
class ShoppingListPurchase(ShoppingList):
completed_requests: List[ShoppingListRequest] = []
async def create(conn): async def create(conn):
await conn.execute(''' await conn.execute('''
CREATE TABLE IF NOT EXISTS ShoppingList ( CREATE TABLE IF NOT EXISTS ShoppingList (
@ -92,14 +95,11 @@ def validate_request(request: ShoppingListRequest) -> None:
if not request.ingredient and not request.meal: if not request.ingredient and not request.meal:
raise ValueError('Request must have either an ingredient or a meal') raise ValueError('Request must have either an ingredient or a meal')
if request.ingredient and request.meal:
raise ValueError('Request cannot have both an ingredient and a meal')
# If an ingredient is provided, it must have a person # If an ingredient is provided, it must have a person
if request.ingredient and not request.person: if request.ingredient and not request.person:
raise ValueError('Ingredient requests must have a person') raise ValueError('Ingredient requests must have a person')
async def insert_shopping_list(conn, shopping_list: ShoppingList): async def purchase_ingredients(conn, shopping_list: ShoppingListPurchase):
shopping_list.created_date = datetime.now().astimezone() shopping_list.created_date = datetime.now().astimezone()
async with conn.execute(''' async with conn.execute('''
@ -108,7 +108,7 @@ async def insert_shopping_list(conn, shopping_list: ShoppingList):
''', (shopping_list.created_date.isoformat(), shopping_list.store_name,)) as cursor: ''', (shopping_list.created_date.isoformat(), shopping_list.store_name,)) as cursor:
shopping_list.id = cursor.lastrowid shopping_list.id = cursor.lastrowid
for request in shopping_list.requests: for request in shopping_list.completed_requests:
request.list_id = shopping_list.id request.list_id = shopping_list.id
validate_request(request) validate_request(request)
@ -128,15 +128,21 @@ async def insert_shopping_list(conn, shopping_list: ShoppingList):
''', (request.ingredient_id, shopping_list.id, request.person_id, request.meal_id, request.created_date.isoformat())) as cursor: ''', (request.ingredient_id, shopping_list.id, request.person_id, request.meal_id, request.created_date.isoformat())) as cursor:
request.id = cursor.lastrowid request.id = cursor.lastrowid
for item in shopping_list.results: if request.ingredient_id and request.person_id:
item.product_id = item.product.id await conn.execute('''
item.list_id = shopping_list.id DELETE FROM ShoppingListRequest
WHERE ingredient_id = ? AND person_id = ? AND list_id IS NULL
''', (request.ingredient_id, request.person_id))
from meals import find_meal_by_id
async def find_completed_meals(conn, shopping_list_request: List[ShoppingListRequest]) -> AsyncIterator[Meal]:
meal_ids = {request.meal_id for request in shopping_list_request if request.meal_id is not None}
if not meal_ids:
return
meals = [await find_meal_by_id(conn, meal_id) for meal_id in meal_ids]
ingredients_as_requests = [ShoppingListRequest(meal_id=meal.id, meal=meal, list_id=shopping_list_request[0].list_id) for meal in meals]
async with conn.execute('''
INSERT INTO ShoppingListResult (product_id, list_id, quantity, unit)
VALUES (?, ?, ?, ?)
''', (item.product_id, item.list_id, item.quantity, item.unit)) as cursor:
item.id = cursor.lastrowid
async def remove_request(conn, request: ShoppingListRequest) -> None: async def remove_request(conn, request: ShoppingListRequest) -> None:
if request.list_id != None: if request.list_id != None: