# Prompt d'implémentation — M5 · ERP-185 (1.5) — Provider + Processor WeighingTicket Projet **Starseed**. Tâche **back**. Lis `CLAUDE.md`, `.claude/rules/backend.md` (Pagination, RBAC, Validation) et la spec : `docs/specs/M5-tickets-pesee/spec-back.md` (§ 4.3, § 4.4, § 2.5, § 2.9, § 2.8, § 6, § 2.3). Prérequis : ERP-183, ERP-184. ## Mission Implémenter la logique métier d'écriture (Processor) et de lecture (Provider) du ticket de pesée. ## Étapes — `WeighingTicketProcessor` (POST/PATCH) 1. **Site courant** : résoudre via `CurrentSiteProviderInterface` → `site_id` (à la création). 2. **Numéro `{siteCode}-TP-{NNNN}`** (RG-5.02) : à la création, incrémenter `weighing_ticket_counter` du site avec **`SELECT ... FOR UPDATE`**, formater `%04d`. Numéro **immuable** au PATCH (RG-5.09). 3. **DSD autoritaire** : (ré)attribuer `empty_dsd`/`full_dsd` via `DsdAllocator` (verrou) si pesée AUTO (RG-5.04). 4. **RG-5.03** (contrepartie) : `#[Assert\Callback]` sur l'entité → selon `counterpartyType`, exiger `client` / `supplier` / `otherLabel` et forcer les autres à `null` (messages FR, `->atPath()` sur le bon champ). 5. **RG-5.05** : `net_weight = full_weight - empty_weight` (plein − vide) si les 2 poids présents, sinon `null`. 6. **RG-5.01 / RG-5.10** : `WeighingTicketFieldNormalizer` (service appelé avant validation) — `immatriculation` trim+UPPER ; si `!plateFreeFormat` reformate `XX-000-XX` et **rejette en 422** si invalide ; `otherLabel` trim. 7. `site` immuable au PATCH (RG-5.09). ## Étapes — `WeighingTicketProvider` (GET) 8. Liste **paginée** via `ApiPlatform\Doctrine\Orm\Paginator` (jamais d'array brut — règle n°13). 9. **Cloisonnement par site courant** (§ 2.3) : appliquer le `SiteScopedQueryExtension` existant (ou filtrer sur le site courant). 10. Query params : `?search=` (sur `number`, nom client/fournisseur, `other_label`, `immatriculation`), tri `displayDate` (défaut `number DESC`). 11. Anti-N+1 : fetch-join `client`/`supplier`/`site` (ManyToOne sûrs). ## Garde-fous - `declare(strict_types=1);` ; commentaires FR ; messages de validation **FR**. - Toutes les violations 422 portent un `propertyPath` aligné sur les noms de champs (consommé par le front `useFormErrors`). - Pas de controller ; pas de `paginationEnabled: false`. ## Vérification - `make test` (les tests dédiés sont écrits en ERP-187) : au minimum `CollectionsArePaginatedTest` **vert**. - `make php-cs-fixer-allow-risky`. - Smoke manuel : `POST /api/weighing_tickets` (Usine) → numéro `86-TP-0001` attribué, `net_weight` calculé ; second POST même site → `86-TP-0002`.