From c2efec89066551fec8fd8b4bbf76ddcebf1e1f33 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Tue, 14 Jul 2026 14:55:48 -0300 Subject: [PATCH] feat: implement FeaturedVariant and CatalogController for managing featured variants and catalog display --- .../Catalog/Controllers/CatalogController.php | 23 ++++++++++ .../CatalogFeaturedGroupResource.php | 42 +++++++++++++++++++ app/Domains/Catalog/routes/api.php | 2 + .../Controllers/FeaturedGroupController.php | 2 +- .../Controllers/FeaturedProductController.php | 42 ------------------- .../Controllers/FeaturedVariantController.php | 42 +++++++++++++++++++ app/Domains/Product/Models/FeaturedGroup.php | 5 ++- ...eaturedProduct.php => FeaturedVariant.php} | 11 +++-- .../Requests/StoreFeaturedGroupRequest.php | 3 +- ...st.php => StoreFeaturedVariantRequest.php} | 4 +- .../Requests/UpdateFeaturedGroupRequest.php | 3 +- ...t.php => UpdateFeaturedVariantRequest.php} | 2 +- .../Resources/FeaturedGroupResource.php | 3 +- ...source.php => FeaturedVariantResource.php} | 5 +-- app/Domains/Product/routes/api.php | 6 +-- ...d_group_order_to_featured_groups_table.php | 28 +++++++++++++ ...featured_products_to_featured_variants.php | 38 +++++++++++++++++ 17 files changed, 200 insertions(+), 61 deletions(-) create mode 100644 app/Domains/Catalog/Controllers/CatalogController.php create mode 100644 app/Domains/Catalog/Resources/CatalogFeaturedGroupResource.php delete mode 100644 app/Domains/Product/Controllers/FeaturedProductController.php create mode 100644 app/Domains/Product/Controllers/FeaturedVariantController.php rename app/Domains/Product/Models/{FeaturedProduct.php => FeaturedVariant.php} (56%) rename app/Domains/Product/Requests/{StoreFeaturedProductRequest.php => StoreFeaturedVariantRequest.php} (71%) rename app/Domains/Product/Requests/{UpdateFeaturedProductRequest.php => UpdateFeaturedVariantRequest.php} (84%) rename app/Domains/Product/Resources/{FeaturedProductResource.php => FeaturedVariantResource.php} (66%) create mode 100644 database/migrations/2026_07_14_174706_add_group_order_to_featured_groups_table.php create mode 100644 database/migrations/2026_07_14_174819_rename_featured_products_to_featured_variants.php diff --git a/app/Domains/Catalog/Controllers/CatalogController.php b/app/Domains/Catalog/Controllers/CatalogController.php new file mode 100644 index 0000000..db7c7e0 --- /dev/null +++ b/app/Domains/Catalog/Controllers/CatalogController.php @@ -0,0 +1,23 @@ +with(['featuredVariants' => function ($query) { + $query->orderBy('order'); + }, 'featuredVariants.variant.product', 'featuredVariants.variant.attachments', 'featuredVariants.variant.product.attachments']) + ->orderBy('group_order') + ->get(); + + return CatalogFeaturedGroupResource::collection($featuredGroups); + } +} diff --git a/app/Domains/Catalog/Resources/CatalogFeaturedGroupResource.php b/app/Domains/Catalog/Resources/CatalogFeaturedGroupResource.php new file mode 100644 index 0000000..7f83d85 --- /dev/null +++ b/app/Domains/Catalog/Resources/CatalogFeaturedGroupResource.php @@ -0,0 +1,42 @@ + $this->id, + 'title' => $this->group_name, + 'layout' => $this->product_layout, + 'group_order' => $this->group_order, + 'items' => $this->whenLoaded('featuredVariants', function () use ($request) { + return $this->featuredVariants->map(function (FeaturedVariant $featuredVariant) use ($request) { + $variant = $featuredVariant->variant; + $variantResource = (new ProductVariantResource($variant))->toArray($request); + + if ($this->product_layout === 'row' || $this->product_layout === 'column_with_cart' || $this->product_layout === 'vertical_with_cart') { + // Devuelve el Product Variant Resource completo como pidio el usuario + // "Que todo devuelva el product variant resource" + return $variantResource; + } + + // Para column_with_image o vertical_with_image + if ($this->product_layout === 'column_with_image' || $this->product_layout === 'vertical_with_image') { + if (isset($variantResource['images']) && count($variantResource['images']) > 0) { + $variantResource['images'] = [$variantResource['images'][0]]; + } + return $variantResource; + } + + return $variantResource; + }); + }), + ]; + } +} diff --git a/app/Domains/Catalog/routes/api.php b/app/Domains/Catalog/routes/api.php index 666d423..ab843de 100644 --- a/app/Domains/Catalog/routes/api.php +++ b/app/Domains/Catalog/routes/api.php @@ -1,6 +1,7 @@ group(function (): void { + Route::get('catalog', [CatalogController::class, 'index']); Route::apiResource('marcas', BrandController::class)->parameters(['marcas' => 'marca']); Route::apiResource('categorias', CategoryController::class)->parameters(['categorias' => 'categoria']); Route::apiResource('productos', ProductController::class); diff --git a/app/Domains/Product/Controllers/FeaturedGroupController.php b/app/Domains/Product/Controllers/FeaturedGroupController.php index 133f029..201014a 100644 --- a/app/Domains/Product/Controllers/FeaturedGroupController.php +++ b/app/Domains/Product/Controllers/FeaturedGroupController.php @@ -32,7 +32,7 @@ class FeaturedGroupController extends Controller public function show(string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource { abort_if($featuredGroup->tenant_codigo !== $tenant, 404); - return new FeaturedGroupResource($featuredGroup->load('featuredProducts')); + return new FeaturedGroupResource($featuredGroup->load('featuredVariants')); } public function update(UpdateFeaturedGroupRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource diff --git a/app/Domains/Product/Controllers/FeaturedProductController.php b/app/Domains/Product/Controllers/FeaturedProductController.php deleted file mode 100644 index e7e7cba..0000000 --- a/app/Domains/Product/Controllers/FeaturedProductController.php +++ /dev/null @@ -1,42 +0,0 @@ -tenant_codigo !== $tenant, 404); - return FeaturedProductResource::collection($featuredGroup->featuredProducts); - } - - public function store(StoreFeaturedProductRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedProductResource - { - abort_if($featuredGroup->tenant_codigo !== $tenant, 404); - $product = $featuredGroup->featuredProducts()->create($request->validated()); - return new FeaturedProductResource($product); - } - - public function update(UpdateFeaturedProductRequest $request, string $tenant, FeaturedGroup $featuredGroup, FeaturedProduct $featuredProduct): FeaturedProductResource - { - abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredProduct->featured_group_id !== $featuredGroup->id, 404); - $featuredProduct->update($request->validated()); - return new FeaturedProductResource($featuredProduct); - } - - public function destroy(string $tenant, FeaturedGroup $featuredGroup, FeaturedProduct $featuredProduct): JsonResponse - { - abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredProduct->featured_group_id !== $featuredGroup->id, 404); - $featuredProduct->delete(); - return response()->json(null, 204); - } -} diff --git a/app/Domains/Product/Controllers/FeaturedVariantController.php b/app/Domains/Product/Controllers/FeaturedVariantController.php new file mode 100644 index 0000000..c36343a --- /dev/null +++ b/app/Domains/Product/Controllers/FeaturedVariantController.php @@ -0,0 +1,42 @@ +tenant_codigo !== $tenant, 404); + return FeaturedVariantResource::collection($featuredGroup->featuredVariants); + } + + public function store(StoreFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedVariantResource + { + abort_if($featuredGroup->tenant_codigo !== $tenant, 404); + $variant = $featuredGroup->featuredVariants()->create($request->validated()); + return new FeaturedVariantResource($variant); + } + + public function update(UpdateFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup, FeaturedVariant $featuredVariant): FeaturedVariantResource + { + abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404); + $featuredVariant->update($request->validated()); + return new FeaturedVariantResource($featuredVariant); + } + + public function destroy(string $tenant, FeaturedGroup $featuredGroup, FeaturedVariant $featuredVariant): JsonResponse + { + abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404); + $featuredVariant->delete(); + return response()->json(null, 204); + } +} diff --git a/app/Domains/Product/Models/FeaturedGroup.php b/app/Domains/Product/Models/FeaturedGroup.php index 3015e08..8e36097 100644 --- a/app/Domains/Product/Models/FeaturedGroup.php +++ b/app/Domains/Product/Models/FeaturedGroup.php @@ -11,10 +11,11 @@ class FeaturedGroup extends Model 'tenant_codigo', 'group_name', 'product_layout', + 'group_order', ]; - public function featuredProducts(): HasMany + public function featuredVariants(): HasMany { - return $this->hasMany(FeaturedProduct::class); + return $this->hasMany(FeaturedVariant::class); } } diff --git a/app/Domains/Product/Models/FeaturedProduct.php b/app/Domains/Product/Models/FeaturedVariant.php similarity index 56% rename from app/Domains/Product/Models/FeaturedProduct.php rename to app/Domains/Product/Models/FeaturedVariant.php index 2e54f22..d7335f8 100644 --- a/app/Domains/Product/Models/FeaturedProduct.php +++ b/app/Domains/Product/Models/FeaturedVariant.php @@ -2,14 +2,17 @@ namespace App\Domains\Product\Models; +use App\Domains\Catalog\Models\ProductVariant; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -class FeaturedProduct extends Model +class FeaturedVariant extends Model { + protected $table = 'featured_variants'; + protected $fillable = [ 'featured_group_id', - 'product_id', + 'product_variant_id', 'order', ]; @@ -18,8 +21,8 @@ class FeaturedProduct extends Model return $this->belongsTo(FeaturedGroup::class); } - public function product(): BelongsTo + public function variant(): BelongsTo { - return $this->belongsTo(Product::class); + return $this->belongsTo(ProductVariant::class, 'product_variant_id'); } } diff --git a/app/Domains/Product/Requests/StoreFeaturedGroupRequest.php b/app/Domains/Product/Requests/StoreFeaturedGroupRequest.php index 0f60fd6..6ef31cd 100644 --- a/app/Domains/Product/Requests/StoreFeaturedGroupRequest.php +++ b/app/Domains/Product/Requests/StoreFeaturedGroupRequest.php @@ -15,7 +15,8 @@ class StoreFeaturedGroupRequest extends FormRequest { return [ 'group_name' => ['required', 'string', 'max:255'], - 'product_layout' => ['required', 'string', 'in:row,column_with_image,column_with_cart'], + 'product_layout' => ['required', 'string', 'in:row,column_with_image,column_with_cart,vertical_with_image,vertical_with_cart'], + 'group_order' => ['nullable', 'integer'], ]; } } diff --git a/app/Domains/Product/Requests/StoreFeaturedProductRequest.php b/app/Domains/Product/Requests/StoreFeaturedVariantRequest.php similarity index 71% rename from app/Domains/Product/Requests/StoreFeaturedProductRequest.php rename to app/Domains/Product/Requests/StoreFeaturedVariantRequest.php index 6c8aee6..08ce018 100644 --- a/app/Domains/Product/Requests/StoreFeaturedProductRequest.php +++ b/app/Domains/Product/Requests/StoreFeaturedVariantRequest.php @@ -4,7 +4,7 @@ namespace App\Domains\Product\Requests; use Illuminate\Foundation\Http\FormRequest; -class StoreFeaturedProductRequest extends FormRequest +class StoreFeaturedVariantRequest extends FormRequest { public function authorize(): bool { @@ -14,7 +14,7 @@ class StoreFeaturedProductRequest extends FormRequest public function rules(): array { return [ - 'product_id' => ['required', 'integer'], + 'product_variant_id' => ['required', 'integer'], 'order' => ['nullable', 'integer'], ]; } diff --git a/app/Domains/Product/Requests/UpdateFeaturedGroupRequest.php b/app/Domains/Product/Requests/UpdateFeaturedGroupRequest.php index 932b387..058aae9 100644 --- a/app/Domains/Product/Requests/UpdateFeaturedGroupRequest.php +++ b/app/Domains/Product/Requests/UpdateFeaturedGroupRequest.php @@ -15,7 +15,8 @@ class UpdateFeaturedGroupRequest extends FormRequest { return [ 'group_name' => ['sometimes', 'string', 'max:255'], - 'product_layout' => ['sometimes', 'string', 'in:row,column_with_image,column_with_cart'], + 'product_layout' => ['sometimes', 'string', 'in:row,column_with_image,column_with_cart,vertical_with_image,vertical_with_cart'], + 'group_order' => ['nullable', 'integer'], ]; } } diff --git a/app/Domains/Product/Requests/UpdateFeaturedProductRequest.php b/app/Domains/Product/Requests/UpdateFeaturedVariantRequest.php similarity index 84% rename from app/Domains/Product/Requests/UpdateFeaturedProductRequest.php rename to app/Domains/Product/Requests/UpdateFeaturedVariantRequest.php index c0aaec8..20e90bf 100644 --- a/app/Domains/Product/Requests/UpdateFeaturedProductRequest.php +++ b/app/Domains/Product/Requests/UpdateFeaturedVariantRequest.php @@ -4,7 +4,7 @@ namespace App\Domains\Product\Requests; use Illuminate\Foundation\Http\FormRequest; -class UpdateFeaturedProductRequest extends FormRequest +class UpdateFeaturedVariantRequest extends FormRequest { public function authorize(): bool { diff --git a/app/Domains/Product/Resources/FeaturedGroupResource.php b/app/Domains/Product/Resources/FeaturedGroupResource.php index 5cb1c73..3469333 100644 --- a/app/Domains/Product/Resources/FeaturedGroupResource.php +++ b/app/Domains/Product/Resources/FeaturedGroupResource.php @@ -14,7 +14,8 @@ class FeaturedGroupResource extends JsonResource 'tenant_codigo' => $this->tenant_codigo, 'group_name' => $this->group_name, 'product_layout' => $this->product_layout, - 'featured_products' => FeaturedProductResource::collection($this->whenLoaded('featuredProducts')), + 'group_order' => $this->group_order, + 'featured_variants' => FeaturedVariantResource::collection($this->whenLoaded('featuredVariants')), ]; } } diff --git a/app/Domains/Product/Resources/FeaturedProductResource.php b/app/Domains/Product/Resources/FeaturedVariantResource.php similarity index 66% rename from app/Domains/Product/Resources/FeaturedProductResource.php rename to app/Domains/Product/Resources/FeaturedVariantResource.php index 3a9b486..a73c93c 100644 --- a/app/Domains/Product/Resources/FeaturedProductResource.php +++ b/app/Domains/Product/Resources/FeaturedVariantResource.php @@ -5,16 +5,15 @@ namespace App\Domains\Product\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; -class FeaturedProductResource extends JsonResource +class FeaturedVariantResource extends JsonResource { public function toArray(Request $request): array { return [ 'id' => $this->id, 'featured_group_id' => $this->featured_group_id, - 'product_id' => $this->product_id, + 'product_variant_id' => $this->product_variant_id, 'order' => $this->order, - // You can add a nested ProductResource here if needed and when loaded ]; } } diff --git a/app/Domains/Product/routes/api.php b/app/Domains/Product/routes/api.php index b26e5bc..5a550c2 100644 --- a/app/Domains/Product/routes/api.php +++ b/app/Domains/Product/routes/api.php @@ -1,15 +1,15 @@ group(function (): void { Route::apiResource('featured-groups', FeaturedGroupController::class); - Route::apiResource('featured-groups.products', FeaturedProductController::class) + Route::apiResource('featured-groups.variants', FeaturedVariantController::class) ->only(['index', 'store', 'update', 'destroy']) ->parameters([ 'featured-groups' => 'featuredGroup', - 'products' => 'featuredProduct', + 'variants' => 'featuredVariant', ]); }); diff --git a/database/migrations/2026_07_14_174706_add_group_order_to_featured_groups_table.php b/database/migrations/2026_07_14_174706_add_group_order_to_featured_groups_table.php new file mode 100644 index 0000000..1fb8276 --- /dev/null +++ b/database/migrations/2026_07_14_174706_add_group_order_to_featured_groups_table.php @@ -0,0 +1,28 @@ +integer('group_order')->default(0)->after('product_layout'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('featured_groups', function (Blueprint $table) { + $table->dropColumn('group_order'); + }); + } +}; diff --git a/database/migrations/2026_07_14_174819_rename_featured_products_to_featured_variants.php b/database/migrations/2026_07_14_174819_rename_featured_products_to_featured_variants.php new file mode 100644 index 0000000..be31913 --- /dev/null +++ b/database/migrations/2026_07_14_174819_rename_featured_products_to_featured_variants.php @@ -0,0 +1,38 @@ +renameColumn('product_id', 'product_variant_id'); + }); + } + + Schema::table('featured_variants', function (Blueprint $table) { + $table->foreign('product_variant_id')->references('id')->on('productos_variantes')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('featured_variants', function (Blueprint $table) { + // + }); + } +};