# ADR-012 : Réception contrôlée des achats

**Statut :** Accepté
**Date :** 2026-10-15
**Contexte :** Lot 7 de la feuille de route restauration — capacité générique (ADR-006), sur le socle du stock théorique daté (ADR-007) et du prix d'achat réel (ADR-008)

---

## Contexte

Un achat porte un statut `ordered`, `pending` ou `received`, mais **ce statut n'a aucun effet** : une commande seulement passée au fournisseur compte déjà dans le stock. Deux conséquences :
- le stock théorique est faux dès qu'une commande est saisie avant la livraison ;
- personne ne contrôle ce qui arrive vraiment. Une livraison de 22 bouteilles facturées 24 passe inaperçue, et les 2 bouteilles manquantes réapparaissent plus tard comme une perte inexpliquée à l'inventaire, imputée à l'équipe.

La note produit demande une « réception contrôlée » : quantité reçue, réceptionnaire, écart entre commandé et reçu.

Mesure faite avant décision (15/10/2026) : **la production ne contient aucun achat**. Changer la règle ne modifie le stock d'aucun tenant en production.

## Décision

### 1. Seul le reçu compte dans le stock

- Un achat entre dans le stock **uniquement** au statut `received`.
- Il y entre pour la **quantité reçue** (`order_items.received_quantity`), ou la quantité commandée si la ligne n'a pas de réception détaillée (achat saisi directement au statut « Reçu »).
- Il y entre à la **date de réception** (`orders.received_at`), ou à la date de l'achat à défaut. Le stock théorique daté (ADR-007 §4) suit la même règle.

`Common::recalculateOrderStock` et `StockLedgerService::theoreticalStocksAt` appliquent cette règle et restent identiques entre eux (invariant testé). Les retours d'achat, les ventes et les retours de vente ne changent pas.

### 2. Réceptionner une commande

Un écran « Réceptions » liste les achats non reçus de l'entrepôt. Le réceptionnaire saisit pour chaque ligne la quantité **effectivement livrée** (en casiers si la ligne a été commandée en conditionnement, ADR-011), puis la date de réception :
- **Saisie en aveugle** : l'écran de réception n'affiche pas la quantité commandée, pour qu'on compte la livraison au lieu de recopier le bon de commande (même principe que l'inventaire, ADR-010). Les quantités commandées et les écarts apparaissent une fois la réception validée. L'aveugle n'est pas une barrière d'accès : le personnel a `purchases_view` par défaut et peut ouvrir l'achat ; c'est le geste par défaut de l'écran qui pousse à compter.
- Toutes les lignes doivent être saisies, zéro compris : une ligne oubliée n'est pas réputée livrée.
- La date de réception n'est ni dans le futur, ni antérieure à la commande, ni dans une période clôturée (ADR-007 §3).
- La réception est une transaction unique (ligne de commande verrouillée) : statut `received`, `received_at`, `received_by`, notes, quantités reçues, recalcul du stock et mise à jour du prix d'achat catalogue (ADR-008 §2).
- Une commande déjà réceptionnée est refusée (422) : pas de double entrée en stock.

Le résultat affiche les **écarts de livraison** (reçu − commandé) valorisés au prix de la ligne, à réclamer au fournisseur.

### 3. Les montants restent ceux de la commande

La réception ne modifie ni les prix ni les montants dus au fournisseur. Un manque à la livraison est une **réclamation** : il est visible dans le détail de l'achat et dans le résultat de la réception, et se règle avec le fournisseur (avoir, livraison complémentaire). Modifier la dette automatiquement supposerait que la facture suit toujours le bon de livraison, ce qui n'est pas garanti.

### 4. Commandes non reçues et verrouillage

Une commande non reçue n'a aucun effet sur le stock : sa modification n'est contrôlée par le verrou de période que sur sa **date de stock** (réception), pas sur sa date de commande. Une commande passée avant un inventaire et livrée après peut donc être réceptionnée.

Repasser un achat reçu à « Commandé » efface sa réception (quantités reçues, date, réceptionnaire), dans les mêmes limites de verrouillage.

### 5. Accès

| Action | Permission | Rôle par défaut |
|---|---|---|
| Lister les commandes à recevoir, réceptionner | `purchases_receive` | admin, personnel |

Pas de droit de plan : capacité générique (ADR-006).

### 6. Rapport d'écarts

Le rapport d'un inventaire (ADR-010 §3) liste les réceptions de la période, avec le réceptionnaire et le nombre de lignes livrées en manque : un écart inexpliqué sur un produit peut venir d'une livraison mal contrôlée.

## Alternatives Considérées

### Laisser le statut sans effet et ajouter seulement une quantité reçue
Rejeté. Le stock théorique resterait faux entre la commande et la livraison, et l'écart d'inventaire mélangerait commandes non livrées et vols.

### Réceptions partielles multiples
Différé. Une commande est livrée en une fois dans la quasi-totalité des cas observés ; un reliquat se saisit comme une nouvelle commande. L'ajout restera possible avec une table `purchase_receptions` dédiée.

### Ajuster la dette fournisseur au reçu
Rejeté pour la v1 (voir §3).

## Conséquences

- Nouvelles colonnes nullables : `orders.received_at`, `orders.received_by`, `orders.reception_notes`, `order_items.received_quantity`. Elles sont protégées contre l'affectation de masse : seule la réception les écrit.
- Les achats existants au statut `ordered` ou `pending` **sortent du stock**. La migration recalcule les produits concernés. Aucun en production au 15/10/2026 ; staging et les bases de démonstration peuvent en contenir.
- Le formulaire d'achat garde le statut « Reçu » pour la saisie directe d'une facture déjà livrée : c'est le cas le plus courant pour un petit commerce.
- Nouvelle permission `purchases_receive`, accordée aux rôles `admin` et `personnel` existants.

## Quand Réviser

- Si les livraisons partielles deviennent fréquentes : réceptions multiples par commande.
- Si les clients veulent que la dette fournisseur suive le reçu : ajustement des montants à la réception, avec trace.
