feat: refactor inventory and recipe services for improved error handling and code reuse; add systematic backend review plan
Test Suite / test (24.15.0) (push) Has been cancelled
Test Suite / test (24.15.0) (push) Has been cancelled
This commit is contained in:
@@ -68,11 +68,8 @@ export class MealPlanService {
|
||||
return this.prisma.mealPlanEntry.delete({ where: { id: entry.id } });
|
||||
}
|
||||
|
||||
/** Samlad ingredienslista för ett datumintervall */
|
||||
async shoppingList(userId: number, from: string, to: string) {
|
||||
const entries = await this.findByRange(userId, from, to);
|
||||
|
||||
// Summera ingredienser per produkt+enhet (skalat per portionsantal)
|
||||
/** Aggregerar ingredienser per produkt+enhet från matplansposter, skalat per portionsantal */
|
||||
private aggregateIngredients(entries: Awaited<ReturnType<typeof this.findByRange>>) {
|
||||
const map = new Map<string, { productId: number; name: string; quantity: number; unit: string }>();
|
||||
for (const entry of entries) {
|
||||
const recipeServings = (entry.recipe as any).servings as number | null;
|
||||
@@ -80,8 +77,8 @@ export class MealPlanService {
|
||||
const scale = recipeServings && entryServings ? entryServings / recipeServings : 1;
|
||||
for (const ing of entry.recipe.ingredients) {
|
||||
const key = `${ing.product.id}-${ing.unit}`;
|
||||
const existing = map.get(key);
|
||||
const qty = Number(ing.quantity) * scale;
|
||||
const existing = map.get(key);
|
||||
if (existing) {
|
||||
existing.quantity += qty;
|
||||
} else {
|
||||
@@ -94,8 +91,13 @@ export class MealPlanService {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
return Array.from(map.values()).sort((a, b) => a.name.localeCompare(b.name, 'sv'));
|
||||
/** Samlad ingredienslista för ett datumintervall */
|
||||
async shoppingList(userId: number, from: string, to: string) {
|
||||
const entries = await this.findByRange(userId, from, to);
|
||||
return this.aggregateIngredients(entries).sort((a, b) => a.name.localeCompare(b.name, 'sv'));
|
||||
}
|
||||
|
||||
/** Jämför veckans ingrediensbehov mot inventariet */
|
||||
@@ -109,32 +111,16 @@ export class MealPlanService {
|
||||
});
|
||||
const pantryProductIds = new Set(pantryItems.map((p) => p.productId));
|
||||
|
||||
// Aggregera ingredienser per produkt+enhet (skalat per portionsantal)
|
||||
const map = new Map<string, { productId: number; name: string; required: number; unit: string }>();
|
||||
for (const entry of entries) {
|
||||
const recipeServings = (entry.recipe as any).servings as number | null;
|
||||
const entryServings = (entry as any).servings as number | null;
|
||||
const scale = recipeServings && entryServings ? entryServings / recipeServings : 1;
|
||||
for (const ing of entry.recipe.ingredients) {
|
||||
const key = `${ing.product.id}-${ing.unit}`;
|
||||
const qty = Number(ing.quantity) * scale;
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const aggregated = this.aggregateIngredients(entries).map((item) => ({
|
||||
productId: item.productId,
|
||||
name: item.name,
|
||||
required: item.quantity,
|
||||
unit: item.unit,
|
||||
}));
|
||||
|
||||
// Kontrollera inventariet för varje ingrediens
|
||||
const result = await Promise.all(
|
||||
Array.from(map.values()).map(async (item) => {
|
||||
aggregated.map(async (item) => {
|
||||
// Pantry-varor anses alltid tillgängliga — visa inte i inköpslistan
|
||||
if (pantryProductIds.has(item.productId)) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user