From 7a7af580745e39536eab838ea4af1306fa763008 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Thu, 12 Mar 2026 11:44:34 +0100 Subject: [PATCH] docs : add piece quantity design spec Co-Authored-By: Claude Opus 4.6 --- .../specs/2026-03-12-piece-quantity-design.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-12-piece-quantity-design.md diff --git a/docs/superpowers/specs/2026-03-12-piece-quantity-design.md b/docs/superpowers/specs/2026-03-12-piece-quantity-design.md new file mode 100644 index 0000000..2a008bd --- /dev/null +++ b/docs/superpowers/specs/2026-03-12-piece-quantity-design.md @@ -0,0 +1,98 @@ +# Piece Quantity — Design Spec + +## Context + +L'application gère des machines composées de composants et de pièces. Une même pièce (catalogue) peut apparaître dans plusieurs contextes avec des quantités différentes. La quantité doit être portée par la **relation**, pas par l'entité catalogue. + +## Scope + +- Quantité sur les **pièces directement liées à une machine** (`MachinePieceLink`) +- Quantité sur les **pièces d'un composant** (JSON `structure.pieces` du `Composant`) +- **Hors scope** : quantité sur `MachineComponentLink`, `MachineProductLink`, override de quantité composant au niveau machine + +## Règles métier + +| Contexte | Stockage | Éditable depuis | Visible sur machine | +|----------|----------|-----------------|---------------------| +| Pièce directement sur machine | `MachinePieceLink.quantity` | Page machine | Oui, éditable | +| Pièce d'un composant | `Composant.structure.pieces[].quantity` | Page composant (création + édition) | Oui, lecture seule | + +- Type : entier, valeur par défaut = 1 +- Affichage : "×N" après le nom de la pièce, masqué si N = 1 + +## Backend + +### 1. MachinePieceLink — Nouvelle colonne + +Ajout d'un champ `quantity` sur l'entité `MachinePieceLink` : + +```php +#[ORM\Column(type: Types::INTEGER, options: ['default' => 1])] +#[Groups(['machine_piece_link:read', 'machine_piece_link:write'])] +private int $quantity = 1; +``` + +Getter/setter standard. + +### 2. Migration SQL + +```sql +ALTER TABLE machine_piece_link ADD COLUMN IF NOT EXISTS quantity INTEGER NOT NULL DEFAULT 1; +``` + +Idempotente avec `IF NOT EXISTS`. + +### 3. Composant.structure JSON + +Le tableau `pieces` dans le JSON `structure` du Composant accepte une nouvelle clé `quantity`. Pas de migration DB nécessaire — c'est un champ JSON libre. + +Avant : +```json +{ "typePieceId": "...", "role": "Filtration" } +``` + +Après : +```json +{ "typePieceId": "...", "role": "Filtration", "quantity": 4 } +``` + +Les entrées existantes sans `quantity` sont traitées comme `quantity = 1` (défaut côté frontend et backend). + +### 4. MachineStructureController + +- `normalizePieceLinks()` : inclure `quantity` dans la réponse JSON + - Pièce machine directe (parentLink = null) : `quantity` depuis `MachinePieceLink.quantity` + - Pièce sous composant : `quantity` depuis le `structure.pieces` du composant source +- **PATCH** : accepter `quantity` pour les pièces directement sur la machine uniquement + +## Frontend + +### 1. Types TypeScript + +Mise à jour de `ComponentModelPiece` : + +```typescript +interface ComponentModelPiece { + typePieceId?: string + typePieceLabel?: string + reference?: string + familyCode?: string + role?: string + quantity?: number // défaut 1 +} +``` + +### 2. Pages composant (création + édition) + +Dans l'éditeur de structure, chaque pièce du tableau `structure.pieces` affiche un champ input : +- Type : `number`, min = 1, step = 1 +- Valeur par défaut : 1 +- Style : `input input-bordered input-sm md:input-md` (DaisyUI) +- Position : à côté des champs existants (reference, role) + +### 3. Page machine (détail/structure) + +- **Pièce directe** (parentLink = null) : affiche "×N" à côté du nom, quantité éditable (input entier) +- **Pièce de composant** : affiche "×N" à côté du nom, lecture seule (pas d'input) +- Si quantité = 1 : rien n'est affiché (pas de bruit visuel) +- Style du label : texte secondaire (`text-base-content/60` ou classe équivalente)