pytest edit shopping list recipes

This commit is contained in:
smilerz 2021-12-13 10:30:53 -06:00
parent 262387da3e
commit a51eb7a2cb
3 changed files with 80 additions and 9 deletions

View File

@ -52,12 +52,14 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
if not r:
raise ValueError(_("You must supply a recipe or mealplan"))
created_by = created_by or getattr(mealplan, 'created_by', None) or getattr(list_recipe, 'created_by', None)
if not created_by:
raise ValueError(_("You must supply a created_by"))
if type(servings) not in [int, float]:
try:
servings = float(servings)
except ValueError:
servings = getattr(mealplan, 'servings', 1.0)
servings_factor = servings / r.servings
shared_users = list(created_by.get_shopping_share())
@ -68,6 +70,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
list_recipe = ShoppingListRecipe.objects.create(recipe=r, mealplan=mealplan, servings=servings)
created = True
related_step_ing = []
if servings == 0 and not created:
list_recipe.delete()
return []
@ -79,7 +82,6 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
if exclude_onhand := created_by.userpreference.mealplan_autoexclude_onhand:
ingredients = ingredients.exclude(food__on_hand=True)
related_step_ing = []
if related := created_by.userpreference.mealplan_autoinclude_related:
# TODO: add levels of related recipes to use when auto-adding mealplans
related_recipes = r.get_related_recipes()
@ -128,6 +130,8 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
if not created and list_recipe.servings != servings:
update_ingredients = set(ingredients.values_list('id', flat=True)) - set(add_ingredients.values_list('id', flat=True))
list_recipe.servings = servings
list_recipe.save()
for sle in ShoppingListEntry.objects.filter(list_recipe=list_recipe, ingredient__id__in=update_ingredients):
sle.amount = sle.ingredient.amount * Decimal(servings_factor)
sle.save()

View File

@ -10,7 +10,7 @@ from django.utils import timezone
from django_scopes import scopes_disabled
from pytest_factoryboy import LazyFixture, register
from cookbook.models import ShoppingListEntry
from cookbook.models import Ingredient, ShoppingListEntry
from cookbook.tests.factories import RecipeFactory
SHOPPING_LIST_URL = 'api:shoppinglistentry-list'
@ -82,7 +82,69 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
assert r.status_code == 405
@pytest.mark.parametrize("recipe, sle_count", [
({}, 10),
({'steps__recipe_count': 1}, 20), # shopping list from recipe with StepRecipe
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe
({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe
], indirect=['recipe'])
def test_shopping_recipe_edit(request, recipe, sle_count, u1_s1, u2_s1):
with scopes_disabled(): # TODO take out
user = auth.get_user(u1_s1)
user2 = auth.get_user(u2_s1)
user.userpreference.mealplan_autoinclude_related = True
user.userpreference.shopping_share.add(user2)
user.userpreference.save()
r = u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}))
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert [x['created_by']['id'] for x in r].count(user.id) == sle_count
all_ing = [x['ingredient'] for x in r]
keep_ing = [x['ingredient'] for x in r[2:]] # TODO change this to remove 1 from each third
list_recipe = r[0]['list_recipe']
amount_sum = sum([x['amount'] for x in r])
# test modifying shopping list as different user
# test increasing servings size of recipe shopping list
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'servings': 2*recipe.servings},
content_type='application/json'
)
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * 2
assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# testing decreasing servings size of recipe shopping list
u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'servings': .5 * recipe.servings},
content_type='application/json'
)
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * .5
assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# test removing 2 items from shopping list
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'ingredients': keep_ing},
content_type='application/json'
)
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert len(r) == sle_count - 2
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 2
# add all ingredients to existing shopping list - don't change serving size
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'ingredients': all_ing},
content_type='application/json'
)
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * .5
assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# TODO test creating shopping list from recipe that includes recipes from multiple users
# TODO test create shopping list from recipe, excluding ingredients
# TODO meal plan recipe with all the user preferences tested
# TODO shopping list from recipe with different servings

View File

@ -661,10 +661,15 @@ class RecipeViewSet(viewsets.ModelViewSet):
def shopping(self, request, pk):
obj = self.get_object()
ingredients = request.data.get('ingredients', None)
servings = request.data.get('servings', obj.servings)
list_recipe = request.data.get('list_recipe', None)
servings = request.data.get('servings', None)
list_recipe = ShoppingListRecipe.objects.filter(id=request.data.get('list_recipe', None)).first()
if servings is None:
servings = getattr(list_recipe, 'servings', obj.servings)
# created_by needs to be sticky to original creator as it is 'their' shopping list
# changing shopping list created_by can shift some items to new owner which may not share in the other direction
created_by = getattr(ShoppingListEntry.objects.filter(list_recipe=list_recipe).first(), 'created_by', request.user)
content = {'msg': _(f'{obj.name} was added to the shopping list.')}
list_from_recipe(list_recipe=list_recipe, recipe=obj, ingredients=ingredients, servings=servings, space=request.space, created_by=request.user)
list_from_recipe(list_recipe=list_recipe, recipe=obj, ingredients=ingredients, servings=servings, space=request.space, created_by=created_by)
return Response(content, status=status.HTTP_204_NO_CONTENT)