test recent shopping list
This commit is contained in:
parent
0e6685882c
commit
ab968f225b
@ -106,7 +106,7 @@ def test_add(arg, request, u1_s2, recipe_1_s1, meal_type):
|
|||||||
r = c.post(
|
r = c.post(
|
||||||
reverse(LIST_URL),
|
reverse(LIST_URL),
|
||||||
{'recipe': {'id': recipe_1_s1.id, 'name': recipe_1_s1.name, 'keywords': []}, 'meal_type': {'id': meal_type.id, 'name': meal_type.name},
|
{'recipe': {'id': recipe_1_s1.id, 'name': recipe_1_s1.name, 'keywords': []}, 'meal_type': {'id': meal_type.id, 'name': meal_type.name},
|
||||||
'date': (datetime.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test','shared':[]},
|
'date': (datetime.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test', 'shared': []},
|
||||||
content_type='application/json'
|
content_type='application/json'
|
||||||
)
|
)
|
||||||
response = json.loads(r.content)
|
response = json.loads(r.content)
|
||||||
@ -139,3 +139,7 @@ def test_delete(u1_s1, u1_s2, obj_1):
|
|||||||
assert r.status_code == 204
|
assert r.status_code == 204
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
assert MealPlan.objects.count() == 0
|
assert MealPlan.objects.count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
# TODO test auto creating shopping list from meal plan
|
||||||
|
# TODO test excluding on-hand when auto creating shopping list
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import json
|
import json
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import factory
|
import factory
|
||||||
import pytest
|
import pytest
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.forms import model_to_dict
|
from django.forms import model_to_dict
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from pytest_factoryboy import LazyFixture, register
|
from pytest_factoryboy import LazyFixture, register
|
||||||
|
|
||||||
@ -155,15 +157,73 @@ def test_sharing(request, shared, count, sle_2, sle, u1_s1):
|
|||||||
assert len(json.loads(r.content)) == count
|
assert len(json.loads(r.content)) == count
|
||||||
|
|
||||||
|
|
||||||
# TODO test completed entries still visible if today, but not yesterday
|
def test_completed(sle, u1_s1):
|
||||||
|
# check 1 entry
|
||||||
|
#
|
||||||
|
u1_s1.patch(
|
||||||
|
reverse(DETAIL_URL, args={sle[0].id}),
|
||||||
|
{'checked': True},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
r = json.loads(u1_s1.get(reverse(LIST_URL)).content)
|
||||||
|
assert len(r) == 10
|
||||||
|
# count unchecked entries
|
||||||
|
assert [x['checked'] for x in r].count(False) == 9
|
||||||
|
# confirm completed_at is populated
|
||||||
|
assert [(x['completed_at'] != None) for x in r if x['checked']].count(True) == 1
|
||||||
|
|
||||||
|
assert len(json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=0').content)) == 9
|
||||||
|
assert len(json.loads(u1_s1.get(f'{reverse(LIST_URL)}?checked=1').content)) == 1
|
||||||
|
|
||||||
|
# uncheck entry
|
||||||
|
u1_s1.patch(
|
||||||
|
reverse(DETAIL_URL, args={sle[0].id}),
|
||||||
|
{'checked': False},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
r = json.loads(u1_s1.get(reverse(LIST_URL)).content)
|
||||||
|
assert [x['checked'] for x in r].count(False) == 10
|
||||||
|
# confirm completed_at value cleared
|
||||||
|
assert [(x['completed_at'] != None) for x in r if x['checked']].count(True) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_recent(sle, u1_s1):
|
||||||
|
user = auth.get_user(u1_s1)
|
||||||
|
today_start = timezone.now().replace(hour=0, minute=0, second=0)
|
||||||
|
|
||||||
|
# past_date within recent_days threshold
|
||||||
|
past_date = today_start - timedelta(days=user.userpreference.shopping_recent_days - 1)
|
||||||
|
sle[0].checked = True
|
||||||
|
sle[0].completed_at = past_date
|
||||||
|
sle[0].save()
|
||||||
|
|
||||||
|
r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content)
|
||||||
|
assert len(r) == 10
|
||||||
|
assert [x['checked'] for x in r].count(False) == 9
|
||||||
|
|
||||||
|
# past_date outside recent_days threshold
|
||||||
|
past_date = today_start - timedelta(days=user.userpreference.shopping_recent_days + 2)
|
||||||
|
sle[0].completed_at = past_date
|
||||||
|
sle[0].save()
|
||||||
|
|
||||||
|
r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content)
|
||||||
|
assert len(r) == 9
|
||||||
|
assert [x['checked'] for x in r].count(False) == 9
|
||||||
|
|
||||||
|
# user preference moved to include entry again
|
||||||
|
user.userpreference.shopping_recent_days = user.userpreference.shopping_recent_days + 4
|
||||||
|
user.userpreference.save()
|
||||||
|
|
||||||
|
r = json.loads(u1_s1.get(f'{reverse(LIST_URL)}?recent=1').content)
|
||||||
|
assert len(r) == 10
|
||||||
|
assert [x['checked'] for x in r].count(False) == 9
|
||||||
|
|
||||||
|
|
||||||
# TODO test create shopping list from recipe
|
# 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 delete shopping list from recipe - include created by, shared with and not shared with
|
||||||
# TODO test create shopping list from food
|
# 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 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 mealplan
|
||||||
# TODO test create shopping list from recipe, excluding ingredients
|
# 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
|
|
||||||
# test delay
|
# test delay
|
||||||
# test completed_at when checked
|
|
||||||
# test completed_at cleared when unchecked
|
|
||||||
|
@ -716,7 +716,7 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
|||||||
if pk := self.request.query_params.getlist('id', []):
|
if pk := self.request.query_params.getlist('id', []):
|
||||||
self.queryset = self.queryset.filter(food__id__in=[int(i) for i in pk])
|
self.queryset = self.queryset.filter(food__id__in=[int(i) for i in pk])
|
||||||
|
|
||||||
if bool(int(self.request.query_params.get('recent', False))):
|
if 'checked' in self.request.query_params or 'recent' in self.request.query_params:
|
||||||
return shopping_helper(self.queryset, self.request)
|
return shopping_helper(self.queryset, self.request)
|
||||||
|
|
||||||
# TODO once old shopping list is removed this needs updated to sharing users in preferences
|
# TODO once old shopping list is removed this needs updated to sharing users in preferences
|
||||||
|
6
vue/package-lock.json
generated
6
vue/package-lock.json
generated
@ -13193,9 +13193,9 @@
|
|||||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.4.4",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
|
||||||
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
"integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uc.micro": {
|
"uc.micro": {
|
||||||
|
@ -49,8 +49,8 @@
|
|||||||
"@vue/eslint-config-typescript": "^9.1.0",
|
"@vue/eslint-config-typescript": "^9.1.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^7.28.0",
|
"eslint": "^7.28.0",
|
||||||
"eslint-plugin-vue": "^8.2.0",
|
"eslint-plugin-vue": "^8.0.3",
|
||||||
"typescript": "~4.4.4",
|
"typescript": "~4.5.2",
|
||||||
"vue-cli-plugin-i18n": "^2.1.1",
|
"vue-cli-plugin-i18n": "^2.1.1",
|
||||||
"webpack-bundle-tracker": "1.4.0",
|
"webpack-bundle-tracker": "1.4.0",
|
||||||
"workbox-expiration": "^6.3.0",
|
"workbox-expiration": "^6.3.0",
|
||||||
|
@ -436,7 +436,7 @@
|
|||||||
delayThis(contextData)
|
delayThis(contextData)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<b-form-group label-cols="10" content-cols="2" class="text-nowrap m-0 mr-2">
|
<b-form-group label-cols="9" content-cols="3" class="text-nowrap m-0 mr-2">
|
||||||
<template #label>
|
<template #label>
|
||||||
<a class="dropdown-item p-2" href="#"><i class="far fa-hourglass"></i> {{ $t("DelayFor", { hours: delay }) }}</a>
|
<a class="dropdown-item p-2" href="#"><i class="far fa-hourglass"></i> {{ $t("DelayFor", { hours: delay }) }}</a>
|
||||||
</template>
|
</template>
|
||||||
@ -550,7 +550,7 @@ export default {
|
|||||||
|
|
||||||
// filter out list items that are delayed
|
// filter out list items that are delayed
|
||||||
if (!this.show_delay && shopping_list) {
|
if (!this.show_delay && shopping_list) {
|
||||||
shopping_list = shopping_list.filter((x) => !x.delay_until || !Date.parse(x?.delay_until) > new Date(Date.now()))
|
shopping_list = shopping_list.filter((x) => !x.delay_until || !Date.parse(x?.delay_until) < new Date(Date.now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// if a supermarket is selected and filtered to only supermarket categories filter out everything else
|
// if a supermarket is selected and filtered to only supermarket categories filter out everything else
|
||||||
@ -671,6 +671,9 @@ export default {
|
|||||||
}
|
}
|
||||||
}, this.settings.shopping_auto_sync * 1000)
|
}, this.settings.shopping_auto_sync * 1000)
|
||||||
},
|
},
|
||||||
|
"settings.default_delay": function (newVal, oldVal) {
|
||||||
|
this.delay = Number(newVal)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getShoppingList()
|
this.getShoppingList()
|
||||||
@ -678,7 +681,8 @@ export default {
|
|||||||
this.getShoppingCategories()
|
this.getShoppingCategories()
|
||||||
|
|
||||||
this.settings = getUserPreference()
|
this.settings = getUserPreference()
|
||||||
this.delay = this.settings.default_delay || 4
|
this.delay = Number(this.settings.default_delay || 4)
|
||||||
|
console.log(this.delay)
|
||||||
this.supermarket_categories_only = this.settings.filter_to_supermarket
|
this.supermarket_categories_only = this.settings.filter_to_supermarket
|
||||||
if (this.settings.shopping_auto_sync) {
|
if (this.settings.shopping_auto_sync) {
|
||||||
window.addEventListener("online", this.updateOnlineStatus)
|
window.addEventListener("online", this.updateOnlineStatus)
|
||||||
|
@ -55,7 +55,8 @@
|
|||||||
<div class="col-md-4 text-muted text-right">{{ formatOneCreatedBy(e) }}</div>
|
<div class="col-md-4 text-muted text-right">{{ formatOneCreatedBy(e) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row ml-2 small">
|
<div class="row ml-2 small">
|
||||||
<div class="col-md-4 offset-md-8 text-muted text-right">{{ formatOneCompletedAt(e) }}</div>
|
<div class="col-md-4 offset-md-8 text-muted text-right" v-if="formatOneCompletedAt(e)">{{ formatOneCompletedAt(e) }}</div>
|
||||||
|
<div class="col-md-4 offset-md-8 text-muted text-right" v-if="formatOneDelayUntil(e)">{{ formatOneDelayUntil(e) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row ml-2 light">
|
<div class="row ml-2 light">
|
||||||
<div class="col-sm-1 text-nowrap">
|
<div class="col-sm-1 text-nowrap">
|
||||||
@ -210,7 +211,7 @@ export default {
|
|||||||
},
|
},
|
||||||
formatOneCompletedAt: function (item) {
|
formatOneCompletedAt: function (item) {
|
||||||
if (!item.completed_at) {
|
if (!item.completed_at) {
|
||||||
return ""
|
return false
|
||||||
}
|
}
|
||||||
return [this.$t("Completed"), "@", this.formatDate(item.completed_at)].join(" ")
|
return [this.$t("Completed"), "@", this.formatDate(item.completed_at)].join(" ")
|
||||||
},
|
},
|
||||||
@ -220,6 +221,12 @@ export default {
|
|||||||
formatOneChecked: function (item) {
|
formatOneChecked: function (item) {
|
||||||
return item.checked
|
return item.checked
|
||||||
},
|
},
|
||||||
|
formatOneDelayUntil: function (item) {
|
||||||
|
if (!item.delay_until && item.checked) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return [this.$t("DelayUntil"), "-", this.formatDate(item.delay_until)].join(" ")
|
||||||
|
},
|
||||||
formatOneMealPlan: function (item) {
|
formatOneMealPlan: function (item) {
|
||||||
return item?.recipe_mealplan?.name
|
return item?.recipe_mealplan?.name
|
||||||
},
|
},
|
||||||
@ -233,7 +240,7 @@ export default {
|
|||||||
return [item?.recipe_mealplan?.mealplan_note, item?.ingredient_note].filter(String)
|
return [item?.recipe_mealplan?.mealplan_note, item?.ingredient_note].filter(String)
|
||||||
},
|
},
|
||||||
formatOneCreatedBy: function (item) {
|
formatOneCreatedBy: function (item) {
|
||||||
return [item?.created_by.username, "@", this.formatDate(item.created_at)].join(" ")
|
return [this.$t("Added_by"), item?.created_by.username, "@", this.formatDate(item.created_at)].join(" ")
|
||||||
},
|
},
|
||||||
openRecipeCard: function (e, item) {
|
openRecipeCard: function (e, item) {
|
||||||
this.genericAPI(this.Models.RECIPE, this.Actions.FETCH, { id: item.recipe_mealplan.recipe }).then((result) => {
|
this.genericAPI(this.Models.RECIPE, this.Actions.FETCH, { id: item.recipe_mealplan.recipe }).then((result) => {
|
||||||
|
@ -275,5 +275,6 @@
|
|||||||
"csv_prefix_help": "Prefix to add when copying list to the clipboard.",
|
"csv_prefix_help": "Prefix to add when copying list to the clipboard.",
|
||||||
"csv_prefix_label": "List Prefix",
|
"csv_prefix_label": "List Prefix",
|
||||||
"copy_markdown_table": "Copy as Markdown Table",
|
"copy_markdown_table": "Copy as Markdown Table",
|
||||||
"in_shopping": "In Shopping List"
|
"in_shopping": "In Shopping List",
|
||||||
|
"DelayUntil": "Delay Until"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user