This commit is contained in:
smilerz
2021-12-13 15:06:04 -06:00
parent a51eb7a2cb
commit 35e81f6247
4 changed files with 105 additions and 51 deletions

View File

@ -5,6 +5,7 @@ from django.contrib.postgres.aggregates import ArrayAgg
from django.db.models import F, OuterRef, Q, Subquery, Value from django.db.models import F, OuterRef, Q, Subquery, Value
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext as _
from cookbook.helper.HelperFunctions import Round, str2bool from cookbook.helper.HelperFunctions import Round, str2bool
from cookbook.models import (Ingredient, ShoppingListEntry, ShoppingListRecipe, from cookbook.models import (Ingredient, ShoppingListEntry, ShoppingListRecipe,
@ -52,6 +53,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
if not r: if not r:
raise ValueError(_("You must supply a recipe or mealplan")) raise ValueError(_("You must supply a recipe or mealplan"))
created_by = created_by or getattr(ShoppingListEntry.objects.filter(list_recipe=list_recipe).first(), 'created_by', None)
if not created_by: if not created_by:
raise ValueError(_("You must supply a created_by")) raise ValueError(_("You must supply a created_by"))

View File

@ -94,17 +94,19 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs):
@receiver(post_save, sender=MealPlan) @receiver(post_save, sender=MealPlan)
def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs): def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs):
user = instance.get_owner() user = instance.get_owner()
if not created or not user.userpreference.mealplan_autoadd_shopping: if not user.userpreference.mealplan_autoadd_shopping:
return return
# if creating a mealplan - perform shopping list activities if not created and instance.shoppinglistrecipe_set.exists():
space = instance.space for x in instance.shoppinglistrecipe_set.all():
if user.userpreference.mealplan_autoadd_shopping: if instance.servings != x.servings:
list_recipe = list_from_recipe(list_recipe=x, servings=instance.servings, space=instance.space)
elif created:
# if creating a mealplan - perform shopping list activities
kwargs = { kwargs = {
'mealplan': instance, 'mealplan': instance,
'space': space, 'space': instance.space,
'created_by': user, 'created_by': user,
'servings': instance.servings 'servings': instance.servings
} }
list_recipe = list_from_recipe(**kwargs) list_recipe = list_from_recipe(**kwargs)

View File

@ -11,12 +11,27 @@ from django_scopes import scopes_disabled
from pytest_factoryboy import LazyFixture, register from pytest_factoryboy import LazyFixture, register
from cookbook.models import Ingredient, ShoppingListEntry from cookbook.models import Ingredient, ShoppingListEntry
from cookbook.tests.factories import RecipeFactory from cookbook.tests.factories import MealPlanFactory, RecipeFactory, UserFactory
SHOPPING_LIST_URL = 'api:shoppinglistentry-list' SHOPPING_LIST_URL = 'api:shoppinglistentry-list'
SHOPPING_RECIPE_URL = 'api:recipe-shopping' SHOPPING_RECIPE_URL = 'api:recipe-shopping'
@pytest.fixture()
def user2(request, u1_s1):
try:
params = request.param # request.param is a magic variable
except AttributeError:
params = {}
user = auth.get_user(u1_s1)
user.userpreference.mealplan_autoadd_shopping = True
user.userpreference.mealplan_autoinclude_related = True
key = list(params)[0]
setattr(user.userpreference, key, params[key])
user.userpreference.save
return u1_s1
@pytest.fixture() @pytest.fixture()
def recipe(request, space_1, u1_s1): def recipe(request, space_1, u1_s1):
try: try:
@ -88,62 +103,97 @@ def test_shopping_recipe_method(request, arg, recipe, sle_count, u1_s1, u2_s1):
({'steps__food_recipe_count': {'step': 0, 'count': 1}}, 19), # shopping list from recipe with food recipe ({'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 ({'steps__food_recipe_count': {'step': 0, 'count': 1}, 'steps__recipe_count': 1}, 29), # shopping list from recipe with StepRecipe and food recipe
], indirect=['recipe']) ], indirect=['recipe'])
def test_shopping_recipe_edit(request, recipe, sle_count, u1_s1, u2_s1): @pytest.mark.parametrize("use_mealplan", [(False), (True), ])
with scopes_disabled(): # TODO take out def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u2_s1):
# tests editing shopping list via recipe or mealplan
user = auth.get_user(u1_s1)
user2 = auth.get_user(u2_s1)
user.userpreference.mealplan_autoinclude_related = True
user.userpreference.mealplan_autoadd_shopping = True
user.userpreference.shopping_share.add(user2)
user.userpreference.save()
user = auth.get_user(u1_s1) if use_mealplan:
user2 = auth.get_user(u2_s1) mealplan = MealPlanFactory(space=recipe.space, created_by=user, servings=recipe.servings, recipe=recipe)
user.userpreference.mealplan_autoinclude_related = True else:
user.userpreference.shopping_share.add(user2) u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}))
user.userpreference.save() 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 = all_ing[1:-1] # remove first and last element
del keep_ing[int(len(keep_ing)/2)] # remove a middle element
list_recipe = r[0]['list_recipe']
amount_sum = sum([x['amount'] for x in r])
r = u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id})) # test modifying shopping list as different user
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) # test increasing servings size of recipe shopping list
assert [x['created_by']['id'] for x in r].count(user.id) == sle_count if use_mealplan:
all_ing = [x['ingredient'] for x in r] mealplan.servings = 2*recipe.servings
keep_ing = [x['ingredient'] for x in r[2:]] # TODO change this to remove 1 from each third mealplan.save()
list_recipe = r[0]['list_recipe'] else:
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}), u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'servings': 2*recipe.servings}, {'list_recipe': list_recipe, 'servings': 2*recipe.servings},
content_type='application/json' content_type='application/json'
) )
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * 2 assert sum([x['amount'] for x in r]) == amount_sum * 2
assert len(r) == sle_count assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# testing decreasing servings size of recipe shopping list # testing decreasing servings size of recipe shopping list
if use_mealplan:
mealplan.servings = .5 * recipe.servings
mealplan.save()
else:
u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), u1_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'servings': .5 * recipe.servings}, {'list_recipe': list_recipe, 'servings': .5 * recipe.servings},
content_type='application/json' content_type='application/json'
) )
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * .5 assert sum([x['amount'] for x in r]) == amount_sum * .5
assert len(r) == sle_count assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# test removing 2 items from shopping list # test removing 2 items from shopping list
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'ingredients': keep_ing}, {'list_recipe': list_recipe, 'ingredients': keep_ing},
content_type='application/json' content_type='application/json'
) )
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert len(r) == sle_count - 2 assert len(r) == sle_count - 3
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 2 assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count - 3
# add all ingredients to existing shopping list - don't change serving size # add all ingredients to existing shopping list - don't change serving size
u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}), u2_s1.put(reverse(SHOPPING_RECIPE_URL, args={recipe.id}),
{'list_recipe': list_recipe, 'ingredients': all_ing}, {'list_recipe': list_recipe, 'ingredients': all_ing},
content_type='application/json' content_type='application/json'
) )
r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content) r = json.loads(u1_s1.get(reverse(SHOPPING_LIST_URL)).content)
assert sum([x['amount'] for x in r]) == amount_sum * .5 assert sum([x['amount'] for x in r]) == amount_sum * .5
assert len(r) == sle_count assert len(r) == sle_count
assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count assert len(json.loads(u2_s1.get(reverse(SHOPPING_LIST_URL)).content)) == sle_count
# auto add shopping, no
# auto include related, no
# auto ignore onhand
# ignore shopping food
@pytest.mark.parametrize("user2, sle_count", [
({'mealplan_autoadd_shopping': False}, 0),
({'mealplan_autoinclude_related': False}, 9),
({'mealplan_autoexclude_onhand': True}, 27), # shopping list from recipe with StepRecipe
], indirect=['user2'])
@pytest.mark.parametrize("use_mealplan", [(False), (True), ])
@pytest.mark.parametrize("recipe", [({'steps__recipe_count': 1})], indirect=['recipe'])
def test_shopping_recipe_userpreference(request, recipe, sle_count, use_mealplan, user2):
with scopes_disabled():
user = auth.get_user(user2)
# setup recipe with 10 ingredients, 1 step recipe with 10 ingredients, 1 food onhand, 1 food ignore shopping
recipe.step.all()
def test_shopping_recipe_mixed_authors(request, user2):
assert 1 == 1
# TODO test creating shopping list from recipe that includes recipes from multiple users # TODO test creating shopping list from recipe that includes recipes from multiple users

View File

@ -195,7 +195,7 @@ class MealPlanFactory(factory.django.DjangoModelFactory):
space = factory.SubFactory(SpaceFactory) space = factory.SubFactory(SpaceFactory)
class Params: class Params:
has_recipe = False has_recipe = True
class Meta: class Meta:
model = 'cookbook.MealPlan' model = 'cookbook.MealPlan'