# Cahier des Charges — Compositions de formules dépendantes des variantes saisonnières (`t_formule_variant`)

---

## 1. Contexte et analyse de l'existant

### 1.1 Architecture actuelle

Le système SmartCentral gère des **formules de béton** dont la **composition** (liste des produits et quantités) peut varier selon la **centrale** de production. Les entités clés sont :

| Entité | Table | Rôle |
|--------|-------|------|
| **Formule** | `t_formule` | Recette de béton (code, appellation commerciale, classes…) |
| **Centrale** | `t_centrale` | Site de production physique |
| **Composition** | `t_composition` | Ligne de composition (produit + quantité) liée à une formule, une centrale **et une variante** |
| **Formule Détail** | `t_formule_detail` | Paramètres techniques d'une formule par centrale (temps malaxage, slump…) |
| **Formule Variante** | `t_formule_variant` | Table de référence des variantes (code, libellé, **statut active**) |
| **Formule Centrale** | `t_formule_centrale` | Pivot : quelles formules sont disponibles dans quelles centrales |
| **Groupe Centrale Formule** | `t_groupe_centrale_formule` | Groupement de centrales partageant les mêmes compositions |

### 1.2 Relations actuelles (schéma mis à jour)

```mermaid
erDiagram
    t_formule ||--o{ t_composition : "1 → N"
    t_centrale ||--o{ t_composition : "1 → N"
    t_formule_variant ||--o{ t_composition : "1 → N (via formule_variant_id - ON DELETE CASCADE)"
    t_formule ||--o{ t_formule_detail : "1 → N"
    t_centrale ||--o{ t_formule_detail : "1 → N"
    t_formule }o--o{ t_centrale : "N → N (t_formule_centrale)"

    t_composition {
        int id_composition PK
        int formule_id FK
        int centrale_id FK
        int formule_variant_id FK
        int produit_id
        int composition_type
        float composition_quantite
        string composition_produit_code
        string composition_produit_libelle
        bool composition_imprimable
        bool composition_facturable
    }

    t_formule_variant {
        int id_formule_variant PK
        string formule_variant_code
        string formule_variant_libelle
        bool formule_variant_active
    }
```

---

## 2. Distinction fondamentale : Variante Active vs Variante Sélectionnée

Afin de répondre précisément aux enjeux opérationnels, l'application distingue deux notions :

```
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ 1. VARIANTE ACTIVE (Stockée dans t_formule_variant.formule_variant_active)             │
│    - Définie au niveau global dans le module "Variantes de formules".                   │
│    - Une seule variante est active à la fois dans tout le système (ex: "Été").         │
│    - Détermine les recettes utilisées en PRODUCTION, DEPART CYCLE & BONS DE LIVRAISON.│
└────────────────────────────────────────────────────────────────────────────────────────┘
                                           │
                                           ▼
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ 2. VARIANTE SÉLECTIONNÉE (Select dans l'onglet Composition & Paramètre d'export)       │
│    - Sélectionnée par l'utilisateur dans l'onglet Composition de la Fiche Formule.     │
│    - Détermine le tableau affiché, les CALCULS (coûts, E/C, masses...) & EXPORTS EXCEL.│
│    - L'utilisateur peut ainsi calculer/exporter la variante "Hiver" pendant qu'"Été"  │
│      tourne en production.                                                             │
└────────────────────────────────────────────────────────────────────────────────────────┘
```

---

## 3. Workflow de Création, Duplication et Suppression des Variantes

### 3.1 Suppression des boutons d'ajout à blanc
- **Dans l'index (`formule_variant/index.blade.php`)** : Suppression du bouton **« Ajouter »**.
- **Dans le formulaire (`formule_variant/form.blade.php`)** : Suppression du bouton **« Nouveau »** (`#reset`).

### 3.2 Création uniquement par duplication de variante
Dans le formulaire d'une variante existante, un nouveau bouton **« Créer à partir de cette variante »** est disponible :
1. L'utilisateur ouvre une variante source (ex: variante *"Défaut"*).
2. Il saisit le Code et le Libellé de la nouvelle variante (ex: *"Hiver"*).
3. Il clique sur **« Créer à partir de cette variante »**.
4. Le système enregistre la nouvelle variante en BDD.
5. **Duplication automatique** : Le serveur copie en masse toutes les lignes de la table `t_composition` rattachées à la variante source (`formule_variant_id = ID_source`) vers la nouvelle variante (`formule_variant_id = ID_nouvelle`).
6. La nouvelle variante dispose instantanément d'une copie conforme de l'ensemble des compositions de la variante d'origine.

### 3.3 Suppression en cascade
- Lorsqu'une variante est supprimée :
  - **Interdiction** : Si la variante est actuellement active (`formule_variant_active = 1`), la suppression est refusée avec un message explicatif ("Impossible de supprimer la variante actuellement active").
  - **Cascade BDD & Logicielle** : Si la variante n'est pas active, la suppression entraîne automatiquement la **suppression de toutes les lignes de compositions rattachées** dans `t_composition` (`composition::where('formule_variant_id', $id)->delete()`).

---

## 4. Spécifications fonctionnelles et Règles métier

### 4.1 Règles métier

| # | Règle | Description |
|---|-------|-------------|
| R1 | **Stockage de la variante active** | La variante active est matérialisée par le champ `formule_variant_active = 1` dans `t_formule_variant`. Une seule ligne peut avoir cette valeur à `1`. |
| R2 | **Variante par défaut et migration** | Lors de la migration initiale, une variante par défaut `"Défaut"` est créée et activée. Toutes les compositions existantes (`formule_variant_id = 0`) basculent sur cet ID. |
| R3 | **Création uniquement par duplication** | Pas de création de variante « à blanc ». Une nouvelle variante est obligatoirement dupliquée depuis une variante existante avec toutes ses compositions. |
| R4 | **Variante sélectionnée par défaut** | Dans l'onglet Composition d'une formule, le champ `Variante` d'en-tête est pré-sélectionné par défaut sur la variante active. |
| R5 | **Affichage et Calculs basés sur la variante sélectionnée** | Le tableau des compositions ainsi que l'ensemble des calculs techniques (masse volumique, dosage ciment, rapport E/C, coût formule, empreinte carbone) sont calculés en temps réel en fonction du couple [Centrale + Variante sélectionnée]. |
| R6 | **Exports Excel basés sur la variante sélectionnée** | Les exports Excel de formules / compositions s'exécutent en fonction de la variante sélectionnée. |
| R7 | **Production et Départ Cycle** | La production réelle et le départ cycle en centrale s'exécutent sur la **variante active** (`formule_variant_active = 1`). |
| R8 | **Indicateur visuel d'état** | Un badge bien visible dans l'onglet Composition indique la variante active en production (ex: `🟢 Variante Active en production : Été`). |
| R9 | **Suppression en cascade** | Une variante peut être supprimée (sauf si elle est active). Toutes ses compositions associées dans `t_composition` sont supprimées en cascade. |

---

## 5. Modifications techniques proposées

### 5.1 Base de données

#### Migration : Ajout du champ `formule_variant_active` dans `t_formule_variant`

```php
Schema::table('t_formule_variant', function (Blueprint $table) {
    $table->boolean('formule_variant_active')->default(0);
});
```

*Script de migration de données inclus :*
1. Création automatique d'une variante par défaut (code `"DEF"`, libellé `"Défaut"`).
2. Activation de cette variante (`formule_variant_active = 1`).
3. Mise à jour de toutes les lignes `t_composition` ayant `formule_variant_id = 0` vers l'ID de la variante `"Défaut"`.

---

### 5.2 Modèles Eloquent

#### `app/Models/formule_variant.php`
- Méthode statique `getActive()` : `return static::where('formule_variant_active', 1)->first();`
- Méthode `activer()` : désactive les autres et active la variante courante.
- Relation `lier_compositions()` (`hasMany` vers `composition`).

#### `app/Models/composition.php`
- Relation `lier_formule_variant()` (`belongsTo` vers `formule_variant`).

---

### 5.3 Contrôleurs

#### `app/Http/Controllers/formule_variant_controller.php`
- `data_table()` : Supprime le bouton Ajouter. Affiche le statut Active / Inactive.
- `dupliquer(Request $request)` :
  - Valide le nouveau code et libellé.
  - Enregistre la nouvelle variante `formule_variant`.
  - Copie les compositions de la variante source vers la nouvelle variante.
- `activer($id)` : Active la variante et consigne l'action dans la traçabilité.
- `supprimer($id)` :
  - Si `$formule_variant->formule_variant_active == 1` : retourne une erreur JSON (`"Impossible de supprimer la variante actuellement active"`).
  - Sinon : supprime les compositions rattachées (`composition::where('formule_variant_id', $id)->delete()`), supprime la variante et consigne la traçabilité.

#### `app/Http/Controllers/formule_controller.php`
- `afficher_formulaire()` : Transmet les variantes et la variante active.
- `data_table_composition()` : Filtre la composition par `centrale_id` ET `formule_variant_id` (variante sélectionnée).
- `composition_enregistrer()` : Enregistre la ligne pour le `formule_variant_id` sélectionné.
- `composition_calcul()` : Exécute les calculs sur la variante sélectionnée.
- `exporter_formule_*()` : Génère les exports sur la variante sélectionnée.

---

### 5.4 Vues Blade & Interface Utilisateur

#### `resources/views/formule_variant/index.blade.php`
- Suppression du bouton Ajouter.
- Colonne **ACTIVE** + Bouton action **Activer**.

#### `resources/views/formule_variant/form.blade.php`
- Suppression du bouton Nouveau.
- Bouton **« Créer à partir de cette variante »**.

#### `resources/views/formule/form.blade.php` (Onglet Composition)
- Menu déroulant Variante en en-tête.
- Badge visuel variante active en production.
- Pas de colonne variante dans `#table_composition`.
- Les calculs et évènements s'exécutent sur la variante sélectionnée.

---

### 5.5 Traits, Helpers & Exports

#### `app/Traits/composition_calcul_trait.php`
- La méthode `composition_calculer(Request $request)` lit `$request->input('formule_variant_id')` pour aller chercher les lignes de composition de la variante demandée.

#### `app/Exports/export_formule_avec_detail.php`
- Reçoit le `$formule_variant_id` dans le constructeur et filtre les compositions sur cette variante.

---

## 6. Synthèse des fichiers impactés

| Fichier | Nature du changement |
|---------|----------------------|
| **Migration BDD** (nouveau) | Ajout `formule_variant_active` + Création variante "Défaut" + Migration `formule_variant_id = 0` |
| `app/Models/formule_variant.php` | Méthodes `getActive()`, `activer()`, relation compositions |
| `app/Models/composition.php` | Relation `lier_formule_variant` |
| `app/Http/Controllers/formule_variant_controller.php` | Méthodes `dupliquer()`, `activer()`, `supprimer()` avec suppression en cascade des compositions |
| `app/Http/Controllers/formule_controller.php` | Filtrage composition et calculs par `centrale_id` + `formule_variant_id` |
| `resources/views/formule_variant/index.blade.php` | Suppression bouton Ajouter, colonne Active + bouton Activer |
| `resources/views/formule_variant/form.blade.php` | Suppression bouton Nouveau, ajout du bouton "Créer à partir de cette variante" |
| `resources/views/formule/form.blade.php` | Select variante + badge variante active dans l'onglet Composition |
| `app/Traits/composition_calcul_trait.php` | Calculs basés sur la variante sélectionnée (`formule_variant_id`) |
| `app/Exports/export_formule_avec_detail.php` | Export basé sur la variante sélectionnée (`formule_variant_id`) |
| `routes/web.php` | Ajout des routes `POST /formule_variant/{formule_variant}/activer` et `POST /formule_variant/dupliquer` |

---

## 7. Plan de validation

1. **Migration initiale** : Vérifier la création de la variante "Défaut", son activation et la migration des compositions.
2. **Gestion des Variantes** :
   - Dupliquer "Défaut" vers "Hiver" : vérifier la copie exacte de toutes les compositions.
   - Supprimer "Hiver" : vérifier la suppression de la variante ET la suppression en cascade de toutes les lignes `t_composition` rattachées à "Hiver".
   - Tenter de supprimer la variante active : vérifier que la suppression est bloquée avec le message d'erreur.
3. **Calculs & Fiche Formule** :
   - Vérifier le fonctionnement des calculs et du tableau sur la variante sélectionnée.
4. **Exports Excel** : Vérifier que l'export correspond bien à la variante sélectionnée.
