From 429fa36b0548ea892adaa9544e904960630afbf1 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Tue, 30 Jun 2026 16:53:23 -0300 Subject: [PATCH] feat: update product and variant resources to improve variant selection handling and response structure --- .../Catalog/Controllers/ProductController.php | 2 +- .../Catalog/Resources/ProductResource.php | 14 +------- .../Resources/ProductVariantResource.php | 11 +++++-- .../Catalog/Services/ProductService.php | 1 + .../Feature/Catalog/ProductControllerTest.php | 32 ++++++++++++------- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/app/Domains/Catalog/Controllers/ProductController.php b/app/Domains/Catalog/Controllers/ProductController.php index 1dcf1c1..b1a1c9f 100644 --- a/app/Domains/Catalog/Controllers/ProductController.php +++ b/app/Domains/Catalog/Controllers/ProductController.php @@ -59,7 +59,7 @@ class ProductController extends Controller protected function resolveScopedProduct(Tenant $tenant, Product $product): Product { if ($product->tenant_codigo !== $tenant->codigo) { - throw new NotFoundHttpException('Product not found for tenant.'); + throw new NotFoundHttpException('Product not found.'); } return $product; diff --git a/app/Domains/Catalog/Resources/ProductResource.php b/app/Domains/Catalog/Resources/ProductResource.php index cba0210..2305942 100644 --- a/app/Domains/Catalog/Resources/ProductResource.php +++ b/app/Domains/Catalog/Resources/ProductResource.php @@ -34,19 +34,7 @@ class ProductResource extends JsonResource 'variants' => ProductVariantResource::collection($this->whenLoaded('variants')), 'variant' => $this->when( $this->getSelectedVariant() !== null, - function () { - $selectedVariant = $this->getSelectedVariant(); - - return [ - 'variant_id' => $selectedVariant->id, - 'images' => $selectedVariant->attachments->isNotEmpty() - ? $selectedVariant->attachments->map(fn ($attachment) => $attachment->getTemporaryUrl(1440))->values() - : $this->attachments->map(fn ($attachment) => $attachment->getTemporaryUrl(1440))->values(), - 'attributes' => $selectedVariant->definitions->mapWithKeys(function ($definition) { - return [$definition->productAttribute?->attribute?->codigo => $definition->value]; - })->toArray(), - ]; - } + fn () => ProductVariantResource::make($this->getSelectedVariant()) ), ]; } diff --git a/app/Domains/Catalog/Resources/ProductVariantResource.php b/app/Domains/Catalog/Resources/ProductVariantResource.php index 3cd3ba1..e069a64 100644 --- a/app/Domains/Catalog/Resources/ProductVariantResource.php +++ b/app/Domains/Catalog/Resources/ProductVariantResource.php @@ -17,10 +17,17 @@ class ProductVariantResource extends JsonResource { return [ 'id' => $this->id, - 'producto_id' => $this->producto_id, 'stock' => $this->stock, 'product' => ProductResource::make($this->whenLoaded('product')), - 'definitions' => ProductVariantDefinitionResource::collection($this->whenLoaded('definitions')), + 'definitions' => $this->whenLoaded( + 'definitions', + fn () => $this->definitions + ->mapWithKeys(fn ($definition) => [ + $definition->productAttribute?->attribute?->codigo => $definition->value, + ]) + ->filter(fn ($value, $key) => $key !== null) + ->toArray() + ), 'images' => $this->whenLoaded('attachments', function () { if ($this->attachments->isNotEmpty()) { return $this->attachments diff --git a/app/Domains/Catalog/Services/ProductService.php b/app/Domains/Catalog/Services/ProductService.php index 48a70a6..3116eb5 100644 --- a/app/Domains/Catalog/Services/ProductService.php +++ b/app/Domains/Catalog/Services/ProductService.php @@ -286,6 +286,7 @@ class ProductService 'brand', 'category', 'attributes.options', + 'variants.definitions.productAttribute.attribute.options', ]); $selectedVariantQuery = $product->variants() diff --git a/tests/Feature/Catalog/ProductControllerTest.php b/tests/Feature/Catalog/ProductControllerTest.php index 41f4728..8098a62 100644 --- a/tests/Feature/Catalog/ProductControllerTest.php +++ b/tests/Feature/Catalog/ProductControllerTest.php @@ -389,7 +389,7 @@ class ProductControllerTest extends TestCase ]); } - public function test_it_returns_product_detail_with_variants_and_default_variant(): void + public function test_it_returns_product_detail_with_variants_and_selected_variant_resource(): void { // 1. Create a product $product = Product::create([ @@ -436,26 +436,36 @@ class ProductControllerTest extends TestCase $response->assertOk(); - // 4. Assert default_variant structure and data + // 4. Assert selected variant resource structure and data $response->assertJsonStructure([ 'data' => [ 'id', 'nombre', - 'default_variant' => [ - 'variant_id', + 'variant' => [ + 'id', + 'producto_id', + 'stock', 'images', - 'attributes' => [ - 'talle', - 'color', + 'definitions' => [ + '*' => [ + 'id', + 'producto_variante_id', + 'products_attribute_id', + 'attribute_id', + 'value', + 'attribute', + 'metadata', + ], ], ], ], ]); - $response->assertJsonPath('data.default_variant.variant_id', $variant->id); - $response->assertJsonPath('data.default_variant.attributes.talle', 'S'); - $response->assertJsonPath('data.default_variant.attributes.color', 'Azul'); - $response->assertJsonCount(1, 'data.default_variant.images'); + $response->assertJsonPath('data.variant.id', $variant->id); + $response->assertJsonPath('data.variant.producto_id', $product->id); + $response->assertJsonPath('data.variant.stock', 10); + $response->assertJsonCount(1, 'data.variant.images'); + $response->assertJsonCount(2, 'data.variant.definitions'); } protected function createTenant(string $codigo, string $nombre, string $dominio): Tenant