, "manualNumber": "" }`) * → `{ weight, dsd, manualNumber, mode }` (DSD = dernier DSD du site + 1). * * `read: false` : pas de chargement d'entite existante — le payload est * denormalise directement dans cette ressource, puis le Processor prend le relais. * * ⚠ Le `dsd` renvoye ici est PREVISIONNEL : l'attribution AUTORITAIRE du DSD * (et du numero de ticket) est refaite/verrouillee a la creation du ticket * (`POST /api/weighing_tickets`, ERP-185) pour eviter les collisions si deux * postes pesent en parallele. Le front affiche cette valeur, mais c'est le * ticket persiste qui fait foi. */ #[ApiResource( shortName: 'WeighbridgeReading', operations: [ new Post( uriTemplate: '/weighbridge_readings', // Action de lecture du pont (pas une creation de ressource) : 200, pas 201. status: 200, security: "is_granted('logistique.weighing_tickets.manage')", normalizationContext: ['groups' => ['weighbridge_reading:read']], denormalizationContext: ['groups' => ['weighbridge_reading:write']], processor: WeighbridgeReadingProcessor::class, read: false, ), ], )] final class WeighbridgeReadingResource { /** AUTO (pesee bascule) | MANUAL (pesee manuelle) — pilote le comportement (§ 4.2). */ #[Assert\NotBlank(message: 'Le mode de pesée est obligatoire.')] #[Assert\Choice(choices: ['AUTO', 'MANUAL'], message: 'Mode de pesée invalide (AUTO ou MANUAL).')] #[Groups(['weighbridge_reading:write', 'weighbridge_reading:read'])] public ?string $mode = null; /** * Poids en kg. En entree : requis et saisi en MANUAL, ignore en AUTO (le pont * fournit le poids). En sortie : poids effectif de la pesee. */ #[Assert\Positive(message: 'Le poids doit être un entier positif (kg).')] #[Groups(['weighbridge_reading:write', 'weighbridge_reading:read'])] public ?int $weight = null; /** Numero de pesee papier saisi en MANUAL (distinct du DSD, RG-5.04). */ #[Assert\Length(max: 50, maxMessage: 'Le numéro de pesée ne peut pas dépasser {{ limit }} caractères.', normalizer: 'trim')] #[Groups(['weighbridge_reading:write', 'weighbridge_reading:read'])] public ?string $manualNumber = null; /** DSD attribue par le serveur (lecture seule) — previsionnel (cf. docbloc classe). */ #[Groups(['weighbridge_reading:read'])] public ?int $dsd = null; /** * RG metier : en pesee MANUAL, le poids est saisi par l'operateur (le pont * n'est pas lu) → il est obligatoire. Porte par un Callback pour que le 422 * cible le propertyPath `weight` (mapping inline front, ERP-101). En AUTO, * le poids fourni par le client est ignore (renseigne par le pont). */ #[Assert\Callback] public function validateManualWeight(ExecutionContextInterface $context): void { if ('MANUAL' === $this->mode && null === $this->weight) { $context->buildViolation('Le poids est obligatoire en pesée manuelle.') ->atPath('weight') ->addViolation() ; } } }