From 6497b109a2c763fcd033bdff67f9235f1399d50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 18 Sep 2026 11:40:22 +0200 Subject: [PATCH] fix(inco): normalize scalar brands query parameter to array in prepareForValidation --- .../IncoSheets/IncoSheetsIndexRequest.php | 16 +++++++++++ .../IncoSheets/IncoSheetsSearchRequest.php | 16 +++++++++++ .../Api/V1/IncoSheets/IncoSheetsIndexTest.php | 27 +++++++++++++++++++ .../V1/IncoSheets/IncoSheetsSearchTest.php | 18 +++++++++++++ 4 files changed, 77 insertions(+) diff --git a/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsIndexRequest.php b/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsIndexRequest.php index bb64756..72547e2 100644 --- a/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsIndexRequest.php +++ b/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsIndexRequest.php @@ -38,6 +38,22 @@ final class IncoSheetsIndexRequest extends FormRequest ]; } + #[\Override] + protected function prepareForValidation(): void + { + if ($this->has('brands')) { + $brands = $this->input('brands'); + if (is_string($brands)) { + $trimmed = trim($brands); + $this->merge([ + 'brands' => $trimmed === '' + ? [] + : (str_contains($trimmed, ',') ? array_map('trim', explode(',', $trimmed)) : [$trimmed]), + ]); + } + } + } + public function sorter(): IncoSheetSorter { return new IncoSheetSorter($this->sortBy(), $this->direction()); diff --git a/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsSearchRequest.php b/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsSearchRequest.php index 6bcc907..514e292 100644 --- a/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsSearchRequest.php +++ b/src/Presentation/Api/V1/Http/Requests/IncoSheets/IncoSheetsSearchRequest.php @@ -24,6 +24,22 @@ final class IncoSheetsSearchRequest extends FormRequest ]; } + #[\Override] + protected function prepareForValidation(): void + { + if ($this->has('brands')) { + $brands = $this->input('brands'); + if (is_string($brands)) { + $trimmed = trim($brands); + $this->merge([ + 'brands' => $trimmed === '' + ? [] + : (str_contains($trimmed, ',') ? array_map('trim', explode(',', $trimmed)) : [$trimmed]), + ]); + } + } + } + public function incoIdSearch(): IncoIdQuery { return new IncoIdQuery($this->string('incoIdLike')->value()); diff --git a/tests/Feature/Api/V1/IncoSheets/IncoSheetsIndexTest.php b/tests/Feature/Api/V1/IncoSheets/IncoSheetsIndexTest.php index e4c1cfc..88b340b 100644 --- a/tests/Feature/Api/V1/IncoSheets/IncoSheetsIndexTest.php +++ b/tests/Feature/Api/V1/IncoSheets/IncoSheetsIndexTest.php @@ -109,6 +109,33 @@ describe('IncoSheets Index Feature API', function (): void { $response->assertJsonPath('incoSheets.0.incoId', '9999001'); }); + it('returns 200 OK with matching sheets filtered by BrandCode passed as scalar query parameter without brackets', function (): void { + // GIVEN + /** @var \Tests\TestCase $test */ + $test = $this; + + MarqueFactory::new()->create(['COD_MARQ' => 504, 'LIB_MARQ' => 'LE GAULOIS PROFESSIONNEL']); + $brand = app(BrandResolver::class)->resolve(new ArcadiaId('504')); + + ArticleRefFactory::new()->create([ + 'NO_ART' => 9999001, + 'COD_SOC' => 1, + 'COD_MARQUE' => 504, + ]); + + IncoFactory::new()->create([ + 'NO_ART' => 9999001, + 'DENOM_LEG' => 'Produit Gaulois Pro', + ]); + + // WHEN + $response = $test->getJson("/api/v1/inco-sheets?brands={$brand->code->value}"); + + // THEN + $response->assertStatus(200); + $response->assertJsonPath('incoSheets.0.incoId', '9999001'); + }); + it('returns 422 Unprocessable Entity when brand code format is invalid', function (): void { // GIVEN /** @var \Tests\TestCase $test */ diff --git a/tests/Feature/Api/V1/IncoSheets/IncoSheetsSearchTest.php b/tests/Feature/Api/V1/IncoSheets/IncoSheetsSearchTest.php index 94711ea..c7529a5 100644 --- a/tests/Feature/Api/V1/IncoSheets/IncoSheetsSearchTest.php +++ b/tests/Feature/Api/V1/IncoSheets/IncoSheetsSearchTest.php @@ -87,6 +87,24 @@ describe('IncoSheets Search Feature API', function (): void { $response->assertJsonPath('incoSheets.0.incoId', '1000101'); }); + it('returns 200 OK with matching sheets filtered by BrandCode without brackets', function (): void { + // GIVEN + /** @var \Tests\TestCase $test */ + $test = $this; + $query = urlencode('%10001%'); + + MarqueFactory::new()->create(['COD_MARQ' => 1, 'LIB_MARQ' => 'Standard']); + $brand = app(BrandResolver::class)->resolve(new ArcadiaId('1')); + + // WHEN + $response = $test->getJson("/api/v1/inco-sheets/search?incoIdLike={$query}&brands={$brand->code->value}"); + + // THEN + $response->assertStatus(200); + $response->assertJsonCount(1, 'incoSheets'); + $response->assertJsonPath('incoSheets.0.incoId', '1000101'); + }); + it('returns 422 Unprocessable Entity when brand code format is invalid', function (): void { // GIVEN /** @var \Tests\TestCase $test */