312c119c06
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).
2.6 KiB
2.6 KiB
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)
- Site courant : résoudre via
CurrentSiteProviderInterface→site_id(à la création). - Numéro
{siteCode}-TP-{NNNN}(RG-5.02) : à la création, incrémenterweighing_ticket_counterdu site avecSELECT ... FOR UPDATE, formater%04d. Numéro immuable au PATCH (RG-5.09). - DSD autoritaire : (ré)attribuer
empty_dsd/full_dsdviaDsdAllocator(verrou) si pesée AUTO (RG-5.04). - RG-5.03 (contrepartie) :
#[Assert\Callback]sur l'entité → seloncounterpartyType, exigerclient/supplier/otherLabelet forcer les autres ànull(messages FR,->atPath()sur le bon champ). - RG-5.05 :
net_weight = full_weight - empty_weight(plein − vide) si les 2 poids présents, sinonnull. - RG-5.01 / RG-5.10 :
WeighingTicketFieldNormalizer(service appelé avant validation) —immatriculationtrim+UPPER ; si!plateFreeFormatreformateXX-000-XXet rejette en 422 si invalide ;otherLabeltrim. siteimmuable au PATCH (RG-5.09).
Étapes — WeighingTicketProvider (GET)
- Liste paginée via
ApiPlatform\Doctrine\Orm\Paginator(jamais d'array brut — règle n°13). - Cloisonnement par site courant (§ 2.3) : appliquer le
SiteScopedQueryExtensionexistant (ou filtrer sur le site courant). - Query params :
?search=(surnumber, nom client/fournisseur,other_label,immatriculation), tridisplayDate(défautnumber DESC). - 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
propertyPathaligné sur les noms de champs (consommé par le frontuseFormErrors). - Pas de controller ; pas de
paginationEnabled: false.
Vérification
make test(les tests dédiés sont écrits en ERP-187) : au minimumCollectionsArePaginatedTestvert.make php-cs-fixer-allow-risky.- Smoke manuel :
POST /api/weighing_tickets(Usine) → numéro86-TP-0001attribué,net_weightcalculé ; second POST même site →86-TP-0002.