From 3fafd43e58dda5682b7c83c9c53668d08c46ca38 Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 29 Dec 2021 16:32:19 -0600 Subject: [PATCH] merge ignore shopping with onhand --- cookbook/helper/shopping_helper.py | 10 +-- .../0159_add_shoppinglistentry_fields.py | 10 +-- .../0160_delete_shoppinglist_orphans.py | 2 +- .../migrations/0163_auto_20211229_1411.py | 35 ++++++++ cookbook/models.py | 10 +-- cookbook/serializer.py | 6 +- cookbook/signals.py | 8 +- cookbook/templates/shopping_list.html | 2 +- cookbook/tests/api/test_api_food.py | 16 ++-- .../tests/api/test_api_shopping_recipe.py | 17 ++-- vue/src/apps/ModelListView/ModelListView.vue | 14 +-- .../ShoppingListView/ShoppingListView.vue | 20 +---- vue/src/components/Badges.vue | 72 +++++++-------- vue/src/components/Badges/OnHand.vue | 8 +- vue/src/components/Badges/Shopping.vue | 12 +-- vue/src/components/ContextMenu/ModelMenu.vue | 90 +++++++------------ vue/src/components/GenericHorizontalCard.vue | 2 +- vue/src/components/GenericPill.vue | 7 +- vue/src/components/IngredientComponent.vue | 48 ++++------ vue/src/components/Modals/ShoppingModal.vue | 4 +- vue/src/locales/en.json | 6 +- vue/src/utils/models.js | 20 +++-- 22 files changed, 191 insertions(+), 228 deletions(-) create mode 100644 cookbook/migrations/0163_auto_20211229_1411.py diff --git a/cookbook/helper/shopping_helper.py b/cookbook/helper/shopping_helper.py index e19de68e..75a70d36 100644 --- a/cookbook/helper/shopping_helper.py +++ b/cookbook/helper/shopping_helper.py @@ -82,7 +82,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None ingredients = Ingredient.objects.filter(step__recipe=r, space=space) if exclude_onhand := created_by.userpreference.mealplan_autoexclude_onhand: - ingredients = ingredients.exclude(food__on_hand=True) + ingredients = ingredients.exclude(food__food_onhand=True) if related := created_by.userpreference.mealplan_autoinclude_related: # TODO: add levels of related recipes (related recipes of related recipes) to use when auto-adding mealplans @@ -93,7 +93,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None # TODO once/if Steps can have a serving size this needs to be refactored if exclude_onhand: # if steps are used more than once in a recipe or subrecipe - I don' think this results in the desired behavior - related_step_ing += Ingredient.objects.filter(step__recipe=x, food__on_hand=False, space=space).values_list('id', flat=True) + related_step_ing += Ingredient.objects.filter(step__recipe=x, food__food_onhand=False, space=space).values_list('id', flat=True) else: related_step_ing += Ingredient.objects.filter(step__recipe=x, space=space).values_list('id', flat=True) @@ -101,10 +101,10 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None if ingredients.filter(food__recipe=x).exists(): for ing in ingredients.filter(food__recipe=x): if exclude_onhand: - x_ing = Ingredient.objects.filter(step__recipe=x, food__on_hand=False, space=space) + x_ing = Ingredient.objects.filter(step__recipe=x, food__food_onhand=False, space=space) else: x_ing = Ingredient.objects.filter(step__recipe=x, space=space) - for i in [x for x in x_ing if not x.food.ignore_shopping]: + for i in [x for x in x_ing]: ShoppingListEntry.objects.create( list_recipe=list_recipe, food=i.food, @@ -139,7 +139,7 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None sle.save() # add any missing Entrys - for i in [x for x in add_ingredients if x.food and not x.food.ignore_shopping]: + for i in [x for x in add_ingredients if x.food]: ShoppingListEntry.objects.create( list_recipe=list_recipe, diff --git a/cookbook/migrations/0159_add_shoppinglistentry_fields.py b/cookbook/migrations/0159_add_shoppinglistentry_fields.py index 9df880d0..633d2960 100644 --- a/cookbook/migrations/0159_add_shoppinglistentry_fields.py +++ b/cookbook/migrations/0159_add_shoppinglistentry_fields.py @@ -28,11 +28,11 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AddField( - model_name='food', - name='on_hand', - field=models.BooleanField(default=False), - ), + # migrations.AddField( + # model_name='food', + # name='on_hand', + # field=models.BooleanField(default=False), + # ), migrations.AddField( model_name='shoppinglistentry', name='completed_at', diff --git a/cookbook/migrations/0160_delete_shoppinglist_orphans.py b/cookbook/migrations/0160_delete_shoppinglist_orphans.py index 27fb0edb..26e08656 100644 --- a/cookbook/migrations/0160_delete_shoppinglist_orphans.py +++ b/cookbook/migrations/0160_delete_shoppinglist_orphans.py @@ -21,7 +21,7 @@ def delete_orphaned_sle(apps, schema_editor): def create_inheritfields(apps, schema_editor): FoodInheritField.objects.create(name='Supermarket Category', field='supermarket_category') - FoodInheritField.objects.create(name='Ignore Shopping', field='ignore_shopping') + FoodInheritField.objects.create(name='On Hand', field='food_onhand') FoodInheritField.objects.create(name='Diet', field='diet') FoodInheritField.objects.create(name='Substitute', field='substitute') FoodInheritField.objects.create(name='Substitute Children', field='substitute_children') diff --git a/cookbook/migrations/0163_auto_20211229_1411.py b/cookbook/migrations/0163_auto_20211229_1411.py new file mode 100644 index 00000000..f279ca12 --- /dev/null +++ b/cookbook/migrations/0163_auto_20211229_1411.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.10 on 2021-12-29 20:11 + +from django.db import migrations + +from cookbook.models import FoodInheritField + +# TODO this can be deleted +# def temp_migration(apps, schema_editor): +# x = FoodInheritField.objects.get(name='Ignore Shopping', field='ignore_shopping') +# x.name = 'On Hand' +# x.field = 'food_onhand' +# x.save + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0162_userpreference_csv_delim'), + ] + + operations = [ + # TODO this can be deleted + # migrations.RunPython(temp_migration), + # TODO this stays + migrations.RenameField( + model_name='food', + old_name='ignore_shopping', + new_name='food_onhand', + ), + # TODO this can be deleted + # migrations.RemoveField( + # model_name='food', + # name='on_hand', + # ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 78eebae3..c5a86f86 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -490,9 +490,9 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin): name = models.CharField(max_length=128, validators=[MinLengthValidator(1)]) recipe = models.ForeignKey('Recipe', null=True, blank=True, on_delete=models.SET_NULL) supermarket_category = models.ForeignKey(SupermarketCategory, null=True, blank=True, on_delete=models.SET_NULL) - ignore_shopping = models.BooleanField(default=False) # inherited field + food_onhand = models.BooleanField(default=False) # inherited field description = models.TextField(default='', blank=True) - on_hand = models.BooleanField(default=False) + # on_hand = models.BooleanField(default=False) inherit = models.BooleanField(default=False) ignore_inherit = models.ManyToManyField(FoodInheritField, blank=True) # inherited field: is this name better as inherit instead of ignore inherit? which is more intuitive? @@ -528,10 +528,10 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin): ]) inherit = inherit.values_list('field', flat=True) - if 'ignore_shopping' in inherit: + if 'food_onhand' in inherit: # get food at root that have children that need updated - Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, space=space, ignore_shopping=True)).update(ignore_shopping=True) - Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, space=space, ignore_shopping=False)).update(ignore_shopping=False) + Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, space=space, food_onhand=True)).update(food_onhand=True) + Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, space=space, food_onhand=False)).update(food_onhand=False) if 'supermarket_category' in inherit: # when supermarket_category is null or blank assuming it is not set and not intended to be blank for all descedants # find top node that has category set diff --git a/cookbook/serializer.py b/cookbook/serializer.py index fca43c1c..55b87f47 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -402,8 +402,8 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR class Meta: model = Food fields = ( - 'id', 'name', 'description', 'shopping', 'recipe', 'ignore_shopping', 'supermarket_category', - 'image', 'parent', 'numchild', 'numrecipe', 'on_hand', 'inherit', 'ignore_inherit', 'full_name' + 'id', 'name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category', + 'image', 'parent', 'numchild', 'numrecipe', 'inherit', 'ignore_inherit', 'full_name' ) read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe') @@ -867,7 +867,7 @@ class FoodExportSerializer(FoodSerializer): class Meta: model = Food - fields = ('name', 'ignore_shopping', 'supermarket_category', 'on_hand') + fields = ('name', 'food_onhand', 'supermarket_category',) class IngredientExportSerializer(WritableNestedModelSerializer): diff --git a/cookbook/signals.py b/cookbook/signals.py index 7fe8384d..1432dbe3 100644 --- a/cookbook/signals.py +++ b/cookbook/signals.py @@ -75,8 +75,8 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs): # apply changes from parent to instance for each inheritted field if instance.inherit and instance.parent and inherit.count() > 0: parent = instance.get_parent() - if 'ignore_shopping' in inherit: - instance.ignore_shopping = parent.ignore_shopping + if 'food_onhand' in inherit: + instance.food_onhand = parent.food_onhand # if supermarket_category is not set, do not cascade - if this becomes non-intuitive can change if 'supermarket_category' in inherit and parent.supermarket_category: instance.supermarket_category = parent.supermarket_category @@ -89,8 +89,8 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs): # TODO figure out how to generalize this # apply changes to direct children - depend on save signals for those objects to cascade inheritance down _save = [] - for child in instance.get_children().filter(inherit=True).exclude(ignore_inherit__field='ignore_shopping'): - child.ignore_shopping = instance.ignore_shopping + for child in instance.get_children().filter(inherit=True).exclude(ignore_inherit__field='food_onhand'): + child.food_onhand = instance.food_onhand _save.append(child) # don't cascade empty supermarket category if instance.supermarket_category: diff --git a/cookbook/templates/shopping_list.html b/cookbook/templates/shopping_list.html index 837c0eac..dcc4ba53 100644 --- a/cookbook/templates/shopping_list.html +++ b/cookbook/templates/shopping_list.html @@ -834,7 +834,7 @@ this.$http.get('{% url 'api:recipe-detail' 123456 %}'.replace('123456', recipe.id)).then((response) => { for (let s of response.data.steps) { for (let i of s.ingredients) { - if (!i.is_header && i.food !== null && i.food.ignore_shopping === false) { + if (!i.is_header && i.food !== null && i.food.food_onhand === false) { this.shopping_list.entries.push({ 'list_recipe': slr.id, 'food': i.food, diff --git a/cookbook/tests/api/test_api_food.py b/cookbook/tests/api/test_api_food.py index 2b1bd3a4..21fc9e1c 100644 --- a/cookbook/tests/api/test_api_food.py +++ b/cookbook/tests/api/test_api_food.py @@ -471,8 +471,8 @@ def test_tree_filter(obj_tree_1, obj_2, obj_3, u1_s1): @pytest.mark.parametrize("obj_tree_1, field, inherit, new_val", [ ({'has_category': True, 'inherit': True}, 'supermarket_category', True, 'cat_1'), ({'has_category': True, 'inherit': False}, 'supermarket_category', False, 'cat_1'), - ({'ignore_shopping': True, 'inherit': True}, 'ignore_shopping', True, 'false'), - ({'ignore_shopping': True, 'inherit': False}, 'ignore_shopping', False, 'false'), + ({'food_onhand': True, 'inherit': True}, 'food_onhand', True, 'false'), + ({'food_onhand': True, 'inherit': False}, 'food_onhand', False, 'false'), ], indirect=['obj_tree_1']) # indirect=True populates magic variable request.param of obj_tree_1 with the parameter def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1): with scope(space=obj_tree_1.space): @@ -498,7 +498,7 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1): @pytest.mark.parametrize("obj_tree_1, field, inherit, new_val", [ ({'has_category': True, 'inherit': True, }, 'supermarket_category', True, 'cat_1'), - ({'ignore_shopping': True, 'inherit': True, }, 'ignore_shopping', True, 'false'), + ({'food_onhand': True, 'inherit': True, }, 'food_onhand', True, 'false'), ], indirect=['obj_tree_1']) # This is more about the model than the API - should this be moved to a different test? def test_ignoreinherit_field(request, obj_tree_1, field, inherit, new_val, u1_s1): @@ -527,16 +527,16 @@ def test_ignoreinherit_field(request, obj_tree_1, field, inherit, new_val, u1_s1 @pytest.mark.parametrize("obj_tree_1", [ - ({'has_category': True, 'inherit': False, 'ignore_shopping': True}), + ({'has_category': True, 'inherit': False, 'food_onhand': True}), ], indirect=['obj_tree_1']) def test_reset_inherit(obj_tree_1, space_1): with scope(space=space_1): space_1.food_inherit.add(*Food.inherit_fields.values_list('id', flat=True)) # set default inherit fields parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] - obj_tree_1.ignore_shopping = False - assert parent.ignore_shopping == child.ignore_shopping - assert parent.ignore_shopping != obj_tree_1.ignore_shopping + obj_tree_1.food_onhand = False + assert parent.food_onhand == child.food_onhand + assert parent.food_onhand != obj_tree_1.food_onhand assert parent.supermarket_category != child.supermarket_category assert parent.supermarket_category != obj_tree_1.supermarket_category @@ -545,5 +545,5 @@ def test_reset_inherit(obj_tree_1, space_1): obj_tree_1 = Food.objects.get(id=obj_tree_1.id) parent = obj_tree_1.get_parent() child = obj_tree_1.get_descendants()[0] - assert parent.ignore_shopping == obj_tree_1.ignore_shopping == child.ignore_shopping + assert parent.food_onhand == obj_tree_1.food_onhand == child.food_onhand assert parent.supermarket_category == obj_tree_1.supermarket_category == child.supermarket_category diff --git a/cookbook/tests/api/test_api_shopping_recipe.py b/cookbook/tests/api/test_api_shopping_recipe.py index cf9c9740..438de046 100644 --- a/cookbook/tests/api/test_api_shopping_recipe.py +++ b/cookbook/tests/api/test_api_shopping_recipe.py @@ -185,27 +185,24 @@ def test_shopping_recipe_edit(request, recipe, sle_count, use_mealplan, u1_s1, u @pytest.mark.parametrize("user2, sle_count", [ - ({'mealplan_autoadd_shopping': False}, (0, 17)), - ({'mealplan_autoinclude_related': False}, (8, 8)), - ({'mealplan_autoexclude_onhand': False}, (19, 19)), - ({'mealplan_autoexclude_onhand': False, 'mealplan_autoinclude_related': False}, (9, 9)), + ({'mealplan_autoadd_shopping': False}, (0, 18)), + ({'mealplan_autoinclude_related': False}, (9, 9)), + ({'mealplan_autoexclude_onhand': False}, (20, 20)), + ({'mealplan_autoexclude_onhand': False, 'mealplan_autoinclude_related': False}, (10, 10)), ], indirect=['user2']) @pytest.mark.parametrize("use_mealplan", [(False), (True), ]) @pytest.mark.parametrize("recipe", [({'steps__recipe_count': 1})], indirect=['recipe']) def test_shopping_recipe_userpreference(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, 2 food onhand(from recipe and step_recipe), 1 food ignore shopping + # setup recipe with 10 ingredients, 1 step recipe with 10 ingredients, 2 food onhand(from recipe and step_recipe) ingredients = Ingredient.objects.filter(step__recipe=recipe) food = Food.objects.get(id=ingredients[2].food.id) - food.on_hand = True + food.food_onhand = True food.save() food = recipe.steps.filter(type=Step.RECIPE).first().step_recipe.steps.first().ingredients.first().food food = Food.objects.get(id=food.id) - food.on_hand = True - food.save() - food = Food.objects.get(id=ingredients[4].food.id) - food.ignore_shopping = True + food.food_onhand = True food.save() if use_mealplan: diff --git a/vue/src/apps/ModelListView/ModelListView.vue b/vue/src/apps/ModelListView/ModelListView.vue index 92420b01..d889267c 100644 --- a/vue/src/apps/ModelListView/ModelListView.vue +++ b/vue/src/apps/ModelListView/ModelListView.vue @@ -19,8 +19,10 @@ {{ this.this_model.name }} - + + + @@ -112,6 +114,9 @@ export default { // TODO this is not necessarily bad but maybe there are better options to do this return () => import(/* webpackChunkName: "header-component" */ `@/components/${this.header_component_name}`) }, + apiName() { + return this.this_model?.apiName + }, }, mounted() { // value is passed from lists.py @@ -291,11 +296,6 @@ export default { this.refreshCard({ ...food }, this.items_right) }) }, - addOnhand: function (item) { - item.on_hand = true - this.saveThis(item) - }, - updateThis: function (item) { this.refreshThis(item.id) }, diff --git a/vue/src/apps/ShoppingListView/ShoppingListView.vue b/vue/src/apps/ShoppingListView/ShoppingListView.vue index 11d43554..762f298f 100644 --- a/vue/src/apps/ShoppingListView/ShoppingListView.vue +++ b/vue/src/apps/ShoppingListView/ShoppingListView.vue @@ -493,15 +493,6 @@ - - {{ $t("IgnoreThis", { food: foodName(contextData) }) }} - - data.map((y) => { @@ -941,10 +925,10 @@ export default { let api = new ApiApiFactory() let food = { id: item?.[0]?.food.id ?? item?.food?.id, - on_hand: true, + food_onhand: true, } - this.updateFood(food) + this.updateFood(food, "food_onhand") .then((result) => { let entries = this.items.filter((x) => x.food.id == food.id).map((x) => x.id) this.items = this.items.filter((x) => x.food.id !== food.id) diff --git a/vue/src/components/Badges.vue b/vue/src/components/Badges.vue index f3599948..3e353d7e 100644 --- a/vue/src/components/Badges.vue +++ b/vue/src/components/Badges.vue @@ -1,52 +1,44 @@ \ No newline at end of file + diff --git a/vue/src/components/Badges/OnHand.vue b/vue/src/components/Badges/OnHand.vue index 9f851af1..7e48294e 100644 --- a/vue/src/components/Badges/OnHand.vue +++ b/vue/src/components/Badges/OnHand.vue @@ -1,7 +1,7 @@ @@ -66,11 +55,10 @@