properties structure imporioved
This commit is contained in:
parent
2a538abf80
commit
3302dacdc3
@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField
|
|||||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
||||||
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
||||||
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace, UnitConversion, PropertyType, FoodProperty, RecipeProperty)
|
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace, UnitConversion, PropertyType, Property)
|
||||||
|
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
@ -334,18 +334,11 @@ class PropertyTypeAdmin(admin.ModelAdmin):
|
|||||||
admin.site.register(PropertyType, PropertyTypeAdmin)
|
admin.site.register(PropertyType, PropertyTypeAdmin)
|
||||||
|
|
||||||
|
|
||||||
class FoodPropertyAdmin(admin.ModelAdmin):
|
class PropertyAdmin(admin.ModelAdmin):
|
||||||
list_display = ('id', 'food_amount', 'food_unit', 'food', 'property_amount', 'property_type')
|
list_display = ('property_amount', 'property_type')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(FoodProperty, FoodPropertyAdmin)
|
admin.site.register(Property, PropertyAdmin)
|
||||||
|
|
||||||
|
|
||||||
class RecipePropertyAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('id', 'property_type', 'property_amount',)
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(RecipeProperty, RecipePropertyAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
class NutritionInformationAdmin(admin.ModelAdmin):
|
class NutritionInformationAdmin(admin.ModelAdmin):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from cookbook.models import Unit, SupermarketCategory, FoodProperty, PropertyType, Supermarket, SupermarketCategoryRelation, Food, Automation, UnitConversion
|
from cookbook.models import Unit, SupermarketCategory, Property, PropertyType, Supermarket, SupermarketCategoryRelation, Food, Automation, UnitConversion
|
||||||
|
|
||||||
|
|
||||||
class OpenDataImporter:
|
class OpenDataImporter:
|
||||||
@ -169,10 +169,7 @@ class OpenDataImporter:
|
|||||||
alias_list = []
|
alias_list = []
|
||||||
for k in list(self.data[datatype].keys()):
|
for k in list(self.data[datatype].keys()):
|
||||||
for fp in self.data[datatype][k]['properties']['type_values']:
|
for fp in self.data[datatype][k]['properties']['type_values']:
|
||||||
food_property_list.append(FoodProperty(
|
food_property_list.append(Property(
|
||||||
food_id=self.slug_id_cache['food'][k],
|
|
||||||
food_amount=self.data[datatype][k]['properties']['food_amount'],
|
|
||||||
food_unit_id=self.slug_id_cache['unit'][self.data[datatype][k]['properties']['food_unit']],
|
|
||||||
property_type_id=self.slug_id_cache['property'][fp['property_type']],
|
property_type_id=self.slug_id_cache['property'][fp['property_type']],
|
||||||
property_amount=fp['property_value'],
|
property_amount=fp['property_value'],
|
||||||
space=self.request.space,
|
space=self.request.space,
|
||||||
@ -186,7 +183,7 @@ class OpenDataImporter:
|
|||||||
created_by=self.request.user,
|
created_by=self.request.user,
|
||||||
))
|
))
|
||||||
|
|
||||||
FoodProperty.objects.bulk_create(food_property_list, ignore_conflicts=True, unique_fields=('space', 'food', 'property_type',))
|
Property.objects.bulk_create(food_property_list, ignore_conflicts=True, unique_fields=('space', 'food', 'property_type',))
|
||||||
Automation.objects.bulk_create(alias_list, ignore_conflicts=True, unique_fields=('space', 'param_1', 'param_2',))
|
Automation.objects.bulk_create(alias_list, ignore_conflicts=True, unique_fields=('space', 'param_1', 'param_2',))
|
||||||
return insert_list + update_list
|
return insert_list + update_list
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from django.core.cache import caches
|
|||||||
|
|
||||||
from cookbook.helper.cache_helper import CacheHelper
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
from cookbook.helper.unit_conversion_helper import UnitConversionHelper
|
from cookbook.helper.unit_conversion_helper import UnitConversionHelper
|
||||||
from cookbook.models import PropertyType, Unit, Food, FoodProperty, Recipe, Step
|
from cookbook.models import PropertyType, Unit, Food, Property, Recipe, Step
|
||||||
|
|
||||||
|
|
||||||
class FoodPropertyHelper:
|
class FoodPropertyHelper:
|
||||||
@ -42,13 +42,13 @@ class FoodPropertyHelper:
|
|||||||
conversions = uch.get_conversions(i)
|
conversions = uch.get_conversions(i)
|
||||||
for pt in property_types:
|
for pt in property_types:
|
||||||
found_property = False
|
found_property = False
|
||||||
for p in i.food.foodproperty_set.all():
|
for p in i.food.properties.all():
|
||||||
if p.property_type == pt:
|
if p.property_type == pt:
|
||||||
for c in conversions:
|
for c in conversions:
|
||||||
if c.unit == p.food_unit:
|
if c.unit == i.food.properties_food_unit:
|
||||||
found_property = True
|
found_property = True
|
||||||
computed_properties[pt.id]['total_value'] += (c.amount / p.food_amount) * p.property_amount
|
computed_properties[pt.id]['total_value'] += (c.amount / i.food.properties_food_amount) * p.property_amount
|
||||||
computed_properties[pt.id]['food_values'] = self.add_or_create(computed_properties[p.property_type.id]['food_values'], c.food.id, (c.amount / p.food_amount) * p.property_amount, c.food)
|
computed_properties[pt.id]['food_values'] = self.add_or_create(computed_properties[p.property_type.id]['food_values'], c.food.id, (c.amount / i.food.properties_food_amount) * p.property_amount, c.food)
|
||||||
if not found_property:
|
if not found_property:
|
||||||
computed_properties[pt.id]['missing_value'] = True
|
computed_properties[pt.id]['missing_value'] = True
|
||||||
computed_properties[pt.id]['food_values'][i.food.id] = {'id': i.food.id, 'food': i.food.name, 'value': 0}
|
computed_properties[pt.id]['food_values'][i.food.id] = {'id': i.food.id, 'food': i.food.name, 'value': 0}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.1.7 on 2023-05-06 19:16
|
# Generated by Django 4.1.9 on 2023-05-25 13:05
|
||||||
|
|
||||||
import cookbook.models
|
import cookbook.models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -16,10 +16,9 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='FoodProperty',
|
name='Property',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('food_amount', models.DecimalField(decimal_places=2, default=0, max_digits=32)),
|
|
||||||
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
|
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
|
||||||
],
|
],
|
||||||
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||||
@ -37,14 +36,6 @@ class Migration(migrations.Migration):
|
|||||||
],
|
],
|
||||||
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='RecipeProperty',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
|
|
||||||
],
|
|
||||||
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='UnitConversion',
|
name='UnitConversion',
|
||||||
fields=[
|
fields=[
|
||||||
@ -77,6 +68,16 @@ class Migration(migrations.Migration):
|
|||||||
name='preferred_unit',
|
name='preferred_unit',
|
||||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties_food_amount',
|
||||||
|
field=models.IntegerField(blank=True, default=100),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties_food_unit',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='cookbook.unit'),
|
||||||
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='supermarket',
|
model_name='supermarket',
|
||||||
name='open_data_slug',
|
name='open_data_slug',
|
||||||
@ -126,45 +127,30 @@ class Migration(migrations.Migration):
|
|||||||
name='space',
|
name='space',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='recipeproperty',
|
|
||||||
name='property_type',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='recipeproperty',
|
|
||||||
name='space',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='propertytype',
|
model_name='propertytype',
|
||||||
name='space',
|
name='space',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='foodproperty',
|
model_name='property',
|
||||||
name='food',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.food'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='foodproperty',
|
|
||||||
name='food_unit',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.unit'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='foodproperty',
|
|
||||||
name='property_type',
|
name='property_type',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='foodproperty',
|
model_name='property',
|
||||||
name='space',
|
name='space',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties',
|
||||||
|
field=models.ManyToManyField(blank=True, to='cookbook.property'),
|
||||||
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='recipe',
|
model_name='recipe',
|
||||||
name='properties',
|
name='properties',
|
||||||
field=models.ManyToManyField(blank=True, to='cookbook.recipeproperty'),
|
field=models.ManyToManyField(blank=True, to='cookbook.property'),
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.AddConstraint(
|
||||||
model_name='unitconversion',
|
model_name='unitconversion',
|
||||||
@ -174,8 +160,4 @@ class Migration(migrations.Migration):
|
|||||||
model_name='propertytype',
|
model_name='propertytype',
|
||||||
constraint=models.UniqueConstraint(fields=('space', 'name'), name='property_type_unique_name_per_space'),
|
constraint=models.UniqueConstraint(fields=('space', 'name'), name='property_type_unique_name_per_space'),
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
|
||||||
model_name='foodproperty',
|
|
||||||
constraint=models.UniqueConstraint(fields=('food', 'property_type', 'space'), name='food_property_unique_per_space'),
|
|
||||||
),
|
|
||||||
]
|
]
|
@ -1,15 +1,14 @@
|
|||||||
# Generated by Django 4.1.7 on 2023-05-06 20:39
|
# Generated by Django 4.1.9 on 2023-05-25 13:06
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
|
||||||
def migrate_old_nutrition_data(apps, schema_editor):
|
def migrate_old_nutrition_data(apps, schema_editor):
|
||||||
print('Transforming nutrition information, this might take a while on large databases')
|
print('Transforming nutrition information, this might take a while on large databases')
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
PropertyType = apps.get_model('cookbook', 'PropertyType')
|
PropertyType = apps.get_model('cookbook', 'PropertyType')
|
||||||
RecipeProperty = apps.get_model('cookbook', 'RecipeProperty')
|
RecipeProperty = apps.get_model('cookbook', 'Property')
|
||||||
Recipe = apps.get_model('cookbook', 'Recipe')
|
Recipe = apps.get_model('cookbook', 'Recipe')
|
||||||
Space = apps.get_model('cookbook', 'Space')
|
Space = apps.get_model('cookbook', 'Space')
|
||||||
|
|
||||||
@ -28,11 +27,10 @@ def migrate_old_nutrition_data(apps, schema_editor):
|
|||||||
r.properties.add(rp_fat, rp_carbohydrates, rp_proteins, rp_calories)
|
r.properties.add(rp_fat, rp_carbohydrates, rp_proteins, rp_calories)
|
||||||
r.nutrition = None
|
r.nutrition = None
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('cookbook', '0189_foodproperty_propertytype_recipeproperty_and_more'),
|
('cookbook', '0189_property_propertytype_unitconversion_food_fdc_id_and_more'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
@ -579,6 +579,10 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
substitute_children = models.BooleanField(default=False)
|
substitute_children = models.BooleanField(default=False)
|
||||||
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
|
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
|
||||||
|
|
||||||
|
properties = models.ManyToManyField("Property", blank=True)
|
||||||
|
properties_food_amount = models.IntegerField(default=100, blank=True)
|
||||||
|
properties_food_unit = models.ForeignKey(Unit, on_delete=models.PROTECT, blank=True, null=True)
|
||||||
|
|
||||||
preferred_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_unit')
|
preferred_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_unit')
|
||||||
preferred_shopping_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_shopping_unit')
|
preferred_shopping_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_shopping_unit')
|
||||||
fdc_id = models.CharField(max_length=128, null=True, blank=True, default=None)
|
fdc_id = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
@ -787,26 +791,7 @@ class PropertyType(models.Model, PermissionModelMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class FoodProperty(models.Model, PermissionModelMixin):
|
class Property(models.Model, PermissionModelMixin):
|
||||||
food_amount = models.DecimalField(default=0, decimal_places=2, max_digits=32)
|
|
||||||
food_unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
|
|
||||||
food = models.ForeignKey(Food, on_delete=models.CASCADE)
|
|
||||||
property_amount = models.DecimalField(default=0, decimal_places=4, max_digits=32)
|
|
||||||
property_type = models.ForeignKey(PropertyType, on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
|
||||||
objects = ScopedManager(space='space')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'{self.food_amount} {self.food_unit} {self.food}: {self.property_amount} {self.property_type.unit} {self.property_type.name}'
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
constraints = [
|
|
||||||
models.UniqueConstraint(fields=['food', 'property_type', 'space'], name='food_property_unique_per_space')
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class RecipeProperty(models.Model, PermissionModelMixin):
|
|
||||||
property_amount = models.DecimalField(default=0, decimal_places=4, max_digits=32)
|
property_amount = models.DecimalField(default=0, decimal_places=4, max_digits=32)
|
||||||
property_type = models.ForeignKey(PropertyType, on_delete=models.PROTECT)
|
property_type = models.ForeignKey(PropertyType, on_delete=models.PROTECT)
|
||||||
|
|
||||||
@ -855,7 +840,7 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
|
|||||||
waiting_time = models.IntegerField(default=0)
|
waiting_time = models.IntegerField(default=0)
|
||||||
internal = models.BooleanField(default=False)
|
internal = models.BooleanField(default=False)
|
||||||
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
||||||
properties = models.ManyToManyField(RecipeProperty, blank=True)
|
properties = models.ManyToManyField(Property, blank=True)
|
||||||
show_ingredient_overview = models.BooleanField(default=True)
|
show_ingredient_overview = models.BooleanField(default=True)
|
||||||
private = models.BooleanField(default=False)
|
private = models.BooleanField(default=False)
|
||||||
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
||||||
|
@ -32,8 +32,8 @@ from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Cu
|
|||||||
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
||||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, FoodProperty,
|
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, Property,
|
||||||
PropertyType, RecipeProperty)
|
PropertyType, Property)
|
||||||
from cookbook.templatetags.custom_tags import markdown
|
from cookbook.templatetags.custom_tags import markdown
|
||||||
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
||||||
|
|
||||||
@ -502,6 +502,36 @@ class SupermarketSerializer(UniqueFieldsMixin, SpacedModelSerializer):
|
|||||||
fields = ('id', 'name', 'description', 'category_to_supermarket', 'open_data_slug')
|
fields = ('id', 'name', 'description', 'category_to_supermarket', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTypeSerializer(serializers.ModelSerializer):
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
|
|
||||||
|
if property_type := PropertyType.objects.filter(Q(name=validated_data['name'])).first():
|
||||||
|
return property_type
|
||||||
|
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PropertyType
|
||||||
|
fields = ('id', 'name', 'icon', 'unit', 'description', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
|
class PropertySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
||||||
|
property_type = PropertyTypeSerializer()
|
||||||
|
property_amount = CustomDecimalField()
|
||||||
|
|
||||||
|
# TODO prevent updates
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Property
|
||||||
|
fields = ('id', 'property_amount', 'property_type')
|
||||||
|
read_only_fields = ('id',)
|
||||||
|
|
||||||
|
|
||||||
class RecipeSimpleSerializer(WritableNestedModelSerializer):
|
class RecipeSimpleSerializer(WritableNestedModelSerializer):
|
||||||
url = serializers.SerializerMethodField('get_url')
|
url = serializers.SerializerMethodField('get_url')
|
||||||
|
|
||||||
@ -538,6 +568,9 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
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)
|
||||||
|
|
||||||
|
properties = PropertySerializer(many=True, allow_null=True, required=False)
|
||||||
|
properties_food_unit = UnitSerializer(allow_null=True, required=False)
|
||||||
|
|
||||||
recipe_filter = 'steps__ingredients__food'
|
recipe_filter = 'steps__ingredients__food'
|
||||||
images = ['recipe__image']
|
images = ['recipe__image']
|
||||||
|
|
||||||
@ -569,7 +602,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
# return ShoppingListEntry.objects.filter(space=obj.space, food=obj, checked=False).count() > 0
|
# return ShoppingListEntry.objects.filter(space=obj.space, food=obj, checked=False).count() > 0
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
name = validated_data.pop('name').strip()
|
name = validated_data['name'].strip()
|
||||||
|
|
||||||
if plural_name := validated_data.pop('plural_name', None):
|
if plural_name := validated_data.pop('plural_name', None):
|
||||||
plural_name = plural_name.strip()
|
plural_name = plural_name.strip()
|
||||||
@ -629,7 +662,9 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Food
|
model = Food
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'name', 'plural_name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category',
|
'id', 'name', 'plural_name', 'description', 'shopping', 'recipe',
|
||||||
|
'properties', 'properties_food_amount', 'properties_food_unit',
|
||||||
|
'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', 'child_inherit_fields', 'open_data_slug',
|
'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand', 'child_inherit_fields', 'open_data_slug',
|
||||||
)
|
)
|
||||||
@ -751,53 +786,6 @@ class UnitConversionSerializer(WritableNestedModelSerializer):
|
|||||||
fields = ('id', 'name', 'base_amount', 'base_unit', 'converted_amount', 'converted_unit', 'food', 'open_data_slug')
|
fields = ('id', 'name', 'base_amount', 'base_unit', 'converted_amount', 'converted_unit', 'food', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
class PropertyTypeSerializer(serializers.ModelSerializer):
|
|
||||||
def create(self, validated_data):
|
|
||||||
validated_data['space'] = self.context['request'].space
|
|
||||||
|
|
||||||
if property_type := PropertyType.objects.filter(Q(name=validated_data['name']) ).first():
|
|
||||||
return property_type
|
|
||||||
|
|
||||||
return super().create(validated_data)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = PropertyType
|
|
||||||
fields = ('id', 'name', 'icon', 'unit', 'description', 'open_data_slug')
|
|
||||||
|
|
||||||
|
|
||||||
class FoodPropertySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
|
||||||
property_type = PropertyTypeSerializer()
|
|
||||||
food = FoodSimpleSerializer()
|
|
||||||
food_unit = UnitSerializer()
|
|
||||||
food_amount = CustomDecimalField()
|
|
||||||
property_amount = CustomDecimalField()
|
|
||||||
|
|
||||||
# TODO prevent updates
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
validated_data['space'] = self.context['request'].space
|
|
||||||
return super().create(validated_data)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = FoodProperty
|
|
||||||
fields = ('id', 'food_amount', 'food_unit', 'food', 'property_amount', 'property_type')
|
|
||||||
read_only_fields = ('id',)
|
|
||||||
|
|
||||||
|
|
||||||
class RecipePropertySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
|
||||||
property_type = PropertyTypeSerializer()
|
|
||||||
property_amount = CustomDecimalField()
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
validated_data['space'] = self.context['request'].space
|
|
||||||
return super().create(validated_data)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = RecipeProperty
|
|
||||||
fields = ('id', 'property_type', 'property_amount',)
|
|
||||||
read_only_fields = ('id',)
|
|
||||||
|
|
||||||
|
|
||||||
class NutritionInformationSerializer(serializers.ModelSerializer):
|
class NutritionInformationSerializer(serializers.ModelSerializer):
|
||||||
carbohydrates = CustomDecimalField()
|
carbohydrates = CustomDecimalField()
|
||||||
fats = CustomDecimalField()
|
fats = CustomDecimalField()
|
||||||
@ -848,7 +836,7 @@ class RecipeOverviewSerializer(RecipeBaseSerializer):
|
|||||||
|
|
||||||
class RecipeSerializer(RecipeBaseSerializer):
|
class RecipeSerializer(RecipeBaseSerializer):
|
||||||
nutrition = NutritionInformationSerializer(allow_null=True, required=False)
|
nutrition = NutritionInformationSerializer(allow_null=True, required=False)
|
||||||
properties = RecipePropertySerializer(many=True, required=False)
|
properties = PropertySerializer(many=True, required=False)
|
||||||
steps = StepSerializer(many=True)
|
steps = StepSerializer(many=True)
|
||||||
keywords = KeywordSerializer(many=True)
|
keywords = KeywordSerializer(many=True)
|
||||||
shared = UserSerializer(many=True, required=False)
|
shared = UserSerializer(many=True, required=False)
|
||||||
|
@ -5,7 +5,7 @@ from decimal import Decimal
|
|||||||
|
|
||||||
from cookbook.helper.cache_helper import CacheHelper
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
from cookbook.helper.property_helper import FoodPropertyHelper
|
from cookbook.helper.property_helper import FoodPropertyHelper
|
||||||
from cookbook.models import Unit, Food, PropertyType, FoodProperty, Recipe, Step, UnitConversion
|
from cookbook.models import Unit, Food, PropertyType, Property, Recipe, Step, UnitConversion, Property
|
||||||
|
|
||||||
|
|
||||||
def test_food_property(space_1, space_2, u1_s1):
|
def test_food_property(space_1, space_2, u1_s1):
|
||||||
@ -17,21 +17,23 @@ def test_food_property(space_1, space_2, u1_s1):
|
|||||||
unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=space_1)
|
unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=space_1)
|
||||||
unit_fantasy = Unit.objects.create(name='Fantasy Unit', base_unit='', space=space_1)
|
unit_fantasy = Unit.objects.create(name='Fantasy Unit', base_unit='', space=space_1)
|
||||||
|
|
||||||
food_1 = Food.objects.create(name='food_1', space=space_1)
|
food_1 = Food.objects.create(name='food_1', space=space_1, properties_food_unit=unit_gram, properties_food_amount=100)
|
||||||
food_2 = Food.objects.create(name='food_2', space=space_1)
|
food_2 = Food.objects.create(name='food_2', space=space_1, properties_food_unit=unit_gram, properties_food_amount=100)
|
||||||
|
|
||||||
property_fat = PropertyType.objects.create(name='property_fat', space=space_1)
|
property_fat = PropertyType.objects.create(name='property_fat', space=space_1)
|
||||||
property_calories = PropertyType.objects.create(name='property_calories', space=space_1)
|
property_calories = PropertyType.objects.create(name='property_calories', space=space_1)
|
||||||
property_nuts = PropertyType.objects.create(name='property_nuts', space=space_1)
|
property_nuts = PropertyType.objects.create(name='property_nuts', space=space_1)
|
||||||
property_price = PropertyType.objects.create(name='property_price', space=space_1)
|
property_price = PropertyType.objects.create(name='property_price', space=space_1)
|
||||||
|
|
||||||
food_1_property_fat = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=50, property_type=property_fat, space=space_1)
|
food_1_property_fat = Property.objects.create(property_amount=50, property_type=property_fat, space=space_1)
|
||||||
food_1_property_nuts = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=1, property_type=property_nuts, space=space_1)
|
food_1_property_nuts = Property.objects.create(property_amount=1, property_type=property_nuts, space=space_1)
|
||||||
food_1_property_price = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=7.50, property_type=property_price, space=space_1)
|
food_1_property_price = Property.objects.create(property_amount=7.50, property_type=property_price, space=space_1)
|
||||||
|
food_1.properties.add(food_1_property_fat, food_1_property_nuts, food_1_property_price)
|
||||||
|
|
||||||
food_2_property_fat = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=25, property_type=property_fat, space=space_1)
|
food_2_property_fat = Property.objects.create(property_amount=25, property_type=property_fat, space=space_1)
|
||||||
food_2_property_nuts = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=0, property_type=property_nuts, space=space_1)
|
food_2_property_nuts = Property.objects.create(property_amount=0, property_type=property_nuts, space=space_1)
|
||||||
food_2_property_price = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=2.50, property_type=property_price, space=space_1)
|
food_2_property_price = Property.objects.create(property_amount=2.50, property_type=property_price, space=space_1)
|
||||||
|
food_2.properties.add(food_2_property_fat, food_2_property_nuts, food_2_property_price)
|
||||||
|
|
||||||
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION MULTI STEP IDENTICAL UNIT ---------------')
|
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION MULTI STEP IDENTICAL UNIT ---------------')
|
||||||
recipe_1 = Recipe.objects.create(name='recipe_1', waiting_time=0, working_time=0, space=space_1, created_by=auth.get_user(u1_s1))
|
recipe_1 = Recipe.objects.create(name='recipe_1', waiting_time=0, working_time=0, space=space_1, created_by=auth.get_user(u1_s1))
|
||||||
|
@ -42,7 +42,7 @@ router.register(r'recipe-book', api.RecipeBookViewSet)
|
|||||||
router.register(r'recipe-book-entry', api.RecipeBookEntryViewSet)
|
router.register(r'recipe-book-entry', api.RecipeBookEntryViewSet)
|
||||||
router.register(r'unit-conversion', api.UnitConversionViewSet)
|
router.register(r'unit-conversion', api.UnitConversionViewSet)
|
||||||
router.register(r'food-property-type', api.PropertyTypeViewSet)
|
router.register(r'food-property-type', api.PropertyTypeViewSet)
|
||||||
router.register(r'food-property', api.FoodPropertyViewSet)
|
router.register(r'food-property', api.PropertyViewSet)
|
||||||
router.register(r'shopping-list', api.ShoppingListViewSet)
|
router.register(r'shopping-list', api.ShoppingListViewSet)
|
||||||
router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet)
|
router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet)
|
||||||
router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
|
router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
|
||||||
|
@ -70,7 +70,7 @@ from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilte
|
|||||||
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, PropertyType, FoodProperty)
|
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, PropertyType, Property)
|
||||||
from cookbook.provider.dropbox import Dropbox
|
from cookbook.provider.dropbox import Dropbox
|
||||||
from cookbook.provider.local import Local
|
from cookbook.provider.local import Local
|
||||||
from cookbook.provider.nextcloud import Nextcloud
|
from cookbook.provider.nextcloud import Nextcloud
|
||||||
@ -94,7 +94,7 @@ from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSeri
|
|||||||
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
||||||
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
||||||
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer,
|
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer,
|
||||||
RecipeExportSerializer, UnitConversionSerializer, PropertyTypeSerializer, FoodPropertySerializer)
|
RecipeExportSerializer, UnitConversionSerializer, PropertyTypeSerializer, PropertySerializer)
|
||||||
from cookbook.views.import_export import get_integration
|
from cookbook.views.import_export import get_integration
|
||||||
from recipes import settings
|
from recipes import settings
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ class MergeMixin(ViewSetMixin):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance(source, Food):
|
if isinstance(source, Food):
|
||||||
FoodProperty.objects.filter(food=source).delete()
|
source.properties.through.objects.all().delete()
|
||||||
|
|
||||||
for link in [field for field in source._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]:
|
for link in [field for field in source._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]:
|
||||||
linkManager = getattr(source, link.get_accessor_name())
|
linkManager = getattr(source, link.get_accessor_name())
|
||||||
@ -825,8 +825,8 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
|||||||
'steps__ingredients__step_set',
|
'steps__ingredients__step_set',
|
||||||
'steps__ingredients__step_set__recipe_set',
|
'steps__ingredients__step_set__recipe_set',
|
||||||
'steps__ingredients__food',
|
'steps__ingredients__food',
|
||||||
'steps__ingredients__food__foodproperty_set',
|
'steps__ingredients__food__properties',
|
||||||
'steps__ingredients__food__foodproperty_set__property_type',
|
'steps__ingredients__food__properties__property_type',
|
||||||
'steps__ingredients__food__inherit_fields',
|
'steps__ingredients__food__inherit_fields',
|
||||||
'steps__ingredients__food__supermarket_category',
|
'steps__ingredients__food__supermarket_category',
|
||||||
'steps__ingredients__food__onhand_users',
|
'steps__ingredients__food__onhand_users',
|
||||||
@ -987,22 +987,12 @@ class PropertyTypeViewSet(viewsets.ModelViewSet):
|
|||||||
return self.queryset.filter(space=self.request.space)
|
return self.queryset.filter(space=self.request.space)
|
||||||
|
|
||||||
|
|
||||||
class FoodPropertyViewSet(viewsets.ModelViewSet):
|
class PropertyViewSet(viewsets.ModelViewSet):
|
||||||
queryset = FoodProperty.objects
|
queryset = Property.objects
|
||||||
serializer_class = FoodPropertySerializer
|
serializer_class = PropertySerializer
|
||||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||||
|
|
||||||
query_params = [
|
|
||||||
QueryParam(name='food',
|
|
||||||
description=_('ID of food to return properties for.'),
|
|
||||||
qtype='int'),
|
|
||||||
]
|
|
||||||
schema = QueryParamAutoSchema()
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if food := self.request.query_params.get('food', None):
|
|
||||||
self.queryset = self.queryset.filter(food__id=food)
|
|
||||||
|
|
||||||
return self.queryset.filter(space=self.request.space)
|
return self.queryset.filter(space=self.request.space)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import uuid
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import update_session_auth_hash
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.contrib.auth.password_validation import validate_password
|
from django.contrib.auth.password_validation import validate_password
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@ -18,12 +15,9 @@ from django.urls import reverse, reverse_lazy
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from oauth2_provider.models import AccessToken
|
|
||||||
|
|
||||||
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, ShoppingPreferenceForm,
|
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, SpaceCreateForm, SpaceJoinForm, User,
|
||||||
SpaceCreateForm, SpaceJoinForm, User,
|
UserCreateForm, UserPreference)
|
||||||
UserCreateForm, UserNameForm, UserPreference, UserPreferenceForm)
|
|
||||||
from cookbook.helper.property_helper import FoodPropertyHelper
|
|
||||||
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||||
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
||||||
Space, ViewLog, UserSpace)
|
Space, ViewLog, UserSpace)
|
||||||
|
@ -28,25 +28,77 @@
|
|||||||
<!-- Food properties -->
|
<!-- Food properties -->
|
||||||
|
|
||||||
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
|
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
|
||||||
<table class="table table-bordered" v-if="food_properties">
|
|
||||||
<tr v-for="fp in food_properties" v-bind:key="fp.id">
|
<b-form-group :label="$t('Properties Food Amount')" description=""> <!-- TODO localize -->
|
||||||
<td><input v-model="fp.property_amount" type="number"> {{ fp.property_type.unit }}</td>
|
<b-form-input v-model="food.properties_food_amount"></b-form-input>
|
||||||
<td><b> {{ fp.property_type.name }} </b></td>
|
</b-form-group>
|
||||||
<td> /</td>
|
|
||||||
<td><input v-model="fp.food_amount" type="number"></td>
|
<b-form-group :label="$t('Properties Food Unit')" description=""> <!-- TODO localize -->
|
||||||
<td>
|
|
||||||
<generic-multiselect
|
<generic-multiselect
|
||||||
@change="fp.food_unit = $event.val;"
|
@change="food.properties_food_unit = $event.val;"
|
||||||
:model="Models.UNIT"
|
:model="Models.UNIT"
|
||||||
:initial_single_selection="fp.food_unit"
|
:initial_single_selection="food.properties_food_unit"
|
||||||
label="name"
|
label="name"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:placeholder="$t('Unit')"
|
:placeholder="$t('Unit')"
|
||||||
></generic-multiselect>
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> {{ $t('Property Amount') }}</th> <!-- TODO localize -->
|
||||||
|
<th> {{ $t('Property Type') }}</th> <!-- TODO localize -->
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="fp in food.properties" v-bind:key="fp.id">
|
||||||
|
<td><input v-model="fp.property_amount" type="number"> <span
|
||||||
|
v-if="fp.property_type">{{ fp.property_type.unit }}</span></td>
|
||||||
|
<td>
|
||||||
|
<generic-multiselect
|
||||||
|
@change="fp.property_type = $event.val"
|
||||||
|
:initial_single_selection="fp.property_type"
|
||||||
|
label="name" :model="Models.PROPERTY_TYPE"
|
||||||
|
:multiple="false"/>
|
||||||
|
</td>
|
||||||
|
<td> / <span>{{ food.properties_food_amount }} <span
|
||||||
|
v-if="food.properties_food_unit !== null">{{
|
||||||
|
food.properties_food_unit.name
|
||||||
|
}}</span></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
|
||||||
|
class="fas fa-trash-alt"></i></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<b-button-group>
|
||||||
|
<b-btn class="btn btn-success shadow-none" @click="addProperty()"><i
|
||||||
|
class="fa fa-plus"></i>
|
||||||
|
</b-btn>
|
||||||
|
<b-btn class="btn btn-secondary shadow-none" @click="addAllProperties()"><i
|
||||||
|
class="fa fa-plus"> <i class="ml-1 fas fa-list"></i></i>
|
||||||
|
</b-btn>
|
||||||
|
</b-button-group>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.supermarket_category = $event.val;"
|
||||||
|
:model="Models.SHOPPING_CATEGORY"
|
||||||
|
:initial_single_selection="food.supermarket_category"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:allow_create="true"
|
||||||
|
:placeholder="$t('Shopping_Category')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
<!-- Unit conversion -->
|
<!-- Unit conversion -->
|
||||||
|
|
||||||
@ -74,18 +126,6 @@
|
|||||||
</b-form-checkbox>
|
</b-form-checkbox>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
|
|
||||||
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.supermarket_category = $event.val;"
|
|
||||||
:model="Models.SHOPPING_CATEGORY"
|
|
||||||
:initial_single_selection="food.supermarket_category"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:allow_create="true"
|
|
||||||
:placeholder="$t('Shopping_Category')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<!-- todo add conditions if false disable dont hide -->
|
<!-- todo add conditions if false disable dont hide -->
|
||||||
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
|
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
|
||||||
@ -191,7 +231,6 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
food: undefined,
|
food: undefined,
|
||||||
food_properties: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -212,6 +251,9 @@ export default {
|
|||||||
description: "",
|
description: "",
|
||||||
shopping: false,
|
shopping: false,
|
||||||
recipe: null,
|
recipe: null,
|
||||||
|
properties: [],
|
||||||
|
properties_food_amount: 100,
|
||||||
|
properties_food_unit: null,
|
||||||
food_onhand: false,
|
food_onhand: false,
|
||||||
supermarket_category: null,
|
supermarket_category: null,
|
||||||
parent: null,
|
parent: null,
|
||||||
@ -225,85 +267,41 @@ export default {
|
|||||||
child_inherit_fields: [],
|
child_inherit_fields: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.allSettled([pf]).then(r => {
|
|
||||||
let property_types = []
|
|
||||||
let property_values = []
|
|
||||||
|
|
||||||
let p1 = apiClient.listPropertyTypes().then((r) => {
|
|
||||||
property_types = r.data
|
|
||||||
})
|
|
||||||
|
|
||||||
let p2
|
|
||||||
if (this.food.id !== undefined) {
|
|
||||||
p2 = apiClient.listFoodPropertys(this.food.id).then((r) => {
|
|
||||||
property_values = r.data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.allSettled([p1, p2]).then(r => {
|
|
||||||
property_types.forEach(fpt => {
|
|
||||||
let food_property = {
|
|
||||||
'food_amount': 100,
|
|
||||||
'food_unit': {'name': 'g'},
|
|
||||||
'food': this.food,
|
|
||||||
'property_amount': 0,
|
|
||||||
'property_type': fpt,
|
|
||||||
}
|
|
||||||
|
|
||||||
property_values.forEach(fpv => {
|
|
||||||
if (fpv.property_type.id === fpt.id) {
|
|
||||||
food_property.id = fpv.id
|
|
||||||
food_property.food_amount = fpv.food_amount
|
|
||||||
food_property.food_unit = fpv.food_unit
|
|
||||||
food_property.property_amount = fpv.property_amount
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.food_properties.push(food_property)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateFood: function () {
|
updateFood: function () {
|
||||||
let apiClient = new ApiApiFactory()
|
let apiClient = new ApiApiFactory()
|
||||||
let p
|
|
||||||
if (this.food.id !== undefined) {
|
if (this.food.id !== undefined) {
|
||||||
p = apiClient.updateFood(this.food.id, this.food).then((r) => {
|
apiClient.updateFood(this.food.id, this.food).then((r) => {
|
||||||
this.food = r.data
|
this.food = r.data
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
p = apiClient.createFood(this.food).then((r) => {
|
apiClient.createFood(this.food).then((r) => {
|
||||||
this.food = r.data
|
this.food = r.data
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Promise.allSettled([p]).then(r => {
|
addProperty: function () {
|
||||||
this.food_properties.forEach(fp => {
|
this.food.properties.push({property_type: null, property_amount: 0})
|
||||||
fp.food = this.food
|
},
|
||||||
if (fp.id === undefined) {
|
addAllProperties: function () {
|
||||||
apiClient.createFoodProperty(fp).then((r) => {
|
let apiClient = new ApiApiFactory()
|
||||||
fp = r.data
|
apiClient.listPropertyTypes().then(r => {
|
||||||
|
r.data.forEach(x => {
|
||||||
|
this.food.properties.push({property_type: x, property_amount: 0})
|
||||||
|
})
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
})
|
})
|
||||||
} else {
|
},
|
||||||
apiClient.updateFoodProperty(fp.id, fp).then((r) => {
|
deleteProperty: function (p) {
|
||||||
fp = r.data
|
this.food.properties = this.food.properties.filter(x => x !== p)
|
||||||
}).catch(err => {
|
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
},
|
},
|
||||||
cancelAction: function () {
|
cancelAction: function () {
|
||||||
this.$emit("hidden", "")
|
this.$emit("hidden", "")
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user