feat: add servings field to Recipe model and implement inventory comparison functionality
This commit is contained in:
@@ -16,6 +16,11 @@ export class MealPlanController {
|
||||
return this.mealPlanService.shoppingList(from, to);
|
||||
}
|
||||
|
||||
@Get('inventory-compare')
|
||||
inventoryCompare(@Query('from') from: string, @Query('to') to: string) {
|
||||
return this.mealPlanService.inventoryCompare(from, to);
|
||||
}
|
||||
|
||||
@Post()
|
||||
upsert(@Body() dto: CreateMealPlanEntryDto) {
|
||||
return this.mealPlanService.upsert(dto);
|
||||
|
||||
@@ -77,4 +77,55 @@ export class MealPlanService {
|
||||
|
||||
return Array.from(map.values()).sort((a, b) => a.name.localeCompare(b.name, 'sv'));
|
||||
}
|
||||
|
||||
/** Jämför veckans ingrediensbehov mot inventariet */
|
||||
async inventoryCompare(from: string, to: string) {
|
||||
const entries = await this.findByRange(from, to);
|
||||
|
||||
// Aggregera ingredienser per produkt+enhet
|
||||
const map = new Map<string, { productId: number; name: string; required: number; unit: string }>();
|
||||
for (const entry of entries) {
|
||||
for (const ing of entry.recipe.ingredients) {
|
||||
const key = `${ing.product.id}-${ing.unit}`;
|
||||
const qty = Number(ing.quantity);
|
||||
const existing = map.get(key);
|
||||
if (existing) {
|
||||
existing.required += qty;
|
||||
} else {
|
||||
map.set(key, {
|
||||
productId: ing.product.id,
|
||||
name: ing.product.canonicalName || ing.product.name,
|
||||
required: qty,
|
||||
unit: ing.unit,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kontrollera inventariet för varje ingrediens
|
||||
const result = await Promise.all(
|
||||
Array.from(map.values()).map(async (item) => {
|
||||
const inventoryItems = await this.prisma.inventoryItem.findMany({
|
||||
where: { productId: item.productId },
|
||||
});
|
||||
const available = inventoryItems
|
||||
.filter((i: any) => i.unit.trim().toLowerCase() === item.unit.trim().toLowerCase())
|
||||
.reduce((sum: number, i: any) => sum + Number(i.quantity), 0);
|
||||
return {
|
||||
productId: item.productId,
|
||||
name: item.name,
|
||||
required: item.required,
|
||||
unit: item.unit,
|
||||
available,
|
||||
missing: Math.max(0, item.required - available),
|
||||
status: (available >= item.required ? 'enough' : 'missing') as 'enough' | 'missing',
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return result.sort((a, b) => {
|
||||
if (a.status !== b.status) return a.status === 'missing' ? -1 : 1;
|
||||
return a.name.localeCompare(b.name, 'sv');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user