Première PR du chantier « gestion des restes » (issue #34) — les fondations, sans encore d'UI de panier. À l'ajout d'une recette au planning on ne saisit plus qu'un seul nombre, `portionsRequested` (« combien ce créneau doit nourrir »). Le serveur en dérive `portions` (ce qui est réellement préparé) via `computeBatchedPortions` : arrondi au multiple supérieur du rendement de la recette (on cuisine des lots entiers, jamais une fraction de plat). L'écart est le futur pool de restes de l'item. Modèle (`PlanningItem`, purement additif) : - `portionsRequested` NOT NULL — migration nullable → backfill (`= portions` pour les lignes existantes, sans restes à l'époque) → verrou, même discipline que `ingredient_unit_catalog`. - `sourcePlanningItemId` (auto-FK nullable, `onDelete: Cascade`) et `discardedPortions` (défaut 0) — posés maintenant, utilisés plus tard. Partagé (`@batch-cooking/shared/logic/planning-portions.ts`) : - `computeBatchedPortions(recipePortions, requested)` → `{ portions, leftover }` - `computeAvailableLeftover(item)` → pool encore disponible (posé pour les PRs suivantes : validation d'écriture côté API, affichage du panier côté web — une seule formule, deux appelants) API : `addPlanningItemSchema` prend `portionsRequested` ; `addPlanningItem` calcule et stocke les deux valeurs + l'évènement analytics ; `PlanningItemView` et `getPlanningForDate` exposent `portionsRequested`/`discardedPortions`/ `sourceItem`. Front : `RecipePickerDialog` — champ « portions demandées » + indice en direct « → N préparées, M en restes » quand l'arrondi crée un reste ; envoie `portionsRequested`. `RecipeImportForm` — envoie `portionsRequested` (un import atterrit à son propre rendement, donc reste nul). Tests : `planning-portions.test.ts` (les deux exemples de #34 + bornes) ; nouveau bloc `POST /planning/items` dans `planning.test.ts` (arrondi au lot, plusieurs lots, borne exacte, 400 sur non-positif) ; fixtures `planningItem.create` des suites existantes mises à jour ; scénario Cypress planning ajusté (`portionsRequested` dans le corps). Docs : `batch-cooking-modele.md`, `backend-architecture.md`, `frontend-architecture.md`. Réf #34 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
59 lines
3.1 KiB
Gherkin
59 lines
3.1 KiB
Gherkin
Feature: Adding a recipe to the planning
|
|
As a signed-in user
|
|
I want to add a recipe to a planning slot even when I haven't imported it yet
|
|
So that browsing an external source and planning it is a single trip
|
|
|
|
Background:
|
|
Given I am signed in as "Alice" "Martin"
|
|
And my household id is 1
|
|
And today is frozen at "2026-08-17T09:00:00.000Z"
|
|
And the household request returns no household
|
|
And the recipe catalog contains nothing
|
|
And the ingredient and diet catalog is available for import
|
|
And the sources reference list has options
|
|
And the household has enabled TheMealDB
|
|
And browsing TheMealDB returns some items
|
|
And the planning request returns nothing
|
|
|
|
Scenario: Selecting a source item only previews it, the footer's Confirmer is what acts on it
|
|
Given previewing TheMealDB item "9999" is available
|
|
When I visit "/"
|
|
And I click the add button for the first empty planning slot
|
|
And I click the button "TheMealDB"
|
|
And I click the source item "Fish Pie"
|
|
Then the recipe detail panel heading should be "Fish Pie"
|
|
And the URL should be the home page
|
|
|
|
Scenario: Confirming a not-yet-imported source item lands on the embedded review form since an ingredient needs resolving
|
|
Given previewing TheMealDB item "9999" is available
|
|
And importing the previewed item will succeed and return id 99
|
|
And adding the imported recipe to the planning will succeed
|
|
When I visit "/"
|
|
And I click the add button for the first empty planning slot
|
|
And I click the button "TheMealDB"
|
|
And I click the source item "Fish Pie"
|
|
And I click the button "Confirmer"
|
|
Then I should see "Cette recette sera automatiquement ajoutée à votre planning une fois importée."
|
|
|
|
When I choose an ingredient for the unresolved line "some mystery paste"
|
|
And I select the ingredient "Sel" from the picker
|
|
And I select unit "unité" for the first ingredient
|
|
And I fill in the last ingredient's quantity with "1" and unit "unité"
|
|
And I click the button "Importer"
|
|
Then the planning add request should have included recipe 99, weekDay "lundi", meal "petit-dejeuner", and requested portions 4
|
|
And the recipe picker dialog should be closed
|
|
And the recipe "Fish Pie" should appear in the first planning slot with 4 portions
|
|
|
|
Scenario: Confirming a fully-resolved not-yet-imported item adds it to the planning transparently, with no review screen at all
|
|
Given previewing TheMealDB item "7777" is fully resolved as "Ratatouille"
|
|
And importing item "7777" will succeed and return id 100
|
|
And adding recipe 100 to the planning will succeed
|
|
When I visit "/"
|
|
And I click the add button for the first empty planning slot
|
|
And I click the button "TheMealDB"
|
|
And I click the source item "Ratatouille"
|
|
And I click the button "Confirmer"
|
|
Then the import request for "7777" should have included the name "Ratatouille"
|
|
And the planning add request should have included recipe 100, weekDay "lundi", meal "petit-dejeuner", and requested portions 4
|
|
And the recipe picker dialog should be closed
|
|
And the recipe "Ratatouille" should appear in the first planning slot with 4 portions
|