From dcad389010e10a38e4e76fab6f7dc4ba6f97124c Mon Sep 17 00:00:00 2001 From: Chris Scoggins Date: Wed, 2 Feb 2022 09:53:37 -0600 Subject: [PATCH] food edit modal - reset children inheritance --- cookbook/models.py | 26 ++++++++++++------- cookbook/serializer.py | 8 +++++- .../RecipeSearchView/RecipeSearchView.vue | 1 + .../components/Modals/GenericModalForm.vue | 12 ++++----- vue/src/locales/en.json | 3 ++- vue/src/utils/models.js | 10 ++++++- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/cookbook/models.py b/cookbook/models.py index 8b913c90..c523a232 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -515,31 +515,37 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin): return super().delete() @staticmethod - def reset_inheritance(space=None): + def reset_inheritance(space=None, food=None): # resets inherited fields to the space defaults and updates all inherited fields to root object values - inherit = space.food_inherit.all() + if food: + inherit = list(food.inherit_fields.all().values('id', 'field')) + filter = Q(id=food.id, space=space) + tree_filter = Q(path__startswith=food.path, space=space) + else: + inherit = list(space.food_inherit.all().values('id', 'field')) + filter = tree_filter = Q(space=space) # remove all inherited fields from food - Through = Food.objects.filter(space=space).first().inherit_fields.through + Through = Food.objects.filter(tree_filter).first().inherit_fields.through Through.objects.all().delete() # food is going to inherit attributes - if space.food_inherit.all().count() > 0: + if len(inherit) > 0: # ManyToMany cannot be updated through an UPDATE operation for i in inherit: Through.objects.bulk_create([ - Through(food_id=x, foodinheritfield_id=i.id) - for x in Food.objects.filter(space=space).values_list('id', flat=True) + Through(food_id=x, foodinheritfield_id=i['id']) + for x in Food.objects.filter(tree_filter).values_list('id', flat=True) ]) - inherit = inherit.values_list('field', flat=True) + inherit = [x['field'] for x in inherit] if 'ignore_shopping' 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(Q(depth=1, numchild__gt=0, ignore_shopping=True) & filter)).update(ignore_shopping=True) + Food.include_descendants(queryset=Food.objects.filter(Q(depth=1, numchild__gt=0, ignore_shopping=False) & filter)).update(ignore_shopping=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 - category_roots = Food.exclude_descendants(queryset=Food.objects.filter(supermarket_category__isnull=False, numchild__gt=0, space=space)) + category_roots = Food.exclude_descendants(queryset=Food.objects.filter(Q(supermarket_category__isnull=False, numchild__gt=0) & filter)) for root in category_roots: root.get_descendants().update(supermarket_category=root.supermarket_category) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index a269b372..fd67d25a 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -419,13 +419,19 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR validated_data['name'] = name.strip() # assuming if on hand for user also onhand for shopping_share users onhand = validated_data.get('food_onhand', None) + reset_inherit = self.initial_data.get('reset_inherit', False) if not onhand is None: shared_users = [user := self.context['request'].user] + list(user.userpreference.shopping_share.all()) if onhand: validated_data['onhand_users'] = list(self.instance.onhand_users.all()) + shared_users else: validated_data['onhand_users'] = list(set(self.instance.onhand_users.all()) - set(shared_users)) - return super(FoodSerializer, self).update(instance, validated_data) + + # update before resetting inheritance + saved_instance = super(FoodSerializer, self).update(instance, validated_data) + if reset_inherit and (r := self.context.get('request', None)): + Food.reset_inheritance(food=saved_instance, space=r.space) + return saved_instance class Meta: model = Food diff --git a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue index aae189d1..039b93f1 100644 --- a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue +++ b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue @@ -1029,6 +1029,7 @@ export default { if (!this.searchFiltered()) { params.options.query.last_viewed = this.ui.recently_viewed } + console.log(params) return params }, searchFiltered: function (ignore_string = false) { diff --git a/vue/src/components/Modals/GenericModalForm.vue b/vue/src/components/Modals/GenericModalForm.vue index 47abc2f3..cd372f11 100644 --- a/vue/src/components/Modals/GenericModalForm.vue +++ b/vue/src/components/Modals/GenericModalForm.vue @@ -271,29 +271,27 @@ export default { if (type_match && field?.condition) { const value = this.item1[field?.condition?.field] const preference = getUserPreference(field?.condition?.field) - console.log("condition", field?.condition?.condition) + checks = false switch (field?.condition?.condition) { case "field_exists": if ((value != undefined) === field.condition.value) { checks = true - } else { - checks = false } break case "preference__array_exists": if (preference?.length > 0 === field.condition.value) { checks = true - } else { - checks = false } break case "preference_equals": if (preference === field.condition.value) { checks = true - } else { - checks = false } break + case "gt": + if (value > field.condition.value) { + checks = true + } } } return type_match && checks diff --git a/vue/src/locales/en.json b/vue/src/locales/en.json index 766baff3..4454b401 100644 --- a/vue/src/locales/en.json +++ b/vue/src/locales/en.json @@ -326,5 +326,6 @@ "make_now": "Make Now", "recipe_filter": "Recipe Filter", "book_filter_help": "Include recipes from recipe filter instead of assigning each recipe", - "filter": "Filter" + "reset_children": "Reset Child Inheritance", + "reset_children_help": "Overwrite all children with values from inherited fields." } diff --git a/vue/src/utils/models.js b/vue/src/utils/models.js index c381536f..fa80bce4 100644 --- a/vue/src/utils/models.js +++ b/vue/src/utils/models.js @@ -76,7 +76,7 @@ export class Models { // REQUIRED: unordered array of fields that can be set during create create: { // if not defined partialUpdate will use the same parameters, prepending 'id' - params: [["name", "description", "recipe", "food_onhand", "supermarket_category", "inherit", "inherit_fields", "ignore_shopping"]], + params: [["name", "description", "recipe", "food_onhand", "supermarket_category", "inherit", "inherit_fields", "ignore_shopping", "reset_inherit"]], form: { show_help: true, @@ -135,6 +135,14 @@ export class Models { label: i18n.t("InheritFields"), condition: { field: "food_children_exist", value: true, condition: "preference_equals" }, }, + reset_inherit: { + form_field: true, + type: "checkbox", + field: "reset_inherit", + label: i18n.t("reset_children"), + help_text: i18n.t("reset_children_help"), + condition: { field: "numchild", value: 0, condition: "gt" }, + }, form_function: "FoodCreateDefault", }, },