mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
tests for single food reset inherit and additional inheritted fields
This commit is contained in:
18
cookbook/migrations/0172_food_child_inherit_fields.py
Normal file
18
cookbook/migrations/0172_food_child_inherit_fields.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2.11 on 2022-02-04 17:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0171_auto_20220202_1340'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='child_inherit_fields',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='child_inherit', to='cookbook.FoodInheritField'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -97,13 +97,6 @@ class TreeModel(MP_Node):
|
|||||||
else:
|
else:
|
||||||
return f"{self.name}"
|
return f"{self.name}"
|
||||||
|
|
||||||
# MP_Tree move uses raw SQL to execute move, override behavior to force a save triggering post_save signal
|
|
||||||
def move(self, *args, **kwargs):
|
|
||||||
super().move(*args, **kwargs)
|
|
||||||
# treebeard bypasses ORM, need to retrieve the object again to avoid writing previous state back to disk
|
|
||||||
obj = self.__class__.objects.get(id=self.id)
|
|
||||||
obj.save()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parent(self):
|
def parent(self):
|
||||||
parent = self.get_parent()
|
parent = self.get_parent()
|
||||||
@@ -488,9 +481,9 @@ class Unit(ExportModelOperationsMixin('unit'), models.Model, PermissionModelMixi
|
|||||||
|
|
||||||
|
|
||||||
class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
||||||
# TODO when savings a food as substitute children - assume children and descednats are also substitutes for siblings
|
|
||||||
# exclude fields not implemented yet
|
# exclude fields not implemented yet
|
||||||
inheritable_fields = FoodInheritField.objects.exclude(field__in=['diet', 'substitute', 'substitute_children', 'substitute_siblings'])
|
inheritable_fields = FoodInheritField.objects.exclude(field__in=['diet', 'substitute', ])
|
||||||
|
# TODO add inherit children_inherit, parent_inherit, Do Not Inherit
|
||||||
|
|
||||||
# WARNING: Food inheritance relies on post_save signals, avoid using UPDATE to update Food objects unless you intend to bypass those signals
|
# WARNING: Food inheritance relies on post_save signals, avoid using UPDATE to update Food objects unless you intend to bypass those signals
|
||||||
if SORT_TREE_BY_NAME:
|
if SORT_TREE_BY_NAME:
|
||||||
@@ -505,6 +498,7 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
substitute = models.ManyToManyField("self", blank=True)
|
substitute = models.ManyToManyField("self", blank=True)
|
||||||
substitute_siblings = models.BooleanField(default=False)
|
substitute_siblings = models.BooleanField(default=False)
|
||||||
substitute_children = models.BooleanField(default=False)
|
substitute_children = models.BooleanField(default=False)
|
||||||
|
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space', _manager_class=TreeManager)
|
objects = ScopedManager(space='space', _manager_class=TreeManager)
|
||||||
@@ -518,16 +512,27 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
else:
|
else:
|
||||||
return super().delete()
|
return super().delete()
|
||||||
|
|
||||||
|
# MP_Tree move uses raw SQL to execute move, override behavior to force a save triggering post_save signal
|
||||||
|
|
||||||
|
def move(self, *args, **kwargs):
|
||||||
|
super().move(*args, **kwargs)
|
||||||
|
# treebeard bypasses ORM, need to explicity save to trigger post save signals retrieve the object again to avoid writing previous state back to disk
|
||||||
|
obj = self.__class__.objects.get(id=self.id)
|
||||||
|
if parent := obj.get_parent():
|
||||||
|
# child should inherit what the parent defines it should inherit
|
||||||
|
obj.inherit_fields.set(list(parent.child_inherit_fields.all() or parent.inherit_fields.all()))
|
||||||
|
obj.save()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reset_inheritance(space=None, food=None):
|
def reset_inheritance(space=None, food=None):
|
||||||
# resets inherited fields to the space defaults and updates all inherited fields to root object values
|
# resets inherited fields to the space defaults and updates all inherited fields to root object values
|
||||||
if food:
|
if food:
|
||||||
inherit = list(food.inherit_fields.all().values('id', 'field'))
|
# if child inherit fields is preset children should be set to that, otherwise inherit this foods inherited fields
|
||||||
filter = Q(id=food.id, space=space)
|
inherit = list((food.child_inherit_fields.all() or food.inherit_fields.all()).values('id', 'field'))
|
||||||
tree_filter = Q(path__startswith=food.path, space=space)
|
tree_filter = Q(path__startswith=food.path, space=space, depth=food.depth+1)
|
||||||
else:
|
else:
|
||||||
inherit = list(space.food_inherit.all().values('id', 'field'))
|
inherit = list(space.food_inherit.all().values('id', 'field'))
|
||||||
filter = tree_filter = Q(space=space)
|
tree_filter = Q(space=space)
|
||||||
|
|
||||||
# remove all inherited fields from food
|
# remove all inherited fields from food
|
||||||
Through = Food.objects.filter(tree_filter).first().inherit_fields.through
|
Through = Food.objects.filter(tree_filter).first().inherit_fields.through
|
||||||
@@ -542,16 +547,26 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
])
|
])
|
||||||
|
|
||||||
inherit = [x['field'] for x in inherit]
|
inherit = [x['field'] for x in inherit]
|
||||||
if 'ignore_shopping' in inherit:
|
for field in ['ignore_shopping', 'substitute_children', 'substitute_siblings']:
|
||||||
# get food at root that have children that need updated
|
if field in inherit:
|
||||||
Food.include_descendants(queryset=Food.objects.filter(Q(depth=1, numchild__gt=0, ignore_shopping=True) & filter)).update(ignore_shopping=True)
|
if food and getattr(food, field, None):
|
||||||
Food.include_descendants(queryset=Food.objects.filter(Q(depth=1, numchild__gt=0, ignore_shopping=False) & filter)).update(ignore_shopping=False)
|
food.get_descendants().update(**{f"{field}": True})
|
||||||
|
elif food and not getattr(food, field, True):
|
||||||
|
food.get_descendants().update(**{f"{field}": False})
|
||||||
|
else:
|
||||||
|
# get food at root that have children that need updated
|
||||||
|
Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, **{f"{field}": True}, space=space)).update(**{f"{field}": True})
|
||||||
|
Food.include_descendants(queryset=Food.objects.filter(depth=1, numchild__gt=0, **{f"{field}": False}, space=space)).update(**{f"{field}": False})
|
||||||
|
|
||||||
if 'supermarket_category' in inherit:
|
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
|
# 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
|
if food and food.supermarket_category:
|
||||||
category_roots = Food.exclude_descendants(queryset=Food.objects.filter(Q(supermarket_category__isnull=False, numchild__gt=0) & filter))
|
food.get_descendants().update(supermarket_category=food.supermarket_category)
|
||||||
for root in category_roots:
|
elif food is None:
|
||||||
root.get_descendants().update(supermarket_category=root.supermarket_category)
|
# 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))
|
||||||
|
for root in category_roots:
|
||||||
|
root.get_descendants().update(supermarket_category=root.supermarket_category)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
# shopping = serializers.SerializerMethodField('get_shopping_status')
|
# shopping = serializers.SerializerMethodField('get_shopping_status')
|
||||||
shopping = serializers.ReadOnlyField(source='shopping_status')
|
shopping = serializers.ReadOnlyField(source='shopping_status')
|
||||||
inherit_fields = FoodInheritFieldSerializer(many=True, allow_null=True, required=False)
|
inherit_fields = FoodInheritFieldSerializer(many=True, allow_null=True, required=False)
|
||||||
|
child_inherit_fields = FoodInheritFieldSerializer(many=True, allow_null=True, required=False)
|
||||||
food_onhand = CustomOnHandField(required=False, allow_null=True)
|
food_onhand = CustomOnHandField(required=False, allow_null=True)
|
||||||
substitute_onhand = serializers.SerializerMethodField('get_substitute_onhand')
|
substitute_onhand = serializers.SerializerMethodField('get_substitute_onhand')
|
||||||
substitute = FoodSimpleSerializer(many=True, allow_null=True, required=False)
|
substitute = FoodSimpleSerializer(many=True, allow_null=True, required=False)
|
||||||
@@ -461,7 +462,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
fields = (
|
fields = (
|
||||||
'id', 'name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category',
|
'id', 'name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category',
|
||||||
'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping',
|
'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping',
|
||||||
'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand'
|
'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand', 'child_inherit_fields'
|
||||||
)
|
)
|
||||||
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_ps
|
|||||||
'django.db.backends.postgresql']:
|
'django.db.backends.postgresql']:
|
||||||
SQLITE = False
|
SQLITE = False
|
||||||
|
|
||||||
|
|
||||||
# wraps a signal with the ability to set 'skip_signal' to avoid creating recursive signals
|
# wraps a signal with the ability to set 'skip_signal' to avoid creating recursive signals
|
||||||
|
|
||||||
|
|
||||||
def skip_signal(signal_func):
|
def skip_signal(signal_func):
|
||||||
@wraps(signal_func)
|
@wraps(signal_func)
|
||||||
def _decorator(sender, instance, **kwargs):
|
def _decorator(sender, instance, **kwargs):
|
||||||
@@ -76,8 +75,9 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs):
|
|||||||
# apply changes from parent to instance for each inherited field
|
# apply changes from parent to instance for each inherited field
|
||||||
if instance.parent and inherit.count() > 0:
|
if instance.parent and inherit.count() > 0:
|
||||||
parent = instance.get_parent()
|
parent = instance.get_parent()
|
||||||
if 'ignore_shopping' in inherit:
|
for field in ['ignore_shopping', 'substitute_children', 'substitute_siblings']:
|
||||||
instance.ignore_shopping = parent.ignore_shopping
|
if field in inherit:
|
||||||
|
setattr(instance, field, getattr(parent, field, None))
|
||||||
# if supermarket_category is not set, do not cascade - if this becomes non-intuitive can change
|
# 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:
|
if 'supermarket_category' in inherit and parent.supermarket_category:
|
||||||
instance.supermarket_category = parent.supermarket_category
|
instance.supermarket_category = parent.supermarket_category
|
||||||
@@ -87,19 +87,17 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs):
|
|||||||
finally:
|
finally:
|
||||||
del instance.skip_signal
|
del instance.skip_signal
|
||||||
|
|
||||||
# TODO figure out how to generalize this
|
|
||||||
# apply changes to direct children - depend on save signals for those objects to cascade inheritance down
|
# 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_fields__in=Food.inheritable_fields):
|
||||||
for child in instance.get_children().filter(inherit_fields__field='ignore_shopping'):
|
# set inherited field values
|
||||||
child.ignore_shopping = instance.ignore_shopping
|
for field in (inherit_fields := ['ignore_shopping', 'substitute_children', 'substitute_siblings']):
|
||||||
_save.append(child)
|
if field in instance.inherit_fields.values_list('field', flat=True):
|
||||||
# don't cascade empty supermarket category
|
setattr(child, field, getattr(instance, field, None))
|
||||||
if instance.supermarket_category:
|
|
||||||
# apply changes to direct children - depend on save signals for those objects to cascade inheritance down
|
# don't cascade empty supermarket category
|
||||||
for child in instance.get_children().filter(inherit_fields__field='supermarket_category'):
|
if instance.supermarket_category and 'supermarket_category' in inherit_fields:
|
||||||
child.supermarket_category = instance.supermarket_category
|
setattr(child, 'supermarket_category', getattr(instance, 'supermarket_category', None))
|
||||||
_save.append(child)
|
|
||||||
for child in set(_save):
|
|
||||||
child.save()
|
child.save()
|
||||||
|
|
||||||
|
|
||||||
@@ -117,19 +115,9 @@ def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs
|
|||||||
if instance.servings != x.servings:
|
if instance.servings != x.servings:
|
||||||
SLR = RecipeShoppingEditor(id=x.id, user=user, space=instance.space)
|
SLR = RecipeShoppingEditor(id=x.id, user=user, space=instance.space)
|
||||||
SLR.edit_servings(servings=instance.servings)
|
SLR.edit_servings(servings=instance.servings)
|
||||||
# list_recipe = list_from_recipe(list_recipe=x, servings=instance.servings, space=instance.space)
|
|
||||||
elif not user.userpreference.mealplan_autoadd_shopping or not instance.recipe:
|
elif not user.userpreference.mealplan_autoadd_shopping or not instance.recipe:
|
||||||
return
|
return
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
# if creating a mealplan - perform shopping list activities
|
|
||||||
# kwargs = {
|
|
||||||
# 'mealplan': instance,
|
|
||||||
# 'space': instance.space,
|
|
||||||
# 'created_by': user,
|
|
||||||
# 'servings': instance.servings
|
|
||||||
# }
|
|
||||||
SLR = RecipeShoppingEditor(user=user, space=instance.space)
|
SLR = RecipeShoppingEditor(user=user, space=instance.space)
|
||||||
SLR.create(mealplan=instance, servings=instance.servings)
|
SLR.create(mealplan=instance, servings=instance.servings)
|
||||||
|
|
||||||
# list_recipe = list_from_recipe(**kwargs)
|
|
||||||
|
|||||||
@@ -485,6 +485,10 @@ def test_tree_filter(obj_tree_1, obj_2, obj_3, u1_s1):
|
|||||||
({'has_category': True, 'inherit': False}, 'supermarket_category', False, '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': True}, 'ignore_shopping', True, 'false'),
|
||||||
({'ignore_shopping': True, 'inherit': False}, 'ignore_shopping', False, 'false'),
|
({'ignore_shopping': True, 'inherit': False}, 'ignore_shopping', False, 'false'),
|
||||||
|
({'substitute_children': True, 'inherit': True}, 'substitute_children', True, 'false'),
|
||||||
|
({'substitute_children': True, 'inherit': False}, 'substitute_children', False, 'false'),
|
||||||
|
({'substitute_siblings': True, 'inherit': True}, 'substitute_siblings', True, 'false'),
|
||||||
|
({'substitute_siblings': True, 'inherit': False}, 'substitute_siblings', False, 'false'),
|
||||||
], indirect=['obj_tree_1']) # indirect=True populates magic variable request.param of obj_tree_1 with the parameter
|
], 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):
|
def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
||||||
with scope(space=obj_tree_1.space):
|
with scope(space=obj_tree_1.space):
|
||||||
@@ -507,28 +511,42 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
|||||||
assert (getattr(obj_tree_1, field) == new_val) == inherit
|
assert (getattr(obj_tree_1, field) == new_val) == inherit
|
||||||
assert (getattr(child, field) == new_val) == inherit
|
assert (getattr(child, field) == new_val) == inherit
|
||||||
|
|
||||||
|
# TODO add test_inherit with child_inherit
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("obj_tree_1", [
|
@pytest.mark.parametrize("obj_tree_1", [
|
||||||
({'has_category': True, 'inherit': False, 'ignore_shopping': True}),
|
({'has_category': True, 'inherit': False, 'ignore_shopping': True, 'substitute_children': True, 'substitute_siblings': True}),
|
||||||
], indirect=['obj_tree_1'])
|
], indirect=['obj_tree_1'])
|
||||||
def test_reset_inherit(obj_tree_1, space_1):
|
@pytest.mark.parametrize("global_reset", [True, False])
|
||||||
|
@pytest.mark.parametrize("field", ['ignore_shopping', 'substitute_children', 'substitute_siblings', 'supermarket_category'])
|
||||||
|
def test_reset_inherit_space_fields(obj_tree_1, space_1, global_reset, field):
|
||||||
with scope(space=space_1):
|
with scope(space=space_1):
|
||||||
space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields
|
|
||||||
parent = obj_tree_1.get_parent()
|
parent = obj_tree_1.get_parent()
|
||||||
child = obj_tree_1.get_descendants()[0]
|
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
|
|
||||||
assert parent.supermarket_category != child.supermarket_category
|
|
||||||
assert parent.supermarket_category != obj_tree_1.supermarket_category
|
|
||||||
|
|
||||||
parent.reset_inheritance(space=space_1)
|
if field == 'supermarket_category':
|
||||||
|
assert parent.supermarket_category != child.supermarket_category
|
||||||
|
assert parent.supermarket_category != obj_tree_1.supermarket_category
|
||||||
|
else:
|
||||||
|
setattr(obj_tree_1, field, False)
|
||||||
|
obj_tree_1.save()
|
||||||
|
assert getattr(parent, field) == getattr(child, field)
|
||||||
|
assert getattr(parent, field) != getattr(obj_tree_1, field)
|
||||||
|
|
||||||
|
if global_reset:
|
||||||
|
space_1.food_inherit.add(*Food.inheritable_fields.values_list('id', flat=True)) # set default inherit fields
|
||||||
|
parent.reset_inheritance(space=space_1)
|
||||||
|
else:
|
||||||
|
obj_tree_1.child_inherit_fields.set(Food.inheritable_fields.values_list('id', flat=True))
|
||||||
|
obj_tree_1.save()
|
||||||
|
parent.reset_inheritance(space=space_1, food=obj_tree_1)
|
||||||
# djangotree bypasses ORM and need to be retrieved again
|
# djangotree bypasses ORM and need to be retrieved again
|
||||||
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
obj_tree_1 = Food.objects.get(id=obj_tree_1.id)
|
||||||
parent = obj_tree_1.get_parent()
|
parent = Food.objects.get(id=parent.id)
|
||||||
child = obj_tree_1.get_descendants()[0]
|
child = Food.objects.get(id=child.id)
|
||||||
assert parent.ignore_shopping == obj_tree_1.ignore_shopping == child.ignore_shopping
|
|
||||||
assert parent.supermarket_category == obj_tree_1.supermarket_category == child.supermarket_category
|
assert (getattr(parent, field) == getattr(obj_tree_1, field)) == global_reset
|
||||||
|
assert getattr(obj_tree_1, field) == getattr(child, field)
|
||||||
|
|
||||||
|
|
||||||
def test_onhand(obj_1, u1_s1, u2_s1):
|
def test_onhand(obj_1, u1_s1, u2_s1):
|
||||||
|
|||||||
@@ -328,11 +328,14 @@
|
|||||||
"view_recipe": "View Recipe",
|
"view_recipe": "View Recipe",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"reset_children": "Reset Child Inheritance",
|
"reset_children": "Reset Child Inheritance",
|
||||||
"reset_children_help": "Overwrite all children with values from inherited fields.",
|
"reset_children_help": "Overwrite all children with values from inherited fields. Inheritted fields of children will be set to Inherit Fields unless Children Inherit Fields is set.",
|
||||||
"substitute_help": "Substitutes are considered when searching for recipes that can be made with onhand ingredients.",
|
"substitute_help": "Substitutes are considered when searching for recipes that can be made with onhand ingredients.",
|
||||||
"substitute_siblings_help": "All food that share a parent of this food are considered substitutes.",
|
"substitute_siblings_help": "All food that share a parent of this food are considered substitutes.",
|
||||||
"substitute_children_help": "All food that are children of this food are considered substitutes.",
|
"substitute_children_help": "All food that are children of this food are considered substitutes.",
|
||||||
"substitute_siblings": "Substitute Siblings",
|
"substitute_siblings": "Substitute Siblings",
|
||||||
"substitute_children": "Substitute Children",
|
"substitute_children": "Substitute Children",
|
||||||
"SubstituteOnHand": "You have a substitute on hand."
|
"SubstituteOnHand": "You have a substitute on hand.",
|
||||||
|
"ChildInheritFields": "Children Inherit Fields",
|
||||||
|
"ChildInheritFields_help": "Children will inherit these fields by default.",
|
||||||
|
"InheritFields_help": "The values of these fields will be inheritted from parent (Exception: blank shopping categories are not inheritted)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export class Models {
|
|||||||
"substitute_siblings",
|
"substitute_siblings",
|
||||||
"substitute_children",
|
"substitute_children",
|
||||||
"reset_inherit",
|
"reset_inherit",
|
||||||
|
"child_inherit_fields",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -179,6 +180,18 @@ export class Models {
|
|||||||
list: "FOOD_INHERIT_FIELDS",
|
list: "FOOD_INHERIT_FIELDS",
|
||||||
label: i18n.t("InheritFields"),
|
label: i18n.t("InheritFields"),
|
||||||
condition: { field: "food_children_exist", value: true, condition: "preference_equals" },
|
condition: { field: "food_children_exist", value: true, condition: "preference_equals" },
|
||||||
|
help_text: i18n.t("InheritFields_help"),
|
||||||
|
},
|
||||||
|
child_inherit_fields: {
|
||||||
|
form_field: true,
|
||||||
|
advanced: true,
|
||||||
|
type: "lookup",
|
||||||
|
multiple: true,
|
||||||
|
field: "child_inherit_fields",
|
||||||
|
list: "FOOD_INHERIT_FIELDS",
|
||||||
|
label: i18n.t("ChildInheritFields"),
|
||||||
|
condition: { field: "numchild", value: 0, condition: "gt" },
|
||||||
|
help_text: i18n.t("ChildInheritFields_help"),
|
||||||
},
|
},
|
||||||
reset_inherit: {
|
reset_inherit: {
|
||||||
form_field: true,
|
form_field: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user