This commit is contained in:
smilerz 2021-10-01 15:59:21 -05:00
parent 0b1d8bbd5f
commit e243e089cc
6 changed files with 73 additions and 56 deletions

View File

@ -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
} }

View File

@ -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) today_start = timezone.now().replace(hour=0, minute=0, second=0)
checked = request.query_params.get('checked', 'recent') qs = qs.filter(Q(shoppinglist__created_by=request.user) | Q(shoppinglist__shared=request.user)).filter(shoppinglist__space=request.space)
qs = qs.filter(Q(checked=False) | Q(completed_at__gte=today_start))
supermarket_order = ['food__supermarket_category__name', 'food__name'] return qs
# 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)
# TODO make recent a user setting
week_ago = today_start - timedelta(days=7)
qs = qs.filter(Q(checked=False) | Q(completed_at__gte=week_ago))
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')

View 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),
),
]

View File

@ -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')

View File

@ -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')

View File

@ -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