first parts of shopping rework
This commit is contained in:
parent
8055754455
commit
be55e034bf
@ -4,7 +4,8 @@ from rest_framework import serializers
|
||||
from rest_framework.exceptions import APIException, ValidationError
|
||||
from rest_framework.fields import CurrentUserDefault
|
||||
|
||||
from cookbook.models import MealPlan, MealType, Recipe, ViewLog, UserPreference, Storage, Sync, SyncLog, Keyword, Unit, Ingredient, Comment, RecipeImport, RecipeBook, RecipeBookEntry, ShareLink, CookLog, Food, Step
|
||||
from cookbook.models import MealPlan, MealType, Recipe, ViewLog, UserPreference, Storage, Sync, SyncLog, Keyword, Unit, Ingredient, Comment, RecipeImport, RecipeBook, RecipeBookEntry, ShareLink, CookLog, Food, Step, ShoppingList, \
|
||||
ShoppingListEntry, ShoppingListRecipe
|
||||
from cookbook.templatetags.custom_tags import markdown
|
||||
|
||||
|
||||
@ -193,6 +194,34 @@ class MealPlanSerializer(serializers.ModelSerializer):
|
||||
fields = ('id', 'title', 'recipe', 'note', 'note_markdown', 'date', 'meal_type', 'created_by', 'shared', 'recipe_name', 'meal_type_name')
|
||||
|
||||
|
||||
class ShoppingListRecipeSerializer(serializers.ModelSerializer):
|
||||
recipe = RecipeSerializer(read_only=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
return ShoppingListRecipe.objects.create(**validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
return super(ShoppingListRecipeSerializer, self).update(instance, validated_data)
|
||||
|
||||
class Meta:
|
||||
model = ShoppingListRecipe
|
||||
fields = ('recipe', 'multiplier')
|
||||
|
||||
|
||||
class ShoppingListEntrySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ShoppingListEntry
|
||||
fields = ('list_recipe', 'food', 'unit', 'amount', 'order', 'checked')
|
||||
|
||||
|
||||
class ShoppingListSerializer(serializers.ModelSerializer):
|
||||
recipes = ShoppingListRecipeSerializer(many=True, allow_null=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ShoppingList
|
||||
fields = ('id', 'uuid', 'note', 'recipes', 'shared', 'created_by', 'created_at',)
|
||||
|
||||
|
||||
class ShareLinkSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ShareLink
|
||||
|
@ -7,11 +7,124 @@
|
||||
{% block title %}{% trans "Shopping List" %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% include 'include/vue_base.html' %}
|
||||
|
||||
<link rel="stylesheet" href="{% static 'css/vue-multiselect-bs4.min.css' %}">
|
||||
<script src="{% static 'js/vue-multiselect.min.js' %}"></script>
|
||||
|
||||
<script src="{% static 'js/Sortable.min.js' %}"></script>
|
||||
<script src="{% static 'js/vuedraggable.umd.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-9">
|
||||
<h2>{% trans 'Shopping List' %}</h2>
|
||||
</div>
|
||||
<div class="col col-3">
|
||||
<b-form-checkbox switch size="lg" v-model="edit_mode">{% trans 'Edit' %}</b-form-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="edit_mode">
|
||||
<div class="row">
|
||||
<div class="col col-6">
|
||||
<input type="text" class="form-control" v-model="recipe_query" @keyup="getRecipes"
|
||||
placeholder="{% trans 'Search Recipe' %}">
|
||||
|
||||
<ul class="list-group" style="margin-top: 8px">
|
||||
<li class="list-group-item" v-for="x in recipes">[[x.name]]</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
Non Edit
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script type="application/javascript">
|
||||
let csrftoken = Cookies.get('csrftoken');
|
||||
Vue.http.headers.common['X-CSRFToken'] = csrftoken;
|
||||
|
||||
Vue.component('vue-multiselect', window.VueMultiselect.default)
|
||||
|
||||
let app = new Vue({
|
||||
components: {
|
||||
Multiselect: window.VueMultiselect.default
|
||||
},
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#id_base_container',
|
||||
data: {
|
||||
edit_mode: true,
|
||||
recipe_query: '',
|
||||
recipes: [],
|
||||
},
|
||||
directives: {
|
||||
tabindex: {
|
||||
inserted(el) {
|
||||
el.setAttribute('tabindex', 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
/*
|
||||
watch: {
|
||||
recipe: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.recipe_changed = this.recipe_changed !== undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
window.addEventListener('beforeunload', this.warnPageLeave)
|
||||
},
|
||||
*/
|
||||
mounted: function () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
/*
|
||||
warnPageLeave: function (event) {
|
||||
if (this.recipe_changed) {
|
||||
event.returnValue = ''
|
||||
return ''
|
||||
}
|
||||
},
|
||||
*/
|
||||
getRecipes: function () {
|
||||
let url = "{% url 'api:recipe-list' %}?limit=5"
|
||||
if (this.recipe_query !== '') {
|
||||
url += '&query=' + this.recipe_query;
|
||||
}
|
||||
|
||||
this.$http.get(url).then((response) => {
|
||||
this.recipes = response.data;
|
||||
}).catch((err) => {
|
||||
console.log("getRecipes error: ", err);
|
||||
this.makeToast('{% trans 'Error' %}', '{% trans 'There was an error loading a resource!' %}' + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
searchKeywords: function (query) {
|
||||
this.keywords_loading = true
|
||||
this.$http.get("{% url 'api:keyword-list' %}" + '?query=' + query + '&limit=10').then((response) => {
|
||||
this.keywords = response.data;
|
||||
this.keywords_loading = false
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.makeToast('{% trans 'Error' %}', '{% trans 'There was an error loading a resource!' %}' + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -23,6 +23,7 @@ router.register(r'recipe', api.RecipeViewSet)
|
||||
router.register(r'ingredient', api.IngredientViewSet)
|
||||
router.register(r'meal-plan', api.MealPlanViewSet)
|
||||
router.register(r'meal-type', api.MealTypeViewSet)
|
||||
router.register(r'shopping-list', api.ShoppingListViewSet)
|
||||
router.register(r'view-log', api.ViewLogViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
@ -34,6 +35,7 @@ urlpatterns = [
|
||||
path('plan/', views.meal_plan, name='view_plan'),
|
||||
path('plan/entry/<int:pk>', views.meal_plan_entry, name='view_plan_entry'),
|
||||
path('shopping/', views.shopping_list, name='view_shopping'),
|
||||
path('shopping/<int:pk>', views.shopping_list, name='view_shopping'),
|
||||
path('settings/', views.user_settings, name='view_settings'),
|
||||
path('history/', views.history, name='view_history'),
|
||||
path('test/', views.test, name='view_test'),
|
||||
|
@ -28,11 +28,11 @@ from rest_framework.viewsets import ViewSetMixin
|
||||
|
||||
from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser, CustomIsGuest, CustomIsShare
|
||||
from cookbook.helper.recipe_url_import import get_from_html
|
||||
from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword, Unit, SyncLog
|
||||
from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword, Unit, SyncLog, ShoppingListRecipe, ShoppingList
|
||||
from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \
|
||||
KeywordSerializer, RecipeImageSerializer, StorageSerializer, SyncSerializer, SyncLogSerializer, UnitSerializer
|
||||
KeywordSerializer, RecipeImageSerializer, StorageSerializer, SyncSerializer, SyncLogSerializer, UnitSerializer, ShoppingListSerializer
|
||||
|
||||
|
||||
class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
@ -233,6 +233,16 @@ class RecipeViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
return Response(serializer.errors, 400)
|
||||
|
||||
|
||||
class ShoppingListViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingList.objects.all()
|
||||
serializer_class = ShoppingListSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(created_by=self.request.user).all()
|
||||
return queryset
|
||||
|
||||
|
||||
class ViewLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = ViewLog.objects.all()
|
||||
serializer_class = ViewLogSerializer
|
||||
|
@ -50,7 +50,7 @@ def shopping_list(request):
|
||||
table = ShoppingListTable(ShoppingList.objects.filter(created_by=request.user).all())
|
||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||
|
||||
return render(request, 'generic/list_template.html', {'title': _("Shopping Lists"), 'table': table, 'create_url': 'new_storage'})
|
||||
return render(request, 'generic/list_template.html', {'title': _("Shopping Lists"), 'table': table, 'create_url': 'view_shopping'})
|
||||
|
||||
|
||||
@group_required('admin')
|
||||
|
@ -164,44 +164,8 @@ def meal_plan_entry(request, pk):
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def shopping_list(request):
|
||||
markdown_format = True
|
||||
|
||||
if request.method == "POST":
|
||||
form = ShoppingForm(request.POST)
|
||||
if form.is_valid():
|
||||
recipes = form.cleaned_data['recipe']
|
||||
markdown_format = form.cleaned_data['markdown_format']
|
||||
else:
|
||||
recipes = []
|
||||
else:
|
||||
raw_list = request.GET.getlist('r')
|
||||
|
||||
recipes = []
|
||||
for r in raw_list:
|
||||
if re.match(r'^([1-9])+$', r):
|
||||
if Recipe.objects.filter(pk=int(r)).exists():
|
||||
recipes.append(int(r))
|
||||
|
||||
markdown_format = False
|
||||
form = ShoppingForm(initial={'recipe': recipes, 'markdown_format': False})
|
||||
|
||||
ingredients = []
|
||||
|
||||
for r in recipes:
|
||||
for s in r.steps.all():
|
||||
for ri in s.ingredients.exclude(unit__name__contains='Special:').all():
|
||||
index = None
|
||||
for x, ig in enumerate(ingredients):
|
||||
if ri.food == ig.food and ri.unit == ig.unit:
|
||||
index = x
|
||||
|
||||
if index:
|
||||
ingredients[index].amount = ingredients[index].amount + ri.amount
|
||||
else:
|
||||
ingredients.append(ri)
|
||||
|
||||
return render(request, 'shopping_list.html', {'ingredients': ingredients, 'recipes': recipes, 'form': form, 'markdown_format': markdown_format})
|
||||
def shopping_list(request, pk=None):
|
||||
return render(request, 'shopping_list.html', {})
|
||||
|
||||
|
||||
@group_required('guest')
|
||||
|
Loading…
Reference in New Issue
Block a user