corentin_wakdo/docs/uml/state-commande.md
Corentin JOGUET 32ff6a63ba
All checks were successful
CI / secret-scan (push) Successful in 8s
CI / php-lint (push) Successful in 16s
CI / static-tests (push) Successful in 4s
P1 conception: security-by-design layer (Merise 21 entities, Forgejo CI/CD, hardening) (#3)
2026-06-15 12:16:11 +02:00

152 lines
7.5 KiB
Markdown

# Diagramme d'etats-transitions - Commande
**Phase UML** : P1 - Conception, complement UML (apres MCD)
**Statut** : v0.2 - prod-like, machine a 4 etats
**Date** : 2026-06-11
**Branche** : `feat/p1-conception`
**Auteur methodologie** : BYAN
---
## 1. Objet du document
Ce document formalise la **machine a etats** de l'attribut `customer_order.status`.
Il decrit les etats possibles d'une commande, les transitions autorisees entre
ces etats, les **evenements** qui les declenchent et les **gardes** (conditions)
qui les conditionnent.
Il complete le MCD (`docs/merise/mcd.md`, cycle de vie de la commande), le
dictionnaire (`docs/merise/dictionary.md` 3.10, qui declare l'ENUM `status`) et
le MCT (`docs/merise/mct.md` section 13, qui resume les transitions par
operation).
---
## 2. Source de verite et regle metier
Le modele v0.2 (prod-like) reduit la machine a **quatre etats**. La regle metier
distingue la **composition payee** de la **remise** : une commande est creee et
payee en une operation atomique (la saisie du numero de retrait tient lieu de
paiement dans le cadre RNCP), puis elle est remise au client en un geste unique.
| Source | Valeurs de statut |
|---|---|
| `dictionary.md` 3.10 (ENUM SQL) | `pending_payment`, `paid`, `delivered`, `cancelled` |
| `mct.md` section 13 (transitions) | creer+payer -> remettre, annulation depuis tout etat non terminal |
> Le dictionnaire (`dictionary.md` 3.10) et la machine ci-dessous partagent la
> meme ENUM a 4 valeurs, ce qui maintient la coherence entre le modele de
> donnees et le modele d'etats (cross-validation, mantra #34).
**Etats supprimes par rapport au v0.1** : `preparing` et `ready`. En contexte
fast-food, l'affichage cuisine (KDS) est un dispositif visuel : l'equipier lit
le ticket et agit. Ces deux etats intermediaires ajoutaient des transitions sans
valeur metier proportionnelle. La cuisine est en **lecture seule** ; la remise
(`DELIVER_ORDER`) est le geste unique qui fait avancer le statut. Le KPI est le
temps total `delivered_at - paid_at` (SLA ~10 min) ; la couleur du KDS est
calculee a l'affichage depuis `now - paid_at`, sans etat stocke supplementaire.
---
## 3. Etats retenus
| Etat | Valeur ENUM | Signification | Acteur qui declenche l'entree |
|---|---|---|---|
| En attente de paiement | `pending_payment` | Etat initial transitoire : commande composee, en attente de paiement. Non observable hors transaction (voir section 7). | Client (kiosk) ou Counter/Drive (back-office) |
| Payee | `paid` | Paiement effectue ; la commande entre en file de preparation (lecture seule cuisine). | Client (kiosk) ou Counter/Drive |
| Livree | `delivered` | Remise effectuee au client. Etat **final**. | Counter ou Drive |
| Annulee | `cancelled` | Commande abandonnee ou annulee avant remise. Etat **final**. | Counter, Drive ou Admin |
`pending_payment` est l'etat par defaut a l'INSERT (`dictionary.md` 3.10), mais
la transition vers `paid` est realisee dans la **meme transaction** que la
creation (operations `CREATE_ORDER` / `CREATE_COUNTER_ORDER` du MCT). Il est donc
conserve dans l'ENUM pour la lisibilite du cycle et pour laisser la porte
ouverte a un paiement reel ulterieur sans migration destructive.
---
## 4. Diagramme d'etats-transitions
```mermaid
stateDiagram-v2
[*] --> pending_payment : creer la commande (kiosk / counter / drive)
pending_payment --> paid : payer\n[atomique dans CREATE_ORDER / CREATE_COUNTER_ORDER\nsaisie du numero = substitut de paiement]
pending_payment --> cancelled : annuler\n[avant remise]
paid --> delivered : remettre au client\n[acteur Counter / Drive, geste unique]
paid --> cancelled : annuler\n[Counter / Drive / Admin, re-credit du stock]
delivered --> [*]
cancelled --> [*]
```
---
## 5. Transitions detaillees
| # | De | Vers | Evenement declencheur | Garde (condition) | Acteur |
|---|---|---|---|---|---|
| T1 | (initial) | `pending_payment` | Creation de la commande composee | Au moins une ligne (`order_item`) ; numero de retrait non vide | Client / Counter / Drive |
| T2 | `pending_payment` | `paid` | Paiement (atomique a la creation) | La commande contient au moins une `order_item` ; decrement du stock et insert dans la meme transaction | Client / Counter / Drive |
| T3 | `pending_payment` | `cancelled` | Abandon avant paiement | Commande pas encore payee | Counter / Drive / Admin |
| T4 | `paid` | `delivered` | Remise physique au client | La commande est `paid` ; l'acteur detient `order.deliver` ; source compatible avec son role (`role_visible_source`) | Counter / Drive |
| T5 | `paid` | `cancelled` | Annulation avant remise | L'acteur detient `order.cancel` ; le stock consomme est re-credite (`stock_movement` type `cancellation`) | Counter / Drive / Admin |
### Invariants de la machine a etats
- `delivered` et `cancelled` sont des etats **finaux** : aucune transition n'en
sort.
- Aucune transition ne revient en arriere. Une erreur operationnelle se traite
par annulation puis nouvelle commande, pour preserver l'integrite de
l'historique et des snapshots (`label_snapshot`, `unit_price_cents_snapshot`,
`vat_rate_snapshot` sur `order_item`).
- La transition vers `cancelled` est possible depuis `pending_payment` et
`paid`, mais pas depuis `delivered` (une commande remise ne s'annule pas dans
ce modele). Coherent avec `mct.md` 7.1 (`CANCEL_ORDER`).
- `paid_at` (DATETIME, `dictionary.md` 3.10) est renseigne a la transition T2.
`delivered_at` est renseigne a T4. `cancelled_at` est renseigne a T3/T5. Les
trois colonnes sont NULL tant que la transition correspondante n'a pas eu lieu.
- La cuisine (`kitchen`) ne declenche aucune transition : son acces a la file
des commandes `paid` est en **lecture seule** (`mct.md` 5.1,
`LIST_ORDERS_DISPLAY`).
---
## 6. Coherence avec les autres livrables
| Verification | Resultat |
|---|---|
| Tous les etats du diagramme existent dans l'ENUM `dictionary.md` 3.10 | Oui (4 valeurs, toutes utilisees) |
| La regle "annulation possible sauf depuis delivered" de `mct.md` 7.1 | Respectee (T3, T5 ; pas de transition depuis `delivered`) |
| Transition `paid -> delivered` en geste unique de `mct.md` 6.1 | Couvert par T4 (`DELIVER_ORDER`) |
| Atomicite `pending_payment -> paid` de `mct.md` 3.3 / 4.1 / section 13 | Couvert par T2 (saisie du numero = substitut de paiement) |
| Acteurs de `use-cases.md` | Counter/Drive declenchent T4/T5 ; Admin peut annuler (T3/T5) ; Kitchen en lecture seule |
| Timestamps de phase `paid_at` / `delivered_at` / `cancelled_at` | Renseignes a T2 / T4 / T3-T5 |
---
## 7. Arbitrage tranche
La machine retenue est reduite a quatre etats (Decision 4,
`docs/notes/revue-alignement-p1.md` section 7) :
```
pending_payment -> paid -> delivered
| |
+------------+--------> cancelled (depuis pending_payment ou paid)
```
**Note sur la transition `pending_payment -> paid`** : dans le cadre RNCP, le
paiement est remplace par la saisie du numero de commande (kiosk) ou par la
validation de l'equipier (counter/drive). La transition est **atomique** dans
`CREATE_ORDER` et `CREATE_COUNTER_ORDER` : le statut `pending_payment` n'est pas
observable en dehors de la transaction de creation. Il reste declare dans l'ENUM
pour exprimer le cycle de vie complet et pour autoriser un paiement reel
ulterieur (cout d'une valeur d'ENUM).
Les etats `preparing` et `ready` du v0.1 sont supprimes : la cuisine est un
affichage visuel en lecture seule, et la remise fusionne preparation+remise en
un geste unique (`DELIVER_ORDER`). Effet de bord propage : les operations
`MARK_IN_PREPARATION` et `MARK_READY` disparaissent du MCT (voir `mct.md`
sections 1 et 13).