# Module — Production / transformation

Permet à une boutique **fabricante** (transformateur) de produire un **produit fini** à partir
de **composants** (matières / intrants) déjà présents au catalogue. Modèle retenu :
**recette à nomenclature fixe** (confirmé avec l'utilisateur).

> Consignation seule — aucune passerelle. La production ne fait que **journaliser** la
> transformation et **mouvementer le stock**.

## Concepts

- **Recette** (`Recipe`) : décrit comment fabriquer un produit fini. `yieldQuantity` = nombre
  d'unités finies produites **par lot**. Une recette a ≥ 1 **composant** (`RecipeComponent`),
  chacun indiquant la quantité consommée **par lot**.
- **Ordre de fabrication** (`ProductionOrder`, append-only, `PRD-AAAA-000000`) : exécuter un
  ordre de N lots :
  1. **contrôle la disponibilité** de chaque composant (stock ≥ quantité requise) — sinon refus
     `422` (`InsufficientStockException`) ;
  2. **consomme** les composants (mouvements de stock `production` négatifs) ;
  3. **crédite** le produit fini (mouvement `production` positif de `yieldQuantity × N`) ;
  4. **roll-up du coût** : coût total = Σ (coût de revient composant × quantité consommée) ;
     coût unitaire du fini = coût total / quantité produite, **recalé** sur `Product.costCents`.
- **Coût de revient** : nouveau champ `Product.costCents` (centimes XOF), saisi au formulaire
  produit et mis à jour automatiquement sur le produit fini à chaque fabrication (coût standard).

## Entités

| Entité | Rôle |
|---|---|
| `Recipe` | Nomenclature : produit fini, `yieldQuantity`, `isActive`, note, composants |
| `RecipeComponent` | Composant : produit consommé + quantité par lot |
| `ProductionOrder` | Journal append-only d'une fabrication (référence, lots, quantité produite, coût total/unitaire, instantané des composants consommés, note, auteur) |
| `Product.costCents` | Coût de revient unitaire (intrant / production) |
| `StockMovement` type `production` | Sorties composants + entrée produit fini |

## API v1

| Action | Endpoint | Gating |
|---|---|---|
| Lister les recettes | `GET /api/v1/recipes` | `COMPANY_VIEW` |
| Détail recette (composants) | `GET /api/v1/recipes/{uuid}` | `COMPANY_VIEW` |
| Créer une recette | `POST /api/v1/recipes` | `COMPANY_EDIT` |
| Modifier une recette | `PUT /api/v1/recipes/{uuid}` | `COMPANY_EDIT` |
| Supprimer une recette | `DELETE /api/v1/recipes/{uuid}` | `COMPANY_EDIT` |
| Lister les fabrications | `GET /api/v1/production-orders` | `COMPANY_VIEW` |
| Détail fabrication (composants consommés) | `GET /api/v1/production-orders/{uuid}` | `COMPANY_VIEW` |
| **Lancer une fabrication** (créer = exécuter) | `POST /api/v1/production-orders` `{recipeUuid, batches, note?}` | `COMPANY_EDIT` |

Permissions RBAC seedées : `production.view` / `production.manage` (accordées au **manager** et au
**magasinier**). Garde-fous : un composant ne peut pas être le produit fini lui-même ; réception
d'une recette sans composant refusée ; stock composant insuffisant → `422`.

## PWA

Écran **Production** (`features/production/`, accès Profil → Gestion) :
- onglet **Recettes** : liste, création/édition (produit fini, rendement, composants + quantités,
  note), suppression, action **Fabriquer** (saisie du nombre de lots) ;
- onglet **Fabrications** : historique des ordres, détail (composants consommés + coûts, coût
  total / unitaire).

Le formulaire **produit** expose désormais le champ **Coût de revient (FCFA)**.

## Tests

`tests/Functional/Api/ProductionApiTest.php` : refus composant = produit fini, fabrication
(consommation composants + entrée fini + roll-up coût + coût produit fini recalé), refus stock
insuffisant, authentification requise.

## Reste à faire / pistes

- Rattacher éventuellement la consommation de production à un ordre planifié (statut `planned` →
  `produced`) si un flux en deux temps devient nécessaire.
- Coût moyen pondéré (au lieu du coût standard) pour le produit fini si souhaité.
