feat(planning): sépare portions demandées et portions préparées #48
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/leftovers-portions-foundations"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Chantier « gestion des restes » (issue #34) — PR 1/4 : les fondations. Aucune UI de panier ni glisser-déposer encore ; juste le découpage portions demandées / préparées et le calcul par lot.
Comportement
À l'ajout d'une recette au planning, on ne saisit plus qu'un seul nombre :
portionsRequested(« on est 3 », « il en faut 10 »). Le serveur calcule combien de portions sont réellement préparées en arrondissant au multiple supérieur du rendement de la recette (on cuisine des lots entiers d'un plat, jamais une fraction) :Modèle (
PlanningItem, purement additif)portionsRequestedNOT NULL— migration nullable → backfill (= portions) → verrou, même discipline que20260819064721_planning_item_portions/ingredient_unit_catalog. Toute ligne existante précède la fonctionnalité, doncdemandé == préparé.sourcePlanningItemId(auto-FK nullable,onDelete: Cascade) +discardedPortions(DEFAULT 0) — posés maintenant, consommés par les PRs suivantes.Logique pure partagée
packages/shared/src/logic/planning-portions.ts:computeBatchedPortions(recipePortions, requested)etcomputeAvailableLeftover(item)— une seule formule appelée des deux côtés (API : dérivation à l'écriture + future validation ; web : indice picker + futur panier).API
addPlanningItemSchemaprendportionsRequested(le client n'envoie plusportions).addPlanningItemcalcule et stocke les deux valeurs ;PlanningItemView/getPlanningForDateexposentportionsRequested/discardedPortions/sourceItemsansincludePrisma supplémentaire.Front
RecipePickerDialog— libellé « Portions demandées » + indice dérivé en direct viacomputeBatchedPortions(« → 12 portions préparées, 2 en restes »), affiché seulement sileftover > 0; envoieportionsRequested.RecipeImportForm— envoieportionsRequested(un import atterrit à son propre rendement → reste nul).Tests
apps/api/test/planning-portions.test.ts— les deux exemples de #34 + bornes (lot exact, plusieurs lots, une portion, recette 1 portion ; pool disponible, service, jet, jamais négatif). Vérifié localement, 10/10.apps/api/test/planning.test.ts— nouveau blocPOST /planning/items(addPlanningItemn'était pas testé du tout) : arrondi au lot, plusieurs lots, borne exacte, 400 surportionsRequestednon positif ; l'assertionGET /planningvérifie aussi les 3 nouveaux champs.prisma.planningItem.create/createManydes suitescooking-session/recipe/shopping-listmises à jour.planning.feature/planning.ts— le corpsPOST /planning/itemsporteportionsRequested.Docs
batch-cooking-modele.md(entité + diagramme),backend-architecture.md(règle de lot),frontend-architecture.md(étape portions).🤖 Generated with Claude Code