Files
Starseed/docs/specs/M5-tickets-pesee/prompts/ERP-185-provider-processor.md
T
Matthieu 312c119c06 feat(logistique) : entité WeighingTicket + dette site.code (ERP-183)
Entité WeighingTicket
- Entité métier complète (#[Auditable], TimestampableBlamableTrait, relations
  ORM Client/Supplier/Site) + contrat de sérialisation à 3 maillons
  (weighing_ticket:read / :item:read + contextes par opération).
- Getters calculés displayDate et plateFreeFormat (#[SerializedName]),
  sécurité view/manage, pas de Delete/archive.
- Validation #[Assert\*] messages FR + #[Assert\Callback] RG-5.03 (->atPath()),
  libellé i18n audit.entity.logistique_weighingticket.
- Repository : interface Domain + DoctrineWeighingTicketRepository
  (recherche + tri number DESC, deletedAt IS NULL).

Dette site.code
- Site.code mappé VARCHAR(8) (groupes read/write), dérivation auto au
  PrePersist (2 premiers chiffres du CP), UniqueConstraint uq_site_code.
- Migration Version20260617160000 : ALTER COLUMN code SET NOT NULL + COMMENT.
- Fixtures (codes 86/17/82) et SiteApiTest ajustés.

Câblage
- doctrine.yaml : mapping ORM du module Logistique (absent du scaffold ERP-181).
- ColumnCommentsCatalog : site.code + table weighing_ticket.

Specs M5 versionnées (spec-back / spec-front / prompts).
2026-06-18 14:37:16 +02:00

2.6 KiB
Raw Blame History

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 CurrentSiteProviderInterfacesite_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)

  1. Liste paginée via ApiPlatform\Doctrine\Orm\Paginator (jamais d'array brut — règle n°13).
  2. Cloisonnement par site courant (§ 2.3) : appliquer le SiteScopedQueryExtension existant (ou filtrer sur le site courant).
  3. Query params : ?search= (sur number, nom client/fournisseur, other_label, immatriculation), tri displayDate (défaut number DESC).
  4. 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.