# #07 — Personnalisation du stand : ajout « Moquette réemployable »

> Statut : ✅ **fait** — 22/08/2026, migration **0.14**.
> Prix reçus le 21/08/2026 ; le 3 m², absent de la liste du client, confirmé à 150 € le 22/08.

**Formulaire :** `offres_stands_exposants_2027` (id 58), `fieldset_1` · **Charge :** S

## Demande client

> Personnalisation du stand — Ajouter le produit suivant :
> "Moquette réemployable" avec les choix suivants :
> 3m2 = xx € HT / 4m2 = xx € HT / 8m2 = xx € HT / 12m2 = xx € HT / 16m2 = xx € HT /
> 24m2 = xx € HT / 32m2 = xx € HT / 64m2 = xx € HT

## Les tarifs

**50 € HT le m², sans exception.**

| Surface | 3 m² | 4 | 8 | 12 | 16 | 24 | 32 | 64 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| Prix HT | 150 € | 200 € | 400 € | 600 € | 800 € | 1 200 € | 1 600 € | 3 200 € |

La liste transmise le 21/08 en comptait **sept** : le 3 m² manquait. C'est la taille du stand
habillé des jeunes pousses, pas une taille de la grille commerciale — d'où l'oubli. Confirmé à
150 € le 22/08.

Les montants sont écrits **en toutes lettres** dans `reex_tarifs_2027()`, et non calculés depuis un
tarif au m². Un prix contractuel se relit, il ne se recalcule pas, et rien ne garantit que la
prochaine grille restera proportionnelle. Un test vérifie en revanche que la règle des 50 €/m² tient
encore, pour que sa rupture soit une décision et non un accident.

## Ce qui a été fait

Une saisie `selection` — `selection_14`, classe `moquette` — en dernière position du fieldset
« Personnalisation du stand », après la réserve d'1 m². Ses options **se déduisent de la table des
tarifs** (`reex_moquette_datas()`), comme celles des stands et des coffrets : proposer une surface
non tarifée est devenu impossible.

Elle se propage au formulaire co-exposants **par recopie du bloc entier**, conformément à la règle
posée par la migration 0.9. La redéclarer des deux côtés ferait vivre deux définitions de la même
moquette, dont l'écart n'apparaîtrait qu'au moment où un co-exposant commande.

### Trois détails qui ont orienté l'implémentation

**Ce n'est pas une quantité.** Les trois autres postes de la section se comptent — la valeur
enregistrée est `personnalisation_reserve_2` — et passent par `lignesQuantite`. La moquette est un
choix unique dont chaque option porte son prix : elle est dispatchée par `GROUPES_TARIFES`, comme
les coffrets. D'où l'absence de la classe `quantity-with-price` sur son conteneur.

**Sa clé de non-choix vaut `aucune`, au féminin.** Trois groupes se partagent déjà `aucun` —
coffrets, packs de visibilité, co-exposants — et ne se départagent que par la classe de la saisie.
En choisir un quatrième aurait élargi une ambiguïté déjà coûteuse. Le groupe est malgré tout
déclaré dans `GROUPES_TARIFES` : la protection ne doit pas tenir à une lettre.

**Les prix ne sont pas dans le formulaire.** Ils sont accolés aux libellés des options par
`contract_form.js` à l'affichage, en interrogeant la table pour **chacune** — y compris celles que
personne ne sélectionne, ce qui fait remonter une surface non tarifée dans le bandeau d'anomalies.
Un montant écrit dans le formulaire aurait sa propre vie.

## Périmètre — tranché (réponse B5)

Les deux réserves du ticket sont levées, dans le sens du statu quo :

- ✅ **La liste des 8 surfaces est reprise telle quelle**, y compris le 3 m² qui ne correspond à
  aucune taille de la grille 2027.
- ✅ **Aucune contrainte croisée** avec la surface du stand sélectionnée plus haut. Un exposant peut
  commander 64 m² de moquette sur un stand de 4 m².

Conséquence assumée : les commandes incohérentes sont corrigées à la main par l'équipe RVR.

## Critères d'acceptation

- [x] Les 8 surfaces sont sélectionnables, aux prix validés par le client.
- [x] Le montant est répercuté dans le total et dans le récapitulatif de contrat
      (champ caché `hidden_26`, classe `moquette_amount`).
- [x] Les libellés existent en fr et en en.
- [x] Le formulaire co-exposants propose la même offre — vérifié par
      `tests/formulaires/comparer_offres.php`.
- [x] La migration est idempotente.
- [ ] Contrôle visuel dans un navigateur.
- [ ] Confirmation définitive des prix par Cécilia — annoncée comme susceptible de bouger.
      Le changement coûte une ligne dans `reex_tarifs.php`, sans migration ni retouche du formulaire.
