shopping line item

This commit is contained in:
smilerz
2021-10-21 17:44:45 -05:00
parent 79b6d4817e
commit 5e4e203dfb
5 changed files with 559 additions and 411 deletions

View File

@ -1,11 +1,42 @@
from django.db.models import Q
from datetime import timedelta
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 cookbook.models import UserPreference
def shopping_helper(qs, request):
today_start = timezone.now().replace(hour=0, minute=0, second=0)
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))
return qs
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 settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']:
# qs = qs.annotate(recipe_notes=ArrayAgg('list_recipe__recipe__steps__ingredients__note', filter=Q(list_recipe__recipe__steps__ingredients__food=F('food_id'))))
# qs = qs.annotate(meal_notes=ArrayAgg('list_recipe__mealplan__note', distinct=True, filter=Q(list_recipe__mealplan__note__isnull=False)))
# else:
# pass # ignore adding notes when running sqlite? or do some ugly contruction?
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', 'list_recipe__mealplan', 'list_recipe__recipe')

View File

@ -1,10 +1,12 @@
# Generated by Django 3.2.7 on 2021-10-01 22:34
import datetime
from datetime import timedelta
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.utils import timezone
from django.utils.timezone import utc
from django_scopes import scopes_disabled
@ -26,6 +28,14 @@ def create_inheritfields(apps, schema_editor):
FoodInheritField.objects.create(name='Substitute Siblings', field='substitute_siblings')
def set_completed_at(apps, schema_editor):
today_start = timezone.now().replace(hour=0, minute=0, second=0)
# arbitrary - keeping all of the closed shopping list items out of the 'recent' view
month_ago = today_start - timedelta(days=30)
with scopes_disabled():
ShoppingListEntry.objects.filter(checked=True).update(completed_at=month_ago)
class Migration(migrations.Migration):
dependencies = [
@ -36,4 +46,5 @@ class Migration(migrations.Migration):
operations = [
migrations.RunPython(delete_orphaned_sle),
migrations.RunPython(create_inheritfields),
migrations.RunPython(set_completed_at),
]

View File

@ -631,7 +631,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
class ShoppingListRecipeSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField('get_name') # should this be done at the front end?
recipe_name = serializers.ReadOnlyField(source='recipe.name')
mealplan_note = serializers.SerializerMethodField('get_note_markdown')
mealplan_note = serializers.ReadOnlyField(source='mealplan.note')
servings = CustomDecimalField()
def get_note_markdown(self, obj):
@ -639,7 +639,7 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer):
class Meta:
model = ShoppingListRecipe
fields = ('id', 'recipe', 'mealplan', 'recipe_name', 'servings', 'mealplan_note')
fields = ('id', 'recipe_name', 'name', 'recipe', 'mealplan', 'servings', 'mealplan_note')
read_only_fields = ('id',)
@ -679,6 +679,12 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
):
# if checked flips from false to true set completed datetime
data['completed_at'] = timezone.now()
elif not data.get('checked', False):
# if not checked set completed to None
data['completed_at'] = None
else:
# otherwise don't write anything
del data['completed_at']
############################################################
# temporary while old and new shopping lists are both in use
@ -707,7 +713,7 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
'id', 'list_recipe', 'food', 'unit', 'ingredient', 'ingredient_note', 'amount', 'order', 'checked', 'recipe_mealplan',
'created_by', 'created_at', 'completed_at'
)
read_only_fields = ('id', 'created_by', 'created_at',)
read_only_fields = ('id', 'list_recipe', 'created_by', 'created_at',)
# TODO deprecate