refactor: integrate category handling for entries and food items in services and tests

This commit is contained in:
2026-08-07 14:34:59 -03:00
parent e1ad27ecf0
commit 11776f0734
6 changed files with 70 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Domains\FiestaFutbolInfantil\Services;
use App\Domains\Catalog\Enums\EventProductType; use App\Domains\Catalog\Enums\EventProductType;
use App\Domains\Catalog\Enums\InventoryPolicy; use App\Domains\Catalog\Enums\InventoryPolicy;
use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory; use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\Variant; use App\Domains\Catalog\Models\Variant;
use App\Domains\Catalog\Services\CatalogService; use App\Domains\Catalog\Services\CatalogService;
@@ -26,10 +27,14 @@ class EntryService
{ {
return DB::transaction(function () use ($tenant, $entries): Collection { return DB::transaction(function () use ($tenant, $entries): Collection {
$reservedSlugs = []; $reservedSlugs = [];
$category = Category::query()->firstOrCreate([
'tenant_code' => $tenant->codigo,
'nombre' => 'Entradas',
]);
return collect($entries)->map(function (array $entry, int $index) use ($tenant, &$reservedSlugs): CatalogItem { return collect($entries)->map(function (array $entry, int $index) use ($tenant, $category, &$reservedSlugs): CatalogItem {
if (isset($entry['id'])) { if (isset($entry['id'])) {
return $this->update($tenant, $entry, $index); return $this->update($tenant, $category, $entry, $index);
} }
$slug = $this->uniqueSlug($tenant, $entry['title'], $reservedSlugs); $slug = $this->uniqueSlug($tenant, $entry['title'], $reservedSlugs);
@@ -40,6 +45,7 @@ class EntryService
'slug' => $slug, 'slug' => $slug,
'nombre' => $entry['title'], 'nombre' => $entry['title'],
'descripcion' => $entry['description'] ?? null, 'descripcion' => $entry['description'] ?? null,
'category_id' => $category->id,
'precio' => $entry['price'], 'precio' => $entry['price'],
'event_product_type' => EventProductType::Entry->value, 'event_product_type' => EventProductType::Entry->value,
'has_tickets' => true, 'has_tickets' => true,
@@ -56,7 +62,7 @@ class EntryService
} }
/** @param array<string, mixed> $entry */ /** @param array<string, mixed> $entry */
private function update(Tenant $tenant, array $entry, int $index): CatalogItem private function update(Tenant $tenant, Category $category, array $entry, int $index): CatalogItem
{ {
$catalogItem = CatalogItem::query() $catalogItem = CatalogItem::query()
->whereKey($entry['id']) ->whereKey($entry['id'])
@@ -100,6 +106,7 @@ class EntryService
$catalogItem->update([ $catalogItem->update([
'nombre' => $entry['title'], 'nombre' => $entry['title'],
'descripcion' => $entry['description'] ?? null, 'descripcion' => $entry['description'] ?? null,
'category_id' => $category->id,
'precio' => $entry['price'], 'precio' => $entry['price'],
'has_tickets' => true, 'has_tickets' => true,
'inventory_policy' => InventoryPolicy::Tracked->value, 'inventory_policy' => InventoryPolicy::Tracked->value,

View File

@@ -7,6 +7,7 @@ use App\Domains\Catalog\Enums\InventoryPolicy;
use App\Domains\Catalog\Models\Attribute; use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\AttributeOption; use App\Domains\Catalog\Models\AttributeOption;
use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\Inventory; use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\ItemAttribute; use App\Domains\Catalog\Models\ItemAttribute;
use App\Domains\Catalog\Models\Variant; use App\Domains\Catalog\Models\Variant;
@@ -96,6 +97,10 @@ class FoodService
/** @param array<int, array<string, mixed>> $variants */ /** @param array<int, array<string, mixed>> $variants */
private function food(Tenant $tenant, array $variants): CatalogItem private function food(Tenant $tenant, array $variants): CatalogItem
{ {
$category = Category::query()->firstOrCreate([
'tenant_code' => $tenant->codigo,
'nombre' => 'Comidas',
]);
$food = CatalogItem::query() $food = CatalogItem::query()
->where('tenant_code', $tenant->codigo) ->where('tenant_code', $tenant->codigo)
->where('slug', 'comida') ->where('slug', 'comida')
@@ -104,6 +109,7 @@ class FoodService
if ($food !== null) { if ($food !== null) {
$food->update([ $food->update([
'category_id' => $category->id,
'event_product_type' => EventProductType::Product->value, 'event_product_type' => EventProductType::Product->value,
'inventory_policy' => InventoryPolicy::Tracked->value, 'inventory_policy' => InventoryPolicy::Tracked->value,
'has_tickets' => false, 'has_tickets' => false,
@@ -117,6 +123,7 @@ class FoodService
'slug' => 'comida', 'slug' => 'comida',
'nombre' => 'Comida', 'nombre' => 'Comida',
'descripcion' => 'Comida', 'descripcion' => 'Comida',
'category_id' => $category->id,
'precio' => collect($variants)->min('price') ?? 0, 'precio' => collect($variants)->min('price') ?? 0,
'event_product_type' => EventProductType::Product->value, 'event_product_type' => EventProductType::Product->value,
'inventory_policy' => InventoryPolicy::Tracked->value, 'inventory_policy' => InventoryPolicy::Tracked->value,

View File

@@ -32,6 +32,16 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
Category::query()->where('tenant_code', $tenant->codigo)->update(['categoria_id' => null]); Category::query()->where('tenant_code', $tenant->codigo)->update(['categoria_id' => null]);
Category::query()->where('tenant_code', $tenant->codigo)->delete(); Category::query()->where('tenant_code', $tenant->codigo)->delete();
$categories = collect([
'entradas' => 'Entradas',
'alojamientos' => 'Alojamientos',
'comidas' => 'Comidas',
'merchandising' => 'Merchandising',
])->map(fn (string $name): Category => Category::query()->create([
'nombre' => $name,
'tenant_code' => $tenant->codigo,
]));
$tenant->update([ $tenant->update([
'event_title' => 'Fiesta Nacional del Fútbol Infantil', 'event_title' => 'Fiesta Nacional del Fútbol Infantil',
'event_location' => 'Sunchales, Santa Fe', 'event_location' => 'Sunchales, Santa Fe',
@@ -49,6 +59,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
$this->createProduct($tenant, [ $this->createProduct($tenant, [
'slug' => 'camiseta', 'slug' => 'camiseta',
'nombre' => 'Camiseta', 'nombre' => 'Camiseta',
'category_id' => $categories['merchandising']->id,
'precio' => 18000, 'precio' => 18000,
'attribute_codes' => ['color', 'talle'], 'attribute_codes' => ['color', 'talle'],
'variants' => collect(['Verde', 'Blanco']) 'variants' => collect(['Verde', 'Blanco'])
@@ -62,6 +73,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
$this->createProduct($tenant, [ $this->createProduct($tenant, [
'slug' => 'alojamiento', 'slug' => 'alojamiento',
'nombre' => 'Alojamiento', 'nombre' => 'Alojamiento',
'category_id' => $categories['alojamientos']->id,
'precio' => 35000, 'precio' => 35000,
'attribute_codes' => ['tipo_alojamiento'], 'attribute_codes' => ['tipo_alojamiento'],
'variants' => collect(['Carpa', 'Motorhome'])->map(fn (string $type): array => [ 'variants' => collect(['Carpa', 'Motorhome'])->map(fn (string $type): array => [
@@ -73,6 +85,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
$this->createProduct($tenant, [ $this->createProduct($tenant, [
'slug' => 'comida', 'slug' => 'comida',
'nombre' => 'Comida', 'nombre' => 'Comida',
'category_id' => $categories['comidas']->id,
'precio' => 4000, 'precio' => 4000,
'attribute_codes' => ['event_date', 'horario', 'servicio'], 'attribute_codes' => ['event_date', 'horario', 'servicio'],
'variants' => $eventDates 'variants' => $eventDates
@@ -94,6 +107,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
$this->createProduct($tenant, [ $this->createProduct($tenant, [
'slug' => 'abono', 'slug' => 'abono',
'nombre' => 'Abono', 'nombre' => 'Abono',
'category_id' => $categories['entradas']->id,
'precio' => 40000, 'precio' => 40000,
'event_product_type' => EventProductType::Entry->value, 'event_product_type' => EventProductType::Entry->value,
'has_tickets' => true, 'has_tickets' => true,

View File

@@ -6,6 +6,7 @@ use App\Domains\Auth\Models\User;
use App\Domains\Authorization\Enums\RoleCode; use App\Domains\Authorization\Enums\RoleCode;
use App\Domains\Catalog\Models\Attribute; use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Shared\Enums\FieldType; use App\Domains\Shared\Enums\FieldType;
use App\Domains\Tenant\Models\Tenant; use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType; use App\Domains\Tenant\Models\WebsiteType;
@@ -83,8 +84,14 @@ class EntryControllerTest extends TestCase
$this->assertDatabaseCount('inventories', 2); $this->assertDatabaseCount('inventories', 2);
$this->assertDatabaseCount('variant_event_dates', 3); $this->assertDatabaseCount('variant_event_dates', 3);
CatalogItem::query()->each(function (CatalogItem $entry) use ($tenant): void { $entryCategory = Category::query()
->where('tenant_code', $tenant->codigo)
->where('nombre', 'Entradas')
->sole();
CatalogItem::query()->each(function (CatalogItem $entry) use ($tenant, $entryCategory): void {
$this->assertSame($tenant->codigo, $entry->tenant_code); $this->assertSame($tenant->codigo, $entry->tenant_code);
$this->assertSame($entryCategory->id, $entry->category_id);
$this->assertSame('entrada', $entry->event_product_type->value); $this->assertSame('entrada', $entry->event_product_type->value);
$this->assertSame('tracked', $entry->inventory_policy->value); $this->assertSame('tracked', $entry->inventory_policy->value);
$this->assertTrue($entry->has_tickets); $this->assertTrue($entry->has_tickets);

View File

@@ -5,6 +5,7 @@ namespace Tests\Feature\FiestaFutbolInfantil;
use App\Domains\Auth\Models\User; use App\Domains\Auth\Models\User;
use App\Domains\Authorization\Enums\RoleCode; use App\Domains\Authorization\Enums\RoleCode;
use App\Domains\Catalog\Models\Attribute; use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\Category;
use App\Domains\Shared\Enums\FieldType; use App\Domains\Shared\Enums\FieldType;
use App\Domains\Tenant\Models\Tenant; use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType; use App\Domains\Tenant\Models\WebsiteType;
@@ -63,6 +64,11 @@ class FoodControllerTest extends TestCase
'tenant_code' => $tenant->codigo, 'tenant_code' => $tenant->codigo,
'slug' => 'comida', 'slug' => 'comida',
'nombre' => 'Comida', 'nombre' => 'Comida',
'category_id' => Category::query()
->where('tenant_code', $tenant->codigo)
->where('nombre', 'Comidas')
->sole()
->id,
'precio' => 8000, 'precio' => 8000,
]); ]);
} }

View File

@@ -19,7 +19,7 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
{ {
use RefreshDatabase; use RefreshDatabase;
public function test_it_seeds_the_category_free_configurable_catalog(): void public function test_it_seeds_the_configurable_catalog_with_its_categories(): void
{ {
$headerLogo = $this->attachment('header'); $headerLogo = $this->attachment('header');
$footerLogo = $this->attachment('footer'); $footerLogo = $this->attachment('footer');
@@ -44,7 +44,14 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
['color', 'event_date', 'horario', 'servicio', 'talle', 'tipo_alojamiento'], ['color', 'event_date', 'horario', 'servicio', 'talle', 'tipo_alojamiento'],
Attribute::query()->where('tenant_codigo', $tenant->codigo)->orderBy('codigo')->pluck('codigo')->all(), Attribute::query()->where('tenant_codigo', $tenant->codigo)->orderBy('codigo')->pluck('codigo')->all(),
); );
$this->assertSame(0, Category::query()->where('tenant_code', $tenant->codigo)->count()); $this->assertSame(
['Alojamientos', 'Comidas', 'Entradas', 'Merchandising'],
Category::query()
->where('tenant_code', $tenant->codigo)
->orderBy('nombre')
->pluck('nombre')
->all(),
);
$this->assertSame( $this->assertSame(
['abono', 'alojamiento', 'camiseta', 'comida'], ['abono', 'alojamiento', 'camiseta', 'comida'],
CatalogItem::query()->where('tenant_code', $tenant->codigo)->orderBy('slug')->pluck('slug')->all(), CatalogItem::query()->where('tenant_code', $tenant->codigo)->orderBy('slug')->pluck('slug')->all(),
@@ -59,9 +66,24 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
foreach ($expectedVariantCounts as $slug => $count) { foreach ($expectedVariantCounts as $slug => $count) {
$item = CatalogItem::query()->where('tenant_code', $tenant->codigo)->where('slug', $slug)->sole(); $item = CatalogItem::query()->where('tenant_code', $tenant->codigo)->where('slug', $slug)->sole();
$this->assertCount($count, $item->variants); $this->assertCount($count, $item->variants);
$this->assertNull($item->category_id);
} }
$this->assertSame(
[
'abono' => 'Entradas',
'alojamiento' => 'Alojamientos',
'camiseta' => 'Merchandising',
'comida' => 'Comidas',
],
CatalogItem::query()
->where('tenant_code', $tenant->codigo)
->with('category')
->orderBy('slug')
->get()
->mapWithKeys(fn (CatalogItem $item): array => [$item->slug => $item->category?->nombre])
->all(),
);
$abono = CatalogItem::query() $abono = CatalogItem::query()
->where('tenant_code', $tenant->codigo) ->where('tenant_code', $tenant->codigo)
->where('slug', 'abono') ->where('slug', 'abono')