From 00489c14d354cb999f1bdd2bd5defd11fb6ed3b6 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 10 Aug 2026 09:28:52 -0300 Subject: [PATCH] feat(forms): implement MerchandiseFormController, MerchandiseFormService, and MerchandiseFormResource for managing merchandise options --- .../AdminApp/MerchandiseFormController.php | 22 ++++ .../Resources/MerchandiseFormResource.php | 32 ++++++ .../Forms/Services/MerchandiseFormService.php | 32 ++++++ app/Domains/Forms/documentacion/README.md | 1 + app/Domains/Forms/routes/adminapp.php | 5 + .../AdminAppMerchandiseFormControllerTest.php | 102 ++++++++++++++++++ 6 files changed, 194 insertions(+) create mode 100644 app/Domains/Forms/Controllers/AdminApp/MerchandiseFormController.php create mode 100644 app/Domains/Forms/Resources/MerchandiseFormResource.php create mode 100644 app/Domains/Forms/Services/MerchandiseFormService.php create mode 100644 tests/Feature/Forms/AdminAppMerchandiseFormControllerTest.php diff --git a/app/Domains/Forms/Controllers/AdminApp/MerchandiseFormController.php b/app/Domains/Forms/Controllers/AdminApp/MerchandiseFormController.php new file mode 100644 index 0000000..6b38675 --- /dev/null +++ b/app/Domains/Forms/Controllers/AdminApp/MerchandiseFormController.php @@ -0,0 +1,22 @@ +merchandiseFormService->get( + $request->user('sanctum')->tenant()->firstOrFail() + ) + ); + } +} diff --git a/app/Domains/Forms/Resources/MerchandiseFormResource.php b/app/Domains/Forms/Resources/MerchandiseFormResource.php new file mode 100644 index 0000000..c8fa453 --- /dev/null +++ b/app/Domains/Forms/Resources/MerchandiseFormResource.php @@ -0,0 +1,32 @@ + */ + public function toArray(Request $request): array + { + return [ + 'colors' => $this->options($this->resource['colors']), + 'sizes' => $this->options($this->resource['sizes']), + ]; + } + + /** + * @param Collection $options + * @return Collection + */ + private function options(Collection $options): Collection + { + return $options->map(fn (AttributeOption $option): array => [ + 'value' => $option->value, + 'label' => $option->label, + ])->values(); + } +} diff --git a/app/Domains/Forms/Services/MerchandiseFormService.php b/app/Domains/Forms/Services/MerchandiseFormService.php new file mode 100644 index 0000000..c8aea73 --- /dev/null +++ b/app/Domains/Forms/Services/MerchandiseFormService.php @@ -0,0 +1,32 @@ +, + * sizes: Collection + * } + */ + public function get(Tenant $tenant): array + { + $attributes = Attribute::query() + ->where('tenant_codigo', $tenant->codigo) + ->whereIn('codigo', ['color', 'talle']) + ->with('options') + ->get() + ->keyBy('codigo'); + + return [ + 'colors' => $attributes->get('color')?->options ?? new Collection, + 'sizes' => $attributes->get('talle')?->options ?? new Collection, + ]; + } +} diff --git a/app/Domains/Forms/documentacion/README.md b/app/Domains/Forms/documentacion/README.md index 826f1af..8f3a84b 100644 --- a/app/Domains/Forms/documentacion/README.md +++ b/app/Domains/Forms/documentacion/README.md @@ -19,6 +19,7 @@ Bajo `/v1/adminapp/forms`, con `auth:sanctum` y `adminapp.tenant`: - `GET /event`. - `GET /sale`. - `GET /staff`. +- `GET /fiesta-futbol-infantil/merchandise`: opciones de color y talle del tenant para merchandising. ## Dependencias diff --git a/app/Domains/Forms/routes/adminapp.php b/app/Domains/Forms/routes/adminapp.php index 14e62ed..77bd8e8 100644 --- a/app/Domains/Forms/routes/adminapp.php +++ b/app/Domains/Forms/routes/adminapp.php @@ -1,6 +1,7 @@ seed(AuthorizationSeeder::class); + WebsiteType::query()->create([ + 'codigo' => 'onticket', + 'nombre' => 'OnTicket', + ]); + } + + public function test_authentication_is_required(): void + { + $this->getJson('/api/v1/adminapp/forms/fiesta-futbol-infantil/merchandise') + ->assertUnauthorized(); + } + + public function test_it_returns_color_and_size_options_for_the_authenticated_tenant(): void + { + $tenant = $this->createTenant('fiesta'); + $otherTenant = $this->createTenant('other'); + $this->createAttribute($tenant, 'color', [ + ['value' => 'verde', 'label' => 'Verde', 'sort_order' => 2], + ['value' => 'blanco', 'label' => 'Blanco', 'sort_order' => 1], + ]); + $this->createAttribute($tenant, 'talle', [ + ['value' => 'S', 'label' => 'S', 'sort_order' => 1], + ['value' => 'M', 'label' => 'M', 'sort_order' => 2], + ]); + $this->createAttribute($otherTenant, 'color', [ + ['value' => 'negro', 'label' => 'Negro', 'sort_order' => 1], + ]); + + Sanctum::actingAs(User::factory()->create([ + 'rol_codigo' => RoleCode::AdminApp->value, + 'tenant_codigo' => $tenant->codigo, + ])); + + $this->getJson('/api/v1/adminapp/forms/fiesta-futbol-infantil/merchandise') + ->assertOk() + ->assertJsonCount(2, 'data.colors') + ->assertJsonCount(2, 'data.sizes') + ->assertJsonPath('data.colors.0.value', 'blanco') + ->assertJsonPath('data.colors.0.label', 'Blanco') + ->assertJsonPath('data.colors.1.value', 'verde') + ->assertJsonPath('data.sizes.0.value', 'S') + ->assertJsonPath('data.sizes.1.value', 'M') + ->assertJsonMissing(['value' => 'negro']); + } + + public function test_a_customer_cannot_get_the_merchandise_form(): void + { + Sanctum::actingAs(User::factory()->create([ + 'rol_codigo' => RoleCode::User->value, + ])); + + $this->getJson('/api/v1/adminapp/forms/fiesta-futbol-infantil/merchandise') + ->assertForbidden(); + } + + private function createTenant(string $code): Tenant + { + return Tenant::query()->create([ + 'codigo' => $code, + 'nombre' => ucfirst($code), + 'dominio' => "{$code}.test", + 'website_type_code' => 'onticket', + ]); + } + + /** @param array $options */ + private function createAttribute(Tenant $tenant, string $code, array $options): void + { + $attribute = Attribute::query()->create([ + 'tenant_codigo' => $tenant->codigo, + 'codigo' => $code, + 'nombre' => ucfirst($code), + 'type' => FieldType::Select, + 'is_required' => true, + ]); + $attribute->options()->createMany($options); + } +}