feat(veckoplan): tillbehor (t.ex. potatisgratang) foreslar proteinbit
Rena tillbehor utan protein i titeln (potatisgratang, mos, pommes) far en not: 'servera med en proteinbit (ryggbiff/entrecote, kyckling, fisk eller tofu/halloumi)'. Kott-/korv-/fiskgratanger raknas som hela ratter. Verifierat mot riktig data: 5 av 19 gratang-traffar klassas som tillbehor, inga falska traffar pa proteinratter.
This commit is contained in:
@@ -232,6 +232,17 @@ export async function processGenerateWeekPlan(
|
|||||||
`${r.cuisine}|${isSoup(r) ? "soup" : "dish"}`;
|
`${r.cuisine}|${isSoup(r) ? "soup" : "dish"}`;
|
||||||
let lastSignature: string | null = null;
|
let lastSignature: string | null = null;
|
||||||
|
|
||||||
|
// Tillbehör/sides (t.ex. potatisgratäng, mos, pommes) är inte en hel middag
|
||||||
|
// i sig. Om titeln redan innehåller ett protein (köttfärs-/korvgratäng) är den
|
||||||
|
// komplett. Annars föreslår vi en proteinbit att servera till.
|
||||||
|
const proteinWords =
|
||||||
|
/kött|korv|kyckling|lax|fisk|fläsk|skinka|biff|färs|räk|tofu|halloumi|ägg|bön|lins|kikärt|falafel|quorn|chorizo|bacon|lamm|anka|kalkon|tonfisk|torsk|sill/i;
|
||||||
|
const sideWords = /gratäng|potatismos|rotmos|pommes|klyftpotatis|potatisstomp|potatissallad/i;
|
||||||
|
const isSideDish = (r: { titleSv: string }) =>
|
||||||
|
sideWords.test(r.titleSv) && !proteinWords.test(r.titleSv);
|
||||||
|
const sideSuggestion =
|
||||||
|
"Tillbehör – servera med en proteinbit: t.ex. en stekt eller grillad ryggbiff eller entrecôte, kyckling, fisk, eller tofu/halloumi för en vegetarisk variant.";
|
||||||
|
|
||||||
for (let day = 0; day < days; day++) {
|
for (let day = 0; day < days; day++) {
|
||||||
const date = new Date(Date.parse(data.input.weekStartDate) + day * 86_400_000)
|
const date = new Date(Date.parse(data.input.weekStartDate) + day * 86_400_000)
|
||||||
.toISOString()
|
.toISOString()
|
||||||
@@ -288,6 +299,13 @@ export async function processGenerateWeekPlan(
|
|||||||
recipeUseCount.set(chosen.recipe.id, (recipeUseCount.get(chosen.recipe.id) ?? 0) + 1);
|
recipeUseCount.set(chosen.recipe.id, (recipeUseCount.get(chosen.recipe.id) ?? 0) + 1);
|
||||||
usedRecipeIds.add(chosen.recipe.id);
|
usedRecipeIds.add(chosen.recipe.id);
|
||||||
const expiring = chosen.coverage.expiringUsed[0];
|
const expiring = chosen.coverage.expiringUsed[0];
|
||||||
|
const notes: string[] = [];
|
||||||
|
if (isSideDish(chosen.recipe) && (mealType === "lunch" || mealType === "dinner")) {
|
||||||
|
notes.push(sideSuggestion);
|
||||||
|
}
|
||||||
|
if (expiring) {
|
||||||
|
notes.push(`Använder ${expiring.displayNameSv.toLowerCase()} som bör ätas snart.`);
|
||||||
|
}
|
||||||
entries.push({
|
entries.push({
|
||||||
weekPlanId,
|
weekPlanId,
|
||||||
date,
|
date,
|
||||||
@@ -296,9 +314,7 @@ export async function processGenerateWeekPlan(
|
|||||||
titleSv: chosen.recipe.titleSv,
|
titleSv: chosen.recipe.titleSv,
|
||||||
portions,
|
portions,
|
||||||
status: "planned",
|
status: "planned",
|
||||||
rescheduleReasonSv: expiring
|
rescheduleReasonSv: notes.length > 0 ? notes.join(" ") : null,
|
||||||
? `Använder ${expiring.displayNameSv.toLowerCase()} som bör ätas snart.`
|
|
||||||
: null,
|
|
||||||
sortOrder: entries.length,
|
sortOrder: entries.length,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user