# Modification groupée de formule — ajout d'un produit et d'un dosage

## Contexte

La feuille "Formule modification groupée" ([formule_modification_groupee_controller.php](../app/Http/Controllers/formule_modification_groupee_controller.php), [index.blade.php](../resources/views/formule_modification_groupee/index.blade.php)) ne permettait de fait que de **remplacer** un produit existant dans les compositions de formules (3 modes d'action : remplacement simple, remplacement sans/avec vérification de quantité).

Le contrôleur contenait déjà une logique "MODE 2 : AJOUT / CREATION" dans `valider()`, mais elle était inatteignable depuis l'interface : la liste des formules ([data_table()](../app/Http/Controllers/formule_modification_groupee_controller.php)) exigeait qu'un "produit à remplacer" soit sélectionné pour afficher la moindre formule, ce qui empêchait de choisir des formules pour y **ajouter** un produit qu'elles ne possèdent pas encore.

## Changement

Ajout d'une 4ᵉ action explicite **"Ajouter un produit et un dosage"** (`action = 3`) dans la même feuille (pas de feuille séparée, pour réutiliser le filtrage centrale/variante/classes béton déjà en place) :

- `data_table()` : en mode ajout, le filtre obligatoire "au moins un produit à remplacer" est levé, et la contrainte `composition_type` sur la requête de base est retirée — les formules de la centrale sont listées même si elles n'ont encore aucune composition du type de produit choisi.
- `valider()` : aucune modification de la logique MODE 2 existante ; elle est simplement rendue atteignable et protégée par un droit.
- Vue : nouvelle option dans le select "Action", colonne "Produits à remplacer" masquée en mode ajout (libellés de la colonne "remplacement" relabellisés dynamiquement en "à ajouter" / "Dosage"), sélections de produit à remplacer réinitialisées au changement de mode pour éviter toute confusion avec un mode de remplacement.

## Droit dédié

Nouvelle colonne `t_profil.profil_formule_modification_groupee_ajout` (booléen, défaut `0`) :

- Migration : [2026_09_29_1200_V905000_NB_t_profil_formule_modification_groupee_ajout.php](../database/migrations/2026_09_29_1200_V905000_NB_t_profil_formule_modification_groupee_ajout.php)
- Case à cocher dans la fiche profil : [profil/form.blade.php](../resources/views/profil/form.blade.php) ("Modification groupée formule : ajout produit")
- Validation/sauvegarde : [profil_controller.php](../app/Http/Controllers/profil_controller.php)
- Contrôle serveur (défense en profondeur, indépendant du paramètre `action` envoyé par le client) :
  - `index()` : n'affiche l'option "Ajouter un produit et un dosage" que si le droit est actif.
  - `data_table()` : `abort(401)` si `action=3` sans le droit.
  - `valider()` : la branche MODE 2 (ajout) est ignorée (`continue`) si le droit est absent, même si une requête forgée simule un ajout via `action` différent de 3.

Reste sous la dépendance du droit global `profil_outil_formule` (accès à la feuille), ce nouveau droit est un sous-droit optionnel qui doit être accordé en plus.

## Garde-fou complémentaire

`action=3` est refusé (résultat vide / message d'erreur) si le type de produit sélectionné est "Aucun" (valeur `9`, placeholder), pour éviter la création de lignes de composition avec un `composition_type` invalide.

## Fichiers modifiés

- [app/Http/Controllers/formule_modification_groupee_controller.php](../app/Http/Controllers/formule_modification_groupee_controller.php)
- [resources/views/formule_modification_groupee/index.blade.php](../resources/views/formule_modification_groupee/index.blade.php)
- [app/Http/Controllers/profil_controller.php](../app/Http/Controllers/profil_controller.php)
- [resources/views/profil/form.blade.php](../resources/views/profil/form.blade.php)
- [database/migrations/2026_09_29_1200_V905000_NB_t_profil_formule_modification_groupee_ajout.php](../database/migrations/2026_09_29_1200_V905000_NB_t_profil_formule_modification_groupee_ajout.php) (migré sur la base de dev)

## Non testé

Pas de vérification en conditions réelles dans le navigateur (page protégée par authentification `interne`, pas d'identifiants de test disponibles dans cette session). Vérifié : compilation Blade sans erreur, lint PHP sans erreur, migration appliquée, route déjà enregistrée.
