shopping / meal plan improvements

This commit is contained in:
vabene1111
2025-03-16 13:36:42 +01:00
parent 7f06f888df
commit ee0f652981
7 changed files with 59 additions and 14 deletions

View File

@@ -1245,7 +1245,7 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
validated_data['created_by'] = self.context['request'].user validated_data['created_by'] = self.context['request'].user
if 'mealplan_id' in validated_data: if 'mealplan_id' in validated_data:
if existing_slr := ShoppingListRecipe.objects.filter(mealplan_id=validated_data['mealplan_id'], space=self.context['request'].space).get(): if existing_slr := ShoppingListRecipe.objects.filter(mealplan_id=validated_data['mealplan_id'], space=self.context['request'].space).first():
validated_data['list_recipe'] = existing_slr validated_data['list_recipe'] = existing_slr
else: else:
validated_data['list_recipe'] = ShoppingListRecipe.objects.create(mealplan_id=validated_data['mealplan_id'], space=self.context['request'].space, created_by=self.context['request'].user) validated_data['list_recipe'] = ShoppingListRecipe.objects.create(mealplan_id=validated_data['mealplan_id'], space=self.context['request'].space, created_by=self.context['request'].user)
@@ -1271,7 +1271,7 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
class Meta: class Meta:
model = ShoppingListEntry model = ShoppingListEntry
fields = ( fields = (
'id', 'list_recipe', 'food', 'unit', 'amount', 'order', 'checked', 'id', 'list_recipe', 'food', 'unit', 'amount', 'order', 'checked', 'ingredient',
'list_recipe_data', 'created_by', 'created_at', 'updated_at', 'completed_at', 'delay_until', 'mealplan_id' 'list_recipe_data', 'created_by', 'created_at', 'updated_at', 'completed_at', 'delay_until', 'mealplan_id'
) )
read_only_fields = ('id', 'created_by', 'created_at') read_only_fields = ('id', 'created_by', 'created_at')

View File

@@ -11,7 +11,7 @@
<v-row> <v-row>
<v-col class="pr-0"> <v-col class="pr-0">
<v-btn height="80px" color="info" density="compact" size="small" block stacked <v-btn height="80px" color="info" density="compact" size="small" block stacked
@click="useShoppingStore().delayEntries(entriesList, !isShoppingLineDelayed, true); "> @click="useShoppingStore().delayEntries(entriesList, !isShoppingLineDelayed, true); showDialog=false">
<i class="fa-solid fa-clock-rotate-left fa-2x mb-2"></i> <i class="fa-solid fa-clock-rotate-left fa-2x mb-2"></i>
<span v-if="!isShoppingLineDelayed">{{ $t('ShopLater') }}</span> <span v-if="!isShoppingLineDelayed">{{ $t('ShopLater') }}</span>
<span v-if="isShoppingLineDelayed">{{ $t('ShopNow') }}</span> <span v-if="isShoppingLineDelayed">{{ $t('ShopNow') }}</span>
@@ -78,26 +78,26 @@
</v-list-item-subtitle> </v-list-item-subtitle>
<v-btn-group divided border> <v-btn-group divided border>
<v-btn icon="" @click="e.amount = e.amount / 2; updateEntryAmount(e)" v-if="!e.listRecipeData"> <v-btn icon="" @click="e.amount = e.amount / 2; updateEntryAmount(e)" v-if="!e.ingredient">
<v-icon icon="fa-solid fa-divide"></v-icon> <v-icon icon="fa-solid fa-divide"></v-icon>
</v-btn> </v-btn>
<v-btn icon="" @click="e.amount--; updateEntryAmount(e)" v-if="!e.listRecipeData"> <v-btn icon="" @click="e.amount--; updateEntryAmount(e)" v-if="!e.ingredient">
<v-icon icon="fa-solid fa-minus"></v-icon> <v-icon icon="fa-solid fa-minus"></v-icon>
</v-btn> </v-btn>
<v-btn icon="" @click="e.amount++; updateEntryAmount(e)" v-if="!e.listRecipeData"> <v-btn icon="" @click="e.amount++; updateEntryAmount(e)" v-if="!e.ingredient">
<v-icon icon="fa-solid fa-plus"></v-icon> <v-icon icon="fa-solid fa-plus"></v-icon>
</v-btn> </v-btn>
<v-btn icon="" @click="e.amount = e.amount * 2; updateEntryAmount(e)" v-if="!e.listRecipeData"> <v-btn icon="" @click="e.amount = e.amount * 2; updateEntryAmount(e)" v-if="!e.ingredient">
<v-icon icon="fa-solid fa-times"></v-icon> <v-icon icon="fa-solid fa-times"></v-icon>
</v-btn> </v-btn>
<v-btn color="edit" icon="$edit" v-if="!e.listRecipeData"> <v-btn color="edit" icon="$edit" v-if="!e.ingredient">
<v-icon icon="$edit"></v-icon> <v-icon icon="$edit"></v-icon>
<model-edit-dialog model="ShoppingListEntry" :item="e" <model-edit-dialog model="ShoppingListEntry" :item="e"
@delete="useShoppingStore().entries.delete(e.id!); shoppingListFood.entries.delete(e.id!)" @delete="useShoppingStore().entries.delete(e.id!); shoppingListFood.entries.delete(e.id!)"
@save="(args: ShoppingListEntry) => { useShoppingStore().entries.set(e.id!, args); shoppingListFood.entries.set(e.id!, args) }"></model-edit-dialog> @save="(args: ShoppingListEntry) => { useShoppingStore().entries.set(e.id!, args); shoppingListFood.entries.set(e.id!, args) }"></model-edit-dialog>
</v-btn> </v-btn>
<v-btn color="edit" icon="$recipes" v-if="e.listRecipe && e.listRecipeData.recipe" <v-btn color="edit" icon="$recipes" v-if="e.listRecipe && e.listRecipeData.recipe && e.ingredient"
:to="{name: 'view_recipe', params: {id: e.listRecipeData.recipe}}"> :to="{name: 'view_recipe', params: {id: e.listRecipeData.recipe}}">
<v-icon icon="$recipes"></v-icon> <v-icon icon="$recipes"></v-icon>
</v-btn> </v-btn>

View File

@@ -1282,7 +1282,7 @@ export interface ApiShoppingListRecipeBulkCreateEntriesCreateRequest {
} }
export interface ApiShoppingListRecipeCreateRequest { export interface ApiShoppingListRecipeCreateRequest {
shoppingListRecipe: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'>; shoppingListRecipe: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'|'created_by'>;
} }
export interface ApiShoppingListRecipeDestroyRequest { export interface ApiShoppingListRecipeDestroyRequest {
@@ -1297,7 +1297,7 @@ export interface ApiShoppingListRecipeListRequest {
export interface ApiShoppingListRecipePartialUpdateRequest { export interface ApiShoppingListRecipePartialUpdateRequest {
id: number; id: number;
patchedShoppingListRecipe?: Omit<PatchedShoppingListRecipe, 'recipe_data'|'meal_plan_data'>; patchedShoppingListRecipe?: Omit<PatchedShoppingListRecipe, 'recipe_data'|'meal_plan_data'|'created_by'>;
} }
export interface ApiShoppingListRecipeRetrieveRequest { export interface ApiShoppingListRecipeRetrieveRequest {
@@ -1306,7 +1306,7 @@ export interface ApiShoppingListRecipeRetrieveRequest {
export interface ApiShoppingListRecipeUpdateRequest { export interface ApiShoppingListRecipeUpdateRequest {
id: number; id: number;
shoppingListRecipe: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'>; shoppingListRecipe: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'|'created_by'>;
} }
export interface ApiSpaceListRequest { export interface ApiSpaceListRequest {

View File

@@ -90,6 +90,12 @@ export interface PatchedShoppingListEntry {
* @memberof PatchedShoppingListEntry * @memberof PatchedShoppingListEntry
*/ */
checked?: boolean; checked?: boolean;
/**
*
* @type {number}
* @memberof PatchedShoppingListEntry
*/
ingredient?: number | null;
/** /**
* *
* @type {ShoppingListRecipe} * @type {ShoppingListRecipe}
@@ -158,6 +164,7 @@ export function PatchedShoppingListEntryFromJSONTyped(json: any, ignoreDiscrimin
'amount': json['amount'] == null ? undefined : json['amount'], 'amount': json['amount'] == null ? undefined : json['amount'],
'order': json['order'] == null ? undefined : json['order'], 'order': json['order'] == null ? undefined : json['order'],
'checked': json['checked'] == null ? undefined : json['checked'], 'checked': json['checked'] == null ? undefined : json['checked'],
'ingredient': json['ingredient'] == null ? undefined : json['ingredient'],
'listRecipeData': json['list_recipe_data'] == null ? undefined : ShoppingListRecipeFromJSON(json['list_recipe_data']), 'listRecipeData': json['list_recipe_data'] == null ? undefined : ShoppingListRecipeFromJSON(json['list_recipe_data']),
'createdBy': json['created_by'] == null ? undefined : UserFromJSON(json['created_by']), 'createdBy': json['created_by'] == null ? undefined : UserFromJSON(json['created_by']),
'createdAt': json['created_at'] == null ? undefined : (new Date(json['created_at'])), 'createdAt': json['created_at'] == null ? undefined : (new Date(json['created_at'])),
@@ -186,6 +193,7 @@ export function PatchedShoppingListEntryToJSONTyped(value?: Omit<PatchedShopping
'amount': value['amount'], 'amount': value['amount'],
'order': value['order'], 'order': value['order'],
'checked': value['checked'], 'checked': value['checked'],
'ingredient': value['ingredient'],
'completed_at': value['completedAt'] == null ? undefined : ((value['completedAt'] as any).toISOString()), 'completed_at': value['completedAt'] == null ? undefined : ((value['completedAt'] as any).toISOString()),
'delay_until': value['delayUntil'] == null ? undefined : ((value['delayUntil'] as any).toISOString()), 'delay_until': value['delayUntil'] == null ? undefined : ((value['delayUntil'] as any).toISOString()),
'mealplan_id': value['mealplanId'], 'mealplan_id': value['mealplanId'],

View File

@@ -20,6 +20,13 @@ import {
MealPlanToJSON, MealPlanToJSON,
MealPlanToJSONTyped, MealPlanToJSONTyped,
} from './MealPlan'; } from './MealPlan';
import type { User } from './User';
import {
UserFromJSON,
UserFromJSONTyped,
UserToJSON,
UserToJSONTyped,
} from './User';
import type { RecipeOverview } from './RecipeOverview'; import type { RecipeOverview } from './RecipeOverview';
import { import {
RecipeOverviewFromJSON, RecipeOverviewFromJSON,
@@ -76,6 +83,12 @@ export interface PatchedShoppingListRecipe {
* @memberof PatchedShoppingListRecipe * @memberof PatchedShoppingListRecipe
*/ */
servings?: number; servings?: number;
/**
*
* @type {User}
* @memberof PatchedShoppingListRecipe
*/
readonly createdBy?: User;
} }
/** /**
@@ -102,6 +115,7 @@ export function PatchedShoppingListRecipeFromJSONTyped(json: any, ignoreDiscrimi
'mealplan': json['mealplan'] == null ? undefined : json['mealplan'], 'mealplan': json['mealplan'] == null ? undefined : json['mealplan'],
'mealPlanData': json['meal_plan_data'] == null ? undefined : MealPlanFromJSON(json['meal_plan_data']), 'mealPlanData': json['meal_plan_data'] == null ? undefined : MealPlanFromJSON(json['meal_plan_data']),
'servings': json['servings'] == null ? undefined : json['servings'], 'servings': json['servings'] == null ? undefined : json['servings'],
'createdBy': json['created_by'] == null ? undefined : UserFromJSON(json['created_by']),
}; };
} }
@@ -109,7 +123,7 @@ export function PatchedShoppingListRecipeToJSON(json: any): PatchedShoppingListR
return PatchedShoppingListRecipeToJSONTyped(json, false); return PatchedShoppingListRecipeToJSONTyped(json, false);
} }
export function PatchedShoppingListRecipeToJSONTyped(value?: Omit<PatchedShoppingListRecipe, 'recipe_data'|'meal_plan_data'> | null, ignoreDiscriminator: boolean = false): any { export function PatchedShoppingListRecipeToJSONTyped(value?: Omit<PatchedShoppingListRecipe, 'recipe_data'|'meal_plan_data'|'created_by'> | null, ignoreDiscriminator: boolean = false): any {
if (value == null) { if (value == null) {
return value; return value;
} }

View File

@@ -90,6 +90,12 @@ export interface ShoppingListEntry {
* @memberof ShoppingListEntry * @memberof ShoppingListEntry
*/ */
checked?: boolean; checked?: boolean;
/**
*
* @type {number}
* @memberof ShoppingListEntry
*/
ingredient?: number | null;
/** /**
* *
* @type {ShoppingListRecipe} * @type {ShoppingListRecipe}
@@ -164,6 +170,7 @@ export function ShoppingListEntryFromJSONTyped(json: any, ignoreDiscriminator: b
'amount': json['amount'], 'amount': json['amount'],
'order': json['order'] == null ? undefined : json['order'], 'order': json['order'] == null ? undefined : json['order'],
'checked': json['checked'] == null ? undefined : json['checked'], 'checked': json['checked'] == null ? undefined : json['checked'],
'ingredient': json['ingredient'] == null ? undefined : json['ingredient'],
'listRecipeData': ShoppingListRecipeFromJSON(json['list_recipe_data']), 'listRecipeData': ShoppingListRecipeFromJSON(json['list_recipe_data']),
'createdBy': UserFromJSON(json['created_by']), 'createdBy': UserFromJSON(json['created_by']),
'createdAt': (new Date(json['created_at'])), 'createdAt': (new Date(json['created_at'])),
@@ -192,6 +199,7 @@ export function ShoppingListEntryToJSONTyped(value?: Omit<ShoppingListEntry, 'li
'amount': value['amount'], 'amount': value['amount'],
'order': value['order'], 'order': value['order'],
'checked': value['checked'], 'checked': value['checked'],
'ingredient': value['ingredient'],
'completed_at': value['completedAt'] == null ? undefined : ((value['completedAt'] as any).toISOString()), 'completed_at': value['completedAt'] == null ? undefined : ((value['completedAt'] as any).toISOString()),
'delay_until': value['delayUntil'] == null ? undefined : ((value['delayUntil'] as any).toISOString()), 'delay_until': value['delayUntil'] == null ? undefined : ((value['delayUntil'] as any).toISOString()),
'mealplan_id': value['mealplanId'], 'mealplan_id': value['mealplanId'],

View File

@@ -20,6 +20,13 @@ import {
MealPlanToJSON, MealPlanToJSON,
MealPlanToJSONTyped, MealPlanToJSONTyped,
} from './MealPlan'; } from './MealPlan';
import type { User } from './User';
import {
UserFromJSON,
UserFromJSONTyped,
UserToJSON,
UserToJSONTyped,
} from './User';
import type { RecipeOverview } from './RecipeOverview'; import type { RecipeOverview } from './RecipeOverview';
import { import {
RecipeOverviewFromJSON, RecipeOverviewFromJSON,
@@ -76,6 +83,12 @@ export interface ShoppingListRecipe {
* @memberof ShoppingListRecipe * @memberof ShoppingListRecipe
*/ */
servings: number; servings: number;
/**
*
* @type {User}
* @memberof ShoppingListRecipe
*/
readonly createdBy: User;
} }
/** /**
@@ -85,6 +98,7 @@ export function instanceOfShoppingListRecipe(value: object): value is ShoppingLi
if (!('recipeData' in value) || value['recipeData'] === undefined) return false; if (!('recipeData' in value) || value['recipeData'] === undefined) return false;
if (!('mealPlanData' in value) || value['mealPlanData'] === undefined) return false; if (!('mealPlanData' in value) || value['mealPlanData'] === undefined) return false;
if (!('servings' in value) || value['servings'] === undefined) return false; if (!('servings' in value) || value['servings'] === undefined) return false;
if (!('createdBy' in value) || value['createdBy'] === undefined) return false;
return true; return true;
} }
@@ -105,6 +119,7 @@ export function ShoppingListRecipeFromJSONTyped(json: any, ignoreDiscriminator:
'mealplan': json['mealplan'] == null ? undefined : json['mealplan'], 'mealplan': json['mealplan'] == null ? undefined : json['mealplan'],
'mealPlanData': MealPlanFromJSON(json['meal_plan_data']), 'mealPlanData': MealPlanFromJSON(json['meal_plan_data']),
'servings': json['servings'], 'servings': json['servings'],
'createdBy': UserFromJSON(json['created_by']),
}; };
} }
@@ -112,7 +127,7 @@ export function ShoppingListRecipeToJSON(json: any): ShoppingListRecipe {
return ShoppingListRecipeToJSONTyped(json, false); return ShoppingListRecipeToJSONTyped(json, false);
} }
export function ShoppingListRecipeToJSONTyped(value?: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'> | null, ignoreDiscriminator: boolean = false): any { export function ShoppingListRecipeToJSONTyped(value?: Omit<ShoppingListRecipe, 'recipe_data'|'meal_plan_data'|'created_by'> | null, ignoreDiscriminator: boolean = false): any {
if (value == null) { if (value == null) {
return value; return value;
} }