WIP
This commit is contained in:
parent
0b1d8bbd5f
commit
e243e089cc
@ -45,7 +45,8 @@ class UserPreferenceForm(forms.ModelForm):
|
|||||||
fields = (
|
fields = (
|
||||||
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
|
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
|
||||||
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
|
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
|
||||||
'plan_share', 'ingredient_decimals', 'comments',
|
'plan_share', 'shopping_share', 'ingredient_decimals', 'shopping_auto_sync',
|
||||||
|
'comments'
|
||||||
)
|
)
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
@ -74,7 +75,8 @@ class UserPreferenceForm(forms.ModelForm):
|
|||||||
'use_kj': _('Display nutritional energy amounts in joules instead of calories'), # noqa: E501
|
'use_kj': _('Display nutritional energy amounts in joules instead of calories'), # noqa: E501
|
||||||
'plan_share': _(
|
'plan_share': _(
|
||||||
'Users with whom newly created meal plans should be shared by default.'),
|
'Users with whom newly created meal plans should be shared by default.'),
|
||||||
'shopping_share': _('Users with whom to share shopping lists.'),
|
'shopping_share': _(
|
||||||
|
'Users with whom to share shopping lists.'),
|
||||||
# noqa: E501
|
# noqa: E501
|
||||||
'show_recent': _('Show recently viewed recipes on search page.'), # noqa: E501
|
'show_recent': _('Show recently viewed recipes on search page.'), # noqa: E501
|
||||||
|
|
||||||
@ -91,8 +93,7 @@ class UserPreferenceForm(forms.ModelForm):
|
|||||||
|
|
||||||
widgets = {
|
widgets = {
|
||||||
'plan_share': MultiSelectWidget,
|
'plan_share': MultiSelectWidget,
|
||||||
'shopping_share': MultiSelectWidget,
|
'shopping_share': MultiSelectWidget
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,40 +1,11 @@
|
|||||||
from datetime import timedelta
|
from django.db.models import Q
|
||||||
|
|
||||||
from django.contrib.postgres.aggregates import ArrayAgg
|
|
||||||
from django.db.models import F, OuterRef, Q, Subquery, Value
|
|
||||||
from django.db.models.functions import Coalesce
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
from cookbook.helper.HelperFunctions import Round, str2bool
|
from cookbook.models import UserPreference
|
||||||
from cookbook.models import SupermarketCategoryRelation
|
|
||||||
from recipes import settings
|
|
||||||
|
|
||||||
|
|
||||||
def shopping_helper(qs, request):
|
def shopping_helper(qs, request):
|
||||||
supermarket = request.query_params.get('supermarket', None)
|
|
||||||
checked = request.query_params.get('checked', 'recent')
|
|
||||||
|
|
||||||
supermarket_order = ['food__supermarket_category__name', 'food__name']
|
|
||||||
|
|
||||||
# TODO created either scheduled task or startup task to delete very old shopping list entries
|
|
||||||
# TODO create user preference to define 'very old'
|
|
||||||
|
|
||||||
# qs = qs.annotate(supermarket_category=Coalesce(F('food__supermarket_category__name'), Value(_('Undefined'))))
|
|
||||||
# TODO add supermarket to API - order by category order
|
|
||||||
if supermarket:
|
|
||||||
supermarket_categories = SupermarketCategoryRelation.objects.filter(supermarket=supermarket, category=OuterRef('food__supermarket_category'))
|
|
||||||
qs = qs.annotate(supermarket_order=Coalesce(Subquery(supermarket_categories.values('order')), Value(9999)))
|
|
||||||
supermarket_order = ['supermarket_order'] + supermarket_order
|
|
||||||
if checked in ['false', 0, '0']:
|
|
||||||
qs = qs.filter(checked=False)
|
|
||||||
elif checked in ['true', 1, '1']:
|
|
||||||
qs = qs.filter(checked=True)
|
|
||||||
elif checked in ['recent']:
|
|
||||||
today_start = timezone.now().replace(hour=0, minute=0, second=0)
|
today_start = timezone.now().replace(hour=0, minute=0, second=0)
|
||||||
# TODO make recent a user setting
|
qs = qs.filter(Q(shoppinglist__created_by=request.user) | Q(shoppinglist__shared=request.user)).filter(shoppinglist__space=request.space)
|
||||||
week_ago = today_start - timedelta(days=7)
|
qs = qs.filter(Q(checked=False) | Q(completed_at__gte=today_start))
|
||||||
qs = qs.filter(Q(checked=False) | Q(completed_at__gte=week_ago))
|
return qs
|
||||||
supermarket_order = ['checked'] + supermarket_order
|
|
||||||
|
|
||||||
return qs.order_by(*supermarket_order).select_related('unit', 'food', 'ingredient', 'created_by', 'list_recipe', 'list_recipe__mealplan', 'list_recipe__recipe')
|
|
||||||
|
58
cookbook/migrations/0158_auto_20211001_1552.py
Normal file
58
cookbook/migrations/0158_auto_20211001_1552.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Generated by Django 3.2.7 on 2021-10-01 20:52
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
def copy_values_to_sle(apps, schema_editor):
|
||||||
|
ShoppingListEntry = apps.get_model('app', 'ShoppingListEntry')
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
from django.db.models import F
|
||||||
|
MetaDataValue.objects.using(db_alias).all().update(
|
||||||
|
short_value=F('shoppinglist__created_by')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('cookbook', '0157_alter_searchpreference_trigram'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='on_hand',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='shoppinglistentry',
|
||||||
|
name='completed_at',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='shoppinglistentry',
|
||||||
|
name='created_at',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='shoppinglistentry',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='auth.user'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='shoppinglistentry',
|
||||||
|
name='recipe',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cookbook.recipe'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userpreference',
|
||||||
|
name='shopping_share',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='shopping_share', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -487,8 +487,6 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
ignore_shopping = models.BooleanField(default=False)
|
ignore_shopping = models.BooleanField(default=False)
|
||||||
description = models.TextField(default='', blank=True)
|
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) # is this better as inherit instead of ignore inherit? which is more intuitive?
|
|
||||||
|
|
||||||
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)
|
||||||
@ -840,10 +838,10 @@ class ShoppingListEntry(ExportModelOperationsMixin('shopping_list_entry'), model
|
|||||||
amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
order = models.IntegerField(default=0)
|
order = models.IntegerField(default=0)
|
||||||
checked = models.BooleanField(default=False)
|
checked = models.BooleanField(default=False)
|
||||||
|
recipe = models.ForeignKey(Recipe, on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
completed_at = models.DateTimeField(null=True, blank=True)
|
completed_at = models.DateTimeField(null=True, blank=True)
|
||||||
delay_until = models.DateTimeField(null=True, blank=True)
|
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
|
@ -390,10 +390,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Food
|
model = Food
|
||||||
fields = (
|
fields = ('id', 'name', 'description', 'recipe', 'ignore_shopping', 'supermarket_category', 'image', 'parent', 'numchild', 'numrecipe', 'on_hand')
|
||||||
'id', 'name', 'description', 'shopping', 'recipe', 'ignore_shopping', 'supermarket_category',
|
|
||||||
'image', 'parent', 'numchild', 'numrecipe', 'on_hand', 'inherit', 'ignore_inherit',
|
|
||||||
)
|
|
||||||
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,13 +119,5 @@ def test_delete(u1_s1, u1_s2, obj_1):
|
|||||||
assert r.status_code == 204
|
assert r.status_code == 204
|
||||||
|
|
||||||
|
|
||||||
# TODO test sharing
|
# test sharing
|
||||||
# TODO test completed entries still visible if today, but not yesterday
|
# test completed entries still visible if today, but not yesterday
|
||||||
# TODO test create shopping list from recipe
|
|
||||||
# TODO test delete shopping list from recipe - include created by, shared with and not shared with
|
|
||||||
# TODO test create shopping list from food
|
|
||||||
# TODO test delete shopping list from food - include created by, shared with and not shared with
|
|
||||||
# TODO test create shopping list from mealplan
|
|
||||||
# TODO test create shopping list from recipe, excluding ingredients
|
|
||||||
# TODO test auto creating shopping list from meal plan
|
|
||||||
# TODO test excluding on-hand when auto creating shopping list
|
|
Loading…
Reference in New Issue
Block a user