From 4ce1bafb2f9778f0d0f18aa922e236a13b038abf Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 29 Jun 2026 10:41:57 +0200 Subject: [PATCH] =?UTF-8?q?fix(logistique)=20:=20bloque=20la=20saisie=20ma?= =?UTF-8?q?nuelle=20poids/DSD=20=C3=A0=205=20chiffres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Masque front 5 chiffres sur la modale manuelle + Assert\LessThanOrEqual(99999) sur WeighbridgeReadingResource (weight/dsd, mode MANUAL) et backstop entité (validateManualEntryDigits). Le DSD auto (compteur de site) n'est pas contraint. --- .../pages/weighing-tickets/[id]/edit.vue | 6 +-- .../logistique/pages/weighing-tickets/new.vue | 6 +-- .../modules/logistique/utils/weighingMasks.ts | 11 +++++ .../Domain/Entity/WeighingTicket.php | 32 ++++++++++++++ .../Resource/WeighbridgeReadingResource.php | 3 ++ .../Api/WeighbridgeReadingApiTest.php | 43 +++++++++++++++++++ 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/frontend/modules/logistique/pages/weighing-tickets/[id]/edit.vue b/frontend/modules/logistique/pages/weighing-tickets/[id]/edit.vue index 98fc7ec..d42b2bd 100644 --- a/frontend/modules/logistique/pages/weighing-tickets/[id]/edit.vue +++ b/frontend/modules/logistique/pages/weighing-tickets/[id]/edit.vue @@ -161,14 +161,14 @@
chaque + * 422 est mappee inline sous le champ via useFormErrors (ERP-101). + */ + #[Assert\Callback] + public function validateManualEntryDigits(ExecutionContextInterface $context): void + { + $this->assertManualDigitCap($context, $this->emptyMode, $this->emptyWeight, 'emptyWeight', 'Le poids saisi ne peut pas dépasser 5 chiffres (99999 kg maximum).'); + $this->assertManualDigitCap($context, $this->emptyMode, $this->emptyDsd, 'emptyDsd', 'Le DSD saisi ne peut pas dépasser 5 chiffres (99999 maximum).'); + $this->assertManualDigitCap($context, $this->fullMode, $this->fullWeight, 'fullWeight', 'Le poids saisi ne peut pas dépasser 5 chiffres (99999 kg maximum).'); + $this->assertManualDigitCap($context, $this->fullMode, $this->fullDsd, 'fullDsd', 'Le DSD saisi ne peut pas dépasser 5 chiffres (99999 maximum).'); + } + /** * Date du ticket affichee en LISTE (§ 4.0) : date de la pesee a plein si * disponible, sinon date de la pesee a vide. Getter calcule (jamais @@ -646,4 +668,14 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface return $this; } + + private function assertManualDigitCap(ExecutionContextInterface $context, ?string $mode, ?int $value, string $path, string $message): void + { + if ('MANUAL' === $mode && null !== $value && $value > self::MANUAL_VALUE_MAX) { + $context->buildViolation($message) + ->atPath($path) + ->addViolation() + ; + } + } } diff --git a/src/Module/Logistique/Infrastructure/ApiPlatform/Resource/WeighbridgeReadingResource.php b/src/Module/Logistique/Infrastructure/ApiPlatform/Resource/WeighbridgeReadingResource.php index 8840f0b..f7f2bcf 100644 --- a/src/Module/Logistique/Infrastructure/ApiPlatform/Resource/WeighbridgeReadingResource.php +++ b/src/Module/Logistique/Infrastructure/ApiPlatform/Resource/WeighbridgeReadingResource.php @@ -6,6 +6,7 @@ namespace App\Module\Logistique\Infrastructure\ApiPlatform\Resource; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Post; +use App\Module\Logistique\Domain\Entity\WeighingTicket; use App\Module\Logistique\Infrastructure\ApiPlatform\State\Processor\WeighbridgeReadingProcessor; use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -59,6 +60,7 @@ final class WeighbridgeReadingResource * fournit le poids). En sortie : poids effectif de la pesee. */ #[Assert\Positive(message: 'Le poids doit être un entier positif (kg).')] + #[Assert\LessThanOrEqual(value: WeighingTicket::MANUAL_VALUE_MAX, message: 'Le poids saisi ne peut pas dépasser 5 chiffres (99999 kg maximum).')] #[Groups(['weighbridge_reading:write', 'weighbridge_reading:read'])] public ?int $weight = null; @@ -68,6 +70,7 @@ final class WeighbridgeReadingResource * (l'obligation en MANUAL est portee par le Callback ci-dessous). */ #[Assert\Positive(message: 'Le DSD doit être un entier positif.')] + #[Assert\LessThanOrEqual(value: WeighingTicket::MANUAL_VALUE_MAX, message: 'Le DSD saisi ne peut pas dépasser 5 chiffres (99999 maximum).')] #[Groups(['weighbridge_reading:write', 'weighbridge_reading:read'])] public ?int $dsd = null; diff --git a/tests/Module/Logistique/Api/WeighbridgeReadingApiTest.php b/tests/Module/Logistique/Api/WeighbridgeReadingApiTest.php index b6b34d7..dd871a4 100644 --- a/tests/Module/Logistique/Api/WeighbridgeReadingApiTest.php +++ b/tests/Module/Logistique/Api/WeighbridgeReadingApiTest.php @@ -133,6 +133,49 @@ final class WeighbridgeReadingApiTest extends AbstractApiTestCase self::assertViolationOnPath($response, 'dsd'); } + public function testManualWeighingRejectsWeightOverFiveDigits(): void + { + $client = $this->manageClientWithCurrentSite(); + + $response = $client->request('POST', '/api/weighbridge_readings', [ + 'headers' => ['Content-Type' => 'application/ld+json'], + // 100000 = 6 chiffres → au-dela du plafond 5 chiffres (99999). + 'json' => ['mode' => 'MANUAL', 'weight' => 100000, 'dsd' => 16619], + ]); + + self::assertResponseStatusCodeSame(422); + self::assertViolationOnPath($response, 'weight'); + } + + public function testManualWeighingRejectsDsdOverFiveDigits(): void + { + $client = $this->manageClientWithCurrentSite(); + + $response = $client->request('POST', '/api/weighbridge_readings', [ + 'headers' => ['Content-Type' => 'application/ld+json'], + 'json' => ['mode' => 'MANUAL', 'weight' => 23187, 'dsd' => 100000], + ]); + + self::assertResponseStatusCodeSame(422); + self::assertViolationOnPath($response, 'dsd'); + } + + public function testManualWeighingAcceptsFiveDigitBoundary(): void + { + $client = $this->manageClientWithCurrentSite(); + + $response = $client->request('POST', '/api/weighbridge_readings', [ + 'headers' => ['Content-Type' => 'application/ld+json'], + // 99999 = exactement 5 chiffres → derniere valeur acceptee. + 'json' => ['mode' => 'MANUAL', 'weight' => 99999, 'dsd' => 99999], + ]); + + self::assertResponseStatusCodeSame(200); + $data = $response->toArray(); + self::assertSame(99999, $data['weight']); + self::assertSame(99999, $data['dsd']); + } + /** * Garde-fou ERP-101 (miroir AbstractWeighingTicketApiTestCase) : une 422 doit * porter une violation sur le `propertyPath` attendu, consommable inline par