added simple entry mode to shopping
This commit is contained in:
8
cookbook/integration/integration.py
Normal file
8
cookbook/integration/integration.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class Integration:
|
||||||
|
@staticmethod
|
||||||
|
def get_recipe(string):
|
||||||
|
raise Exception('Method not implemented in storage integration')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_export(recipe):
|
||||||
|
raise Exception('Method not implemented in storage integration')
|
@ -407,13 +407,9 @@ class ShoppingListRecipe(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class ShoppingListEntry(models.Model):
|
class ShoppingListEntry(models.Model):
|
||||||
list_recipe = models.ForeignKey(
|
list_recipe = models.ForeignKey(ShoppingListRecipe, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
ShoppingListRecipe, on_delete=models.CASCADE, null=True, blank=True
|
|
||||||
)
|
|
||||||
food = models.ForeignKey(Food, on_delete=models.CASCADE)
|
food = models.ForeignKey(Food, on_delete=models.CASCADE)
|
||||||
unit = models.ForeignKey(
|
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
Unit, on_delete=models.CASCADE, null=True, blank=True
|
|
||||||
)
|
|
||||||
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)
|
||||||
|
@ -178,7 +178,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
|||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
# since multi select tags dont have id's
|
||||||
# duplicate names might be routed to create
|
# duplicate names might be routed to create
|
||||||
obj, created = Food.objects.get_or_create(**validated_data)
|
obj, created = Food.objects.get_or_create(name=validated_data['name'])
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
@ -135,6 +135,27 @@
|
|||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<form v-on:submit.prevent="addSimpleEntry()">
|
||||||
|
|
||||||
|
<label for="id_simple_entry">{% trans 'Add Entry' %}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
|
||||||
|
<input id="id_simple_entry" class="form-control" v-model="simple_entry">
|
||||||
|
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-outline-secondary" type="button"><i class="fa fa-plus"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-lg-3">
|
<div class="col-12 col-lg-3">
|
||||||
@ -278,7 +299,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>[[x.amount]]</td>
|
<td>[[x.amount]]</td>
|
||||||
<td>[[x.unit.name]]</td>
|
<td>[[x.unit.name]]</td>
|
||||||
<td>[[x.food.name]] <span class="text-muted" v-if="x.recipes.length > 0">([[x.recipes.join(', ')]])</span></td>
|
<td>[[x.food.name]] <span class="text-muted" v-if="x.recipes.length > 0">([[x.recipes.join(', ')]])</span>
|
||||||
|
</td>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
@ -382,6 +404,7 @@
|
|||||||
users: [],
|
users: [],
|
||||||
users_loading: false,
|
users_loading: false,
|
||||||
onLine: navigator.onLine,
|
onLine: navigator.onLine,
|
||||||
|
simple_entry: '',
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
tabindex: {
|
tabindex: {
|
||||||
@ -444,7 +467,12 @@
|
|||||||
|
|
||||||
let entry = this.findMergeEntry(categories, item)
|
let entry = this.findMergeEntry(categories, item)
|
||||||
if (entry !== undefined) {
|
if (entry !== undefined) {
|
||||||
entry.amount += item.amount * this.servings_cache[item.list_recipe]
|
let servings = 1
|
||||||
|
if (item.list_recipe in this.servings_cache) {
|
||||||
|
servings = this.servings_cache[item.list_recipe]
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.amount += item.amount * servings
|
||||||
|
|
||||||
if (item.list_recipe !== null && entry.recipes.indexOf(this.recipe_cache[item.list_recipe]) === -1) {
|
if (item.list_recipe !== null && entry.recipes.indexOf(this.recipe_cache[item.list_recipe]) === -1) {
|
||||||
entry.recipes.push(this.recipe_cache[item.list_recipe])
|
entry.recipes.push(this.recipe_cache[item.list_recipe])
|
||||||
@ -736,6 +764,28 @@
|
|||||||
this.makeToast(gettext('Error'), gettext('Please enter a valid food'), 'danger')
|
this.makeToast(gettext('Error'), gettext('Please enter a valid food'), 'danger')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addSimpleEntry: function () {
|
||||||
|
if (this.simple_entry !== '') {
|
||||||
|
|
||||||
|
this.$http.post('{% url 'api_ingredient_from_string' %}', {text: this.simple_entry}, {emulateJSON: true}).then((response) => {
|
||||||
|
|
||||||
|
console.log(response)
|
||||||
|
this.shopping_list.entries.push({
|
||||||
|
'list_recipe': null,
|
||||||
|
'food': {'name': response.body.food, supermarket_category: null},
|
||||||
|
'unit': {'name': response.body.unit},
|
||||||
|
'amount': response.body.amount,
|
||||||
|
'order': 0,
|
||||||
|
'checked': false,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.simple_entry = ''
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
this.makeToast(gettext('Error'), gettext('Something went wrong while trying to add the simple entry.'), 'danger')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
getRecipes: function () {
|
getRecipes: function () {
|
||||||
let url = "{% url 'api:recipe-list' %}?limit=5&internal=true"
|
let url = "{% url 'api:recipe-list' %}?limit=5&internal=true"
|
||||||
if (this.recipe_query !== '') {
|
if (this.recipe_query !== '') {
|
||||||
|
@ -88,6 +88,7 @@ urlpatterns = [
|
|||||||
path('api/plan-ical/<slug:from_date>/<slug:to_date>/', api.get_plan_ical, name='api_get_plan_ical'),
|
path('api/plan-ical/<slug:from_date>/<slug:to_date>/', api.get_plan_ical, name='api_get_plan_ical'),
|
||||||
path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'),
|
path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'),
|
||||||
path('api/backup/', api.get_backup, name='api_backup'),
|
path('api/backup/', api.get_backup, name='api_backup'),
|
||||||
|
path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'),
|
||||||
|
|
||||||
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
||||||
path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'),
|
path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'),
|
||||||
|
@ -27,6 +27,7 @@ from rest_framework.parsers import MultiPartParser
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ViewSetMixin
|
from rest_framework.viewsets import ViewSetMixin
|
||||||
|
|
||||||
|
from cookbook.helper.ingredient_parser import parse
|
||||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
|
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
|
||||||
CustomIsOwner, CustomIsShare,
|
CustomIsOwner, CustomIsShare,
|
||||||
CustomIsShared, CustomIsUser,
|
CustomIsShared, CustomIsUser,
|
||||||
@ -536,3 +537,18 @@ def get_backup(request):
|
|||||||
response["Content-Disposition"] = f'attachment; filename=backup{date_format(timezone.now(), format="SHORT_DATETIME_FORMAT", use_l10n=True)}.json' # noqa: E501
|
response["Content-Disposition"] = f'attachment; filename=backup{date_format(timezone.now(), format="SHORT_DATETIME_FORMAT", use_l10n=True)}.json' # noqa: E501
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@group_required('user')
|
||||||
|
def ingredient_from_string(request):
|
||||||
|
text = request.POST['text']
|
||||||
|
amount, unit, food, note = parse(text)
|
||||||
|
|
||||||
|
return JsonResponse(
|
||||||
|
{
|
||||||
|
'amount': amount,
|
||||||
|
'unit': unit,
|
||||||
|
'food': food,
|
||||||
|
},
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
Reference in New Issue
Block a user