feat: Introduce source type for featured groups; add category association and implement FeaturedGroupService for item sourcing
This commit is contained in:
@@ -2,34 +2,28 @@
|
||||
|
||||
namespace App\Domains\Catalog\Controllers;
|
||||
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Models\FeaturedItem;
|
||||
use App\Domains\Catalog\Requests\CatalogItemDetailRequest;
|
||||
use App\Domains\Catalog\Requests\CategoryPageRequest;
|
||||
use App\Domains\Catalog\Requests\FeaturedGroupPageRequest;
|
||||
use App\Domains\Catalog\Requests\SearchCatalogItemsRequest;
|
||||
use App\Domains\Catalog\Requests\StoreCatalogItemRequest;
|
||||
use App\Domains\Catalog\Resources\CatalogFeaturedGroupResource;
|
||||
use App\Domains\Catalog\Resources\CatalogFeaturedItemResource;
|
||||
use App\Domains\Catalog\Resources\CatalogItemDetailResource;
|
||||
use App\Domains\Catalog\Resources\CatalogItemResource;
|
||||
use App\Domains\Catalog\Resources\CatalogSearchItemResource;
|
||||
use App\Domains\Catalog\Services\CatalogService;
|
||||
use App\Domains\Catalog\Services\FeaturedGroupService;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
class CatalogController extends Controller
|
||||
{
|
||||
private const ITEMS_PER_PAGE = 12;
|
||||
|
||||
public function index(Tenant $tenant): JsonResponse
|
||||
public function index(Tenant $tenant, FeaturedGroupService $featuredGroupService): JsonResponse
|
||||
{
|
||||
$featuredGroups = FeaturedGroup::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
@@ -39,7 +33,7 @@ class CatalogController extends Controller
|
||||
return response()->json($featuredGroups->map(
|
||||
fn (FeaturedGroup $featuredGroup): array => (new CatalogFeaturedGroupResource(
|
||||
$featuredGroup,
|
||||
$this->featuredItemsResponse($featuredGroup, 1),
|
||||
$featuredGroupService->itemsResponse($featuredGroup, 1),
|
||||
))->resolve()
|
||||
));
|
||||
}
|
||||
@@ -89,12 +83,13 @@ class CatalogController extends Controller
|
||||
FeaturedGroupPageRequest $request,
|
||||
Tenant $tenant,
|
||||
FeaturedGroup $featuredGroup,
|
||||
FeaturedGroupService $featuredGroupService,
|
||||
): JsonResponse {
|
||||
abort_unless($featuredGroup->tenant_code === $tenant->codigo, 404);
|
||||
|
||||
$page = (int) $request->validated('page', 1);
|
||||
|
||||
return response()->json($this->featuredItemsResponse($featuredGroup, $page));
|
||||
return response()->json($featuredGroupService->itemsResponse($featuredGroup, $page));
|
||||
}
|
||||
|
||||
public function show(
|
||||
@@ -129,59 +124,4 @@ class CatalogController extends Controller
|
||||
->response()
|
||||
->setStatusCode(201);
|
||||
}
|
||||
|
||||
/** @return array<array-key, mixed> */
|
||||
private function featuredItemsResponse(FeaturedGroup $featuredGroup, int $page): array
|
||||
{
|
||||
if ($featuredGroup->group_layout !== GroupLayout::Paginated) {
|
||||
$featuredItems = $this->featuredItemsQuery($featuredGroup)->get();
|
||||
|
||||
$featuredItems->each(
|
||||
fn ($featuredItem) => $featuredItem->setRelation('featuredGroup', $featuredGroup)
|
||||
);
|
||||
|
||||
return CatalogFeaturedItemResource::collection($featuredItems)->resolve();
|
||||
}
|
||||
|
||||
$paginator = $this->paginateFeaturedItems($featuredGroup, $page);
|
||||
|
||||
$paginator->getCollection()->each(
|
||||
fn ($featuredItem) => $featuredItem->setRelation('featuredGroup', $featuredGroup)
|
||||
);
|
||||
|
||||
return CatalogFeaturedItemResource::collection($paginator)
|
||||
->response()
|
||||
->getData(true);
|
||||
}
|
||||
|
||||
private function paginateFeaturedItems(
|
||||
FeaturedGroup $featuredGroup,
|
||||
int $page,
|
||||
): LengthAwarePaginator {
|
||||
$paginator = $this->featuredItemsQuery($featuredGroup)->paginate(
|
||||
perPage: self::ITEMS_PER_PAGE,
|
||||
pageName: 'page',
|
||||
page: $page,
|
||||
);
|
||||
|
||||
return $paginator->withPath(route('catalog.featured-groups.items.index', [
|
||||
'tenant' => $featuredGroup->tenant_code,
|
||||
'featuredGroup' => $featuredGroup->id,
|
||||
]));
|
||||
}
|
||||
|
||||
/** @return HasMany<FeaturedItem, FeaturedGroup> */
|
||||
private function featuredItemsQuery(FeaturedGroup $featuredGroup): HasMany
|
||||
{
|
||||
return $featuredGroup->featuredItems()->with([
|
||||
'catalogItem.inventory',
|
||||
'catalogItem.attachments',
|
||||
'catalogItem.variants.inventory',
|
||||
'catalogItem.variants.attachments',
|
||||
'catalogItem.variants.eventDate',
|
||||
'catalogItem.variants.definitions.itemAttribute.attribute',
|
||||
'catalogItem.bundleComponents.catalogItem',
|
||||
'catalogItem.bundleComponents.variant.catalogItem',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
18
app/Domains/Catalog/Enums/FeaturedGroupSource.php
Normal file
18
app/Domains/Catalog/Enums/FeaturedGroupSource.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Enums;
|
||||
|
||||
enum FeaturedGroupSource: string
|
||||
{
|
||||
case Manual = 'manual';
|
||||
case Category = 'category';
|
||||
case All = 'all';
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function values(): array
|
||||
{
|
||||
return array_column(self::cases(), 'value');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Domains\Catalog\Models;
|
||||
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -13,6 +14,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'tenant_code',
|
||||
'source_type',
|
||||
'category_id',
|
||||
'product_layout',
|
||||
'group_layout',
|
||||
'group_name',
|
||||
@@ -26,9 +29,15 @@ class FeaturedGroup extends Model
|
||||
|
||||
protected $table = 'featured_groups';
|
||||
|
||||
protected $attributes = [
|
||||
'source_type' => FeaturedGroupSource::Manual->value,
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'source_type' => FeaturedGroupSource::class,
|
||||
'category_id' => 'integer',
|
||||
'product_layout' => ProductLayout::class,
|
||||
'group_layout' => GroupLayout::class,
|
||||
'group_order' => 'integer',
|
||||
@@ -41,6 +50,12 @@ class FeaturedGroup extends Model
|
||||
return $this->belongsTo(Tenant::class, 'tenant_code', 'codigo');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Category, $this> */
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
/** @return HasMany<FeaturedItem, $this> */
|
||||
public function featuredItems(): HasMany
|
||||
{
|
||||
|
||||
@@ -5,20 +5,22 @@ namespace App\Domains\Catalog\Resources;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\FeaturedItem;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/** @mixin FeaturedItem */
|
||||
/** @mixin CatalogItem */
|
||||
class CatalogFeaturedItemResource extends JsonResource
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$catalogItem = $this->catalogItem;
|
||||
$catalogItem = $this->resource;
|
||||
/** @var FeaturedGroup $featuredGroup */
|
||||
$featuredGroup = $catalogItem->getRelation('featuredGroup');
|
||||
|
||||
if ($this->featuredGroup->product_layout === ProductLayout::ColumnWithImage) {
|
||||
if ($featuredGroup->product_layout === ProductLayout::ColumnWithImage) {
|
||||
return $this->columnWithImageData($catalogItem);
|
||||
}
|
||||
|
||||
|
||||
87
app/Domains/Catalog/Services/FeaturedGroupService.php
Normal file
87
app/Domains/Catalog/Services/FeaturedGroupService.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Catalog\Services;
|
||||
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Resources\CatalogFeaturedItemResource;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
class FeaturedGroupService
|
||||
{
|
||||
private const ITEMS_PER_PAGE = 12;
|
||||
|
||||
/** @return array<array-key, mixed> */
|
||||
public function itemsResponse(FeaturedGroup $featuredGroup, int $page): array
|
||||
{
|
||||
if ($featuredGroup->group_layout !== GroupLayout::Paginated) {
|
||||
$items = $this->itemsQuery($featuredGroup)->get();
|
||||
$this->attachGroup($items, $featuredGroup);
|
||||
|
||||
return CatalogFeaturedItemResource::collection($items)->resolve();
|
||||
}
|
||||
|
||||
$paginator = $this->paginateItems($featuredGroup, $page);
|
||||
$this->attachGroup($paginator->getCollection(), $featuredGroup);
|
||||
|
||||
return CatalogFeaturedItemResource::collection($paginator)
|
||||
->response()
|
||||
->getData(true);
|
||||
}
|
||||
|
||||
/** @return Builder<CatalogItem> */
|
||||
private function itemsQuery(FeaturedGroup $featuredGroup): Builder
|
||||
{
|
||||
$query = CatalogItem::query()
|
||||
->where('catalog_items.tenant_code', $featuredGroup->tenant_code)
|
||||
->with([
|
||||
'inventory',
|
||||
'attachments',
|
||||
'variants.inventory',
|
||||
'variants.attachments',
|
||||
'variants.eventDate',
|
||||
'variants.definitions.itemAttribute.attribute',
|
||||
'bundleComponents.catalogItem',
|
||||
'bundleComponents.variant.catalogItem',
|
||||
]);
|
||||
|
||||
return match ($featuredGroup->source_type) {
|
||||
FeaturedGroupSource::Manual => $query
|
||||
->select('catalog_items.*')
|
||||
->join('featured_items', 'featured_items.catalog_item_id', '=', 'catalog_items.id')
|
||||
->where('featured_items.featured_group_id', $featuredGroup->id)
|
||||
->orderBy('featured_items.order')
|
||||
->orderBy('featured_items.id'),
|
||||
FeaturedGroupSource::Category => $query
|
||||
->where('catalog_items.category_id', $featuredGroup->category_id)
|
||||
->orderBy('catalog_items.id'),
|
||||
FeaturedGroupSource::All => $query->orderBy('catalog_items.id'),
|
||||
};
|
||||
}
|
||||
|
||||
private function paginateItems(
|
||||
FeaturedGroup $featuredGroup,
|
||||
int $page,
|
||||
): LengthAwarePaginator {
|
||||
$paginator = $this->itemsQuery($featuredGroup)->paginate(
|
||||
perPage: self::ITEMS_PER_PAGE,
|
||||
pageName: 'page',
|
||||
page: $page,
|
||||
);
|
||||
|
||||
return $paginator->withPath(route('catalog.featured-groups.items.index', [
|
||||
'tenant' => $featuredGroup->tenant_code,
|
||||
'featuredGroup' => $featuredGroup->id,
|
||||
]));
|
||||
}
|
||||
|
||||
private function attachGroup(iterable $items, FeaturedGroup $featuredGroup): void
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
$item->setRelation('featuredGroup', $featuredGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('featured_groups', function (Blueprint $table): void {
|
||||
$table->enum('source_type', FeaturedGroupSource::values())
|
||||
->default(FeaturedGroupSource::Manual->value)
|
||||
->after('tenant_code');
|
||||
$table->foreignId('category_id')
|
||||
->nullable()
|
||||
->after('source_type')
|
||||
->constrained('categorias')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('featured_groups', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('category_id');
|
||||
$table->dropColumn('source_type');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -4,6 +4,7 @@ namespace Database\Seeders;
|
||||
|
||||
use App\Domains\Catalog\Enums\CatalogItemType;
|
||||
use App\Domains\Catalog\Enums\EventProductType;
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
@@ -61,6 +62,18 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'nombre' => 'Gastronomía',
|
||||
'tenant_code' => $tenant->codigo,
|
||||
]);
|
||||
$mealCategory = Category::query()->updateOrCreate([
|
||||
'nombre' => 'Comidas',
|
||||
'tenant_code' => $tenant->codigo,
|
||||
], [
|
||||
'categoria_id' => $foodCategory->id,
|
||||
]);
|
||||
$drinkCategory = Category::query()->updateOrCreate([
|
||||
'nombre' => 'Bebidas',
|
||||
'tenant_code' => $tenant->codigo,
|
||||
], [
|
||||
'categoria_id' => $foodCategory->id,
|
||||
]);
|
||||
$parkingCategory = Category::query()->firstOrCreate([
|
||||
'nombre' => 'Estacionamiento',
|
||||
'tenant_code' => $tenant->codigo,
|
||||
@@ -93,10 +106,10 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
]);
|
||||
|
||||
$items = [
|
||||
['slug' => 'hamburguesa-papa-frita', 'nombre' => 'Hamburguesa con papa frita', 'precio' => 8000, 'category_id' => $foodCategory->id],
|
||||
['slug' => 'pancho', 'nombre' => 'Pancho', 'precio' => 4000, 'category_id' => $foodCategory->id],
|
||||
['slug' => 'coca-cola-500ml', 'nombre' => 'Coca Cola 500ml', 'precio' => 3000, 'category_id' => $foodCategory->id],
|
||||
['slug' => 'agua-mineral-1l', 'nombre' => 'Agua Mineral 1L', 'precio' => 2500, 'category_id' => $foodCategory->id],
|
||||
['slug' => 'hamburguesa-papa-frita', 'nombre' => 'Hamburguesa con papa frita', 'precio' => 8000, 'category_id' => $mealCategory->id],
|
||||
['slug' => 'pancho', 'nombre' => 'Pancho', 'precio' => 4000, 'category_id' => $mealCategory->id],
|
||||
['slug' => 'coca-cola-500ml', 'nombre' => 'Coca Cola 500ml', 'precio' => 3000, 'category_id' => $drinkCategory->id],
|
||||
['slug' => 'agua-mineral-1l', 'nombre' => 'Agua Mineral 1L', 'precio' => 2500, 'category_id' => $drinkCategory->id],
|
||||
['slug' => 'estacionamiento-auto', 'nombre' => 'Estacionamiento Auto', 'precio' => 5000, 'category_id' => $parkingCategory->id],
|
||||
['slug' => 'estacionamiento-moto', 'nombre' => 'Estacionamiento Moto', 'precio' => 2000, 'category_id' => $parkingCategory->id],
|
||||
];
|
||||
@@ -144,7 +157,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'nombre' => 'Combo 2 Panchos + 2 Hamburguesas',
|
||||
'descripcion' => 'Incluye 2 panchos y 2 hamburguesas con papa frita.',
|
||||
'precio' => 24000,
|
||||
'category_id' => $foodCategory->id,
|
||||
'category_id' => $mealCategory->id,
|
||||
'components' => [
|
||||
[
|
||||
'catalog_item_id' => $createdItems['pancho']->id,
|
||||
@@ -157,7 +170,12 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
],
|
||||
]);
|
||||
|
||||
$this->seedFeaturedGroups($tenant);
|
||||
$this->seedFeaturedGroups($tenant, [
|
||||
'Entradas' => $ticketCategory,
|
||||
'Estacionamiento' => $parkingCategory,
|
||||
'Comidas' => $mealCategory,
|
||||
'Bebidas' => $drinkCategory,
|
||||
]);
|
||||
}
|
||||
|
||||
private function deleteExistingCatalog(Tenant $tenant): void
|
||||
@@ -173,7 +191,8 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
->each(fn (CatalogItem $item) => $this->catalogService->delete($item));
|
||||
}
|
||||
|
||||
private function seedFeaturedGroups(Tenant $tenant): void
|
||||
/** @param array<string, Category> $categories */
|
||||
private function seedFeaturedGroups(Tenant $tenant, array $categories): void
|
||||
{
|
||||
FeaturedGroup::query()->where('tenant_code', $tenant->codigo)->delete();
|
||||
|
||||
@@ -181,62 +200,33 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'Entradas' => [
|
||||
'product_layout' => ProductLayout::Row,
|
||||
'group_layout' => GroupLayout::SimpleVertical,
|
||||
'slugs' => [
|
||||
'entrada-general',
|
||||
'entrada-general-todos-los-dias',
|
||||
],
|
||||
],
|
||||
'Estacionamiento' => [
|
||||
'product_layout' => ProductLayout::ColumnWithCart,
|
||||
'group_layout' => GroupLayout::Simple,
|
||||
'slugs' => [
|
||||
'estacionamiento-auto',
|
||||
'estacionamiento-moto',
|
||||
],
|
||||
],
|
||||
'Comidas' => [
|
||||
'product_layout' => ProductLayout::ColumnWithCart,
|
||||
'group_layout' => GroupLayout::Simple,
|
||||
'slugs' => [
|
||||
'hamburguesa-papa-frita',
|
||||
'pancho',
|
||||
'combo-2-panchos-2-hamburguesas',
|
||||
],
|
||||
],
|
||||
'Bebidas' => [
|
||||
'product_layout' => ProductLayout::ColumnWithCart,
|
||||
'group_layout' => GroupLayout::Simple,
|
||||
'slugs' => [
|
||||
'coca-cola-500ml',
|
||||
'agua-mineral-1l',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$catalogItems = CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->whereIn('slug', collect($groups)->pluck('slugs')->flatten()->all())
|
||||
->get()
|
||||
->keyBy('slug');
|
||||
|
||||
$groupOrder = 0;
|
||||
foreach ($groups as $groupName => $config) {
|
||||
$featuredGroup = FeaturedGroup::query()->create([
|
||||
FeaturedGroup::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'source_type' => FeaturedGroupSource::Category,
|
||||
'category_id' => $categories[$groupName]->id,
|
||||
'product_layout' => $config['product_layout'],
|
||||
'group_layout' => $config['group_layout'],
|
||||
'group_name' => $groupName,
|
||||
'group_order' => $groupOrder++,
|
||||
]);
|
||||
|
||||
$featuredGroup->featuredItems()->createMany(
|
||||
collect($config['slugs'])->values()->map(
|
||||
fn (string $slug, int $order): array => [
|
||||
'catalog_item_id' => $catalogItems->get($slug)->id,
|
||||
'order' => $order,
|
||||
]
|
||||
)->all()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
@@ -168,30 +169,18 @@ class ProductCatalogFromImagesSeeder extends Seeder
|
||||
{
|
||||
FeaturedGroup::query()->where('tenant_code', $tenant->codigo)->delete();
|
||||
|
||||
$paginatedGroup = FeaturedGroup::query()->create([
|
||||
FeaturedGroup::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'source_type' => FeaturedGroupSource::All,
|
||||
'product_layout' => ProductLayout::ColumnWithImage,
|
||||
'group_layout' => GroupLayout::Paginated,
|
||||
'group_name' => 'Productos',
|
||||
'group_order' => 2,
|
||||
]);
|
||||
|
||||
$items = CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->orderBy('id')
|
||||
->get('id');
|
||||
|
||||
$paginatedGroup->featuredItems()->createMany(
|
||||
$items->values()->map(
|
||||
fn (CatalogItem $item, int $order): array => [
|
||||
'catalog_item_id' => $item->id,
|
||||
'order' => $order,
|
||||
]
|
||||
)->all()
|
||||
);
|
||||
|
||||
$carouselGroup = FeaturedGroup::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'source_type' => FeaturedGroupSource::Manual,
|
||||
'product_layout' => ProductLayout::ColumnWithImage,
|
||||
'group_layout' => GroupLayout::Carousel,
|
||||
'group_name' => 'Productos destacados',
|
||||
|
||||
@@ -4,9 +4,11 @@ namespace Tests\Feature\Catalog;
|
||||
|
||||
use App\Domains\Attachable\Enums\AttachmentType;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Models\Inventory;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -198,6 +200,46 @@ class CatalogControllerTest extends TestCase
|
||||
->assertJsonPath('0.nombre', 'carousel Item 1');
|
||||
}
|
||||
|
||||
public function test_groups_can_source_items_from_a_category_or_the_entire_catalog(): void
|
||||
{
|
||||
$tenant = $this->createTenant('catalog-sources');
|
||||
$category = Category::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'nombre' => 'Food',
|
||||
]);
|
||||
|
||||
FeaturedGroup::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'source_type' => FeaturedGroupSource::Category,
|
||||
'category_id' => $category->id,
|
||||
'product_layout' => ProductLayout::Row,
|
||||
'group_layout' => GroupLayout::Simple,
|
||||
'group_name' => 'Food',
|
||||
'group_order' => 0,
|
||||
]);
|
||||
FeaturedGroup::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'source_type' => FeaturedGroupSource::All,
|
||||
'product_layout' => ProductLayout::Row,
|
||||
'group_layout' => GroupLayout::Paginated,
|
||||
'group_name' => 'All products',
|
||||
'group_order' => 1,
|
||||
]);
|
||||
|
||||
$food = $this->createItem($tenant, 'Hamburger');
|
||||
$food->category()->associate($category)->save();
|
||||
$this->createItem($tenant, 'Parking');
|
||||
|
||||
$this->getJson("/api/tenants/{$tenant->codigo}/catalog")
|
||||
->assertOk()
|
||||
->assertJsonPath('0.title', 'Food')
|
||||
->assertJsonCount(1, '0.items')
|
||||
->assertJsonPath('0.items.0.nombre', 'Hamburger')
|
||||
->assertJsonPath('1.title', 'All products')
|
||||
->assertJsonCount(2, '1.items.data')
|
||||
->assertJsonPath('1.items.meta.total', 2);
|
||||
}
|
||||
|
||||
private function createGroup(
|
||||
Tenant $tenant,
|
||||
ProductLayout $layout,
|
||||
|
||||
@@ -79,6 +79,8 @@ class CatalogSchemaTest extends TestCase
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'id',
|
||||
'tenant_code',
|
||||
'source_type',
|
||||
'category_id',
|
||||
'product_layout',
|
||||
'group_layout',
|
||||
'group_name',
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Domains\Attachable\Enums\AttachmentType;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Catalog\Enums\CatalogItemType;
|
||||
use App\Domains\Catalog\Enums\EventProductType;
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
@@ -174,7 +175,7 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
|
||||
$this->assertSame(9, CatalogItem::query()->where('tenant_code', $tenant->codigo)->count());
|
||||
$this->assertSame(10, Inventory::query()->count());
|
||||
$this->assertSame(
|
||||
['Entradas', 'Estacionamiento', 'Gastronomía'],
|
||||
['Bebidas', 'Comidas', 'Entradas', 'Estacionamiento', 'Gastronomía'],
|
||||
Category::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->orderBy('nombre')
|
||||
@@ -194,7 +195,7 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
|
||||
|
||||
$featuredGroups = FeaturedGroup::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->with('featuredItems.catalogItem')
|
||||
->with('category.catalogItems')
|
||||
->orderBy('group_order')
|
||||
->get();
|
||||
|
||||
@@ -207,21 +208,23 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
|
||||
],
|
||||
$featuredGroups
|
||||
->mapWithKeys(fn (FeaturedGroup $group): array => [
|
||||
$group->group_name => $group->featuredItems->pluck('catalogItem.slug')->all(),
|
||||
$group->group_name => $group->category->catalogItems->pluck('slug')->all(),
|
||||
])
|
||||
->all()
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
['Entradas', ProductLayout::Row, GroupLayout::SimpleVertical, 0],
|
||||
['Estacionamiento', ProductLayout::ColumnWithCart, GroupLayout::Simple, 1],
|
||||
['Comidas', ProductLayout::ColumnWithCart, GroupLayout::Simple, 2],
|
||||
['Bebidas', ProductLayout::ColumnWithCart, GroupLayout::Simple, 3],
|
||||
['Entradas', FeaturedGroupSource::Category, 'Entradas', ProductLayout::Row, GroupLayout::SimpleVertical, 0],
|
||||
['Estacionamiento', FeaturedGroupSource::Category, 'Estacionamiento', ProductLayout::ColumnWithCart, GroupLayout::Simple, 1],
|
||||
['Comidas', FeaturedGroupSource::Category, 'Comidas', ProductLayout::ColumnWithCart, GroupLayout::Simple, 2],
|
||||
['Bebidas', FeaturedGroupSource::Category, 'Bebidas', ProductLayout::ColumnWithCart, GroupLayout::Simple, 3],
|
||||
],
|
||||
$featuredGroups
|
||||
->map(fn (FeaturedGroup $group): array => [
|
||||
$group->group_name,
|
||||
$group->source_type,
|
||||
$group->category->nombre,
|
||||
$group->product_layout,
|
||||
$group->group_layout,
|
||||
$group->group_order,
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Seeders;
|
||||
|
||||
use App\Domains\Attachable\Enums\AttachmentType;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
@@ -70,16 +71,14 @@ class ProductCatalogFromImagesSeederTest extends TestCase
|
||||
$this->assertNotNull($paginatedGroup);
|
||||
$this->assertSame(ProductLayout::ColumnWithImage, $paginatedGroup->product_layout);
|
||||
$this->assertSame(GroupLayout::Paginated, $paginatedGroup->group_layout);
|
||||
$this->assertSame(0, $paginatedGroup->group_order);
|
||||
$this->assertSame(
|
||||
CatalogItem::query()->where('tenant_code', $tenant->codigo)->orderBy('id')->pluck('slug')->all(),
|
||||
$paginatedGroup->featuredItems->pluck('catalogItem.slug')->all(),
|
||||
);
|
||||
$this->assertCount(10, $paginatedGroup->featuredItems);
|
||||
$this->assertSame(FeaturedGroupSource::All, $paginatedGroup->source_type);
|
||||
$this->assertSame(2, $paginatedGroup->group_order);
|
||||
$this->assertCount(0, $paginatedGroup->featuredItems);
|
||||
|
||||
$this->assertNotNull($carouselGroup);
|
||||
$this->assertSame(ProductLayout::ColumnWithImage, $carouselGroup->product_layout);
|
||||
$this->assertSame(GroupLayout::Carousel, $carouselGroup->group_layout);
|
||||
$this->assertSame(FeaturedGroupSource::Manual, $carouselGroup->source_type);
|
||||
$this->assertSame(1, $carouselGroup->group_order);
|
||||
$this->assertCount(5, $carouselGroup->featuredItems);
|
||||
$this->assertCount(
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Tests\Unit\Catalog;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Catalog\Enums\CatalogItemType;
|
||||
use App\Domains\Catalog\Enums\EventProductType;
|
||||
use App\Domains\Catalog\Enums\FeaturedGroupSource;
|
||||
use App\Domains\Catalog\Enums\GroupLayout;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Enums\ProductLayout;
|
||||
@@ -104,6 +105,8 @@ class CatalogModelsTest extends TestCase
|
||||
{
|
||||
$group = new FeaturedGroup;
|
||||
$group->setRawAttributes([
|
||||
'source_type' => FeaturedGroupSource::Category->value,
|
||||
'category_id' => '4',
|
||||
'product_layout' => ProductLayout::ColumnWithImage->value,
|
||||
'group_layout' => GroupLayout::SimpleVertical->value,
|
||||
'group_order' => '2',
|
||||
@@ -118,9 +121,12 @@ class CatalogModelsTest extends TestCase
|
||||
$this->assertSame('featured_groups', $group->getTable());
|
||||
$this->assertFalse($group->usesTimestamps());
|
||||
$this->assertSame(ProductLayout::ColumnWithImage, $group->product_layout);
|
||||
$this->assertSame(FeaturedGroupSource::Category, $group->source_type);
|
||||
$this->assertSame(4, $group->category_id);
|
||||
$this->assertSame(GroupLayout::SimpleVertical, $group->group_layout);
|
||||
$this->assertSame(2, $group->group_order);
|
||||
$this->assertInstanceOf(Tenant::class, $group->tenant()->getRelated());
|
||||
$this->assertInstanceOf(Category::class, $group->category()->getRelated());
|
||||
$this->assertInstanceOf(FeaturedItem::class, $group->featuredItems()->getRelated());
|
||||
|
||||
$this->assertSame('featured_items', $featuredItem->getTable());
|
||||
|
||||
Reference in New Issue
Block a user