feat: Add event management to tenant and catalog

- Introduced Event and EventDate models with relationships to Tenant and CatalogItem.
- Added active_event_id to Tenant model to track the currently active event.
- Updated TenantResource to include active event details in the response.
- Enhanced Ticket model to link to CatalogItem and Variant, allowing for event-specific ticketing.
- Implemented migrations to create events and link them to catalog items and variants.
- Updated seeders to populate events and their associated dates for the Fiesta Futbol Infantil tenant.
- Modified Ticket generation logic to respect event dates over standard ticket dates.
- Added tests for event and ticket functionalities, ensuring proper relationships and date handling.
This commit is contained in:
2026-08-03 12:01:20 -03:00
parent 4a51f3afde
commit c3713c62a6
30 changed files with 736 additions and 107 deletions

View File

@@ -32,6 +32,8 @@ class CatalogSchemaTest extends TestCase
$this->assertEqualsCanonicalizing([
'id',
'tenant_code',
'event_id',
'event_product_type',
'category_id',
'brand_id',
'inventory_id',
@@ -178,8 +180,27 @@ class CatalogSchemaTest extends TestCase
public function test_variants_can_override_catalog_item_use_dates(): void
{
$this->assertTrue(Schema::hasColumns('variantes', [
'event_date_id',
'minimum_use_date',
'maximum_use_date',
]));
}
public function test_events_and_event_dates_are_linked_to_the_catalog(): void
{
$this->assertEqualsCanonicalizing([
'id',
'tenant_code',
'name',
'address',
], Schema::getColumnListing('events'));
$this->assertEqualsCanonicalizing([
'id',
'event_id',
'date',
'time_start',
'time_end',
], Schema::getColumnListing('event_dates'));
$this->assertTrue(Schema::hasColumn('tenants', 'active_event_id'));
}
}

View File

@@ -5,6 +5,7 @@ namespace Tests\Feature\Seeders;
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\GroupLayout;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\Attribute;
@@ -12,6 +13,8 @@ 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\Event\Models\Event;
use App\Domains\Event\Models\EventDate;
use App\Domains\Tenant\Models\Tenant;
use Database\Seeders\AttributeSeeder;
use Database\Seeders\FiestaFutbolInfantilProductSeeder;
@@ -62,24 +65,34 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
$this->assertFalse(Attribute::query()
->where('tenant_codigo', $tenant->codigo)
->whereIn('codigo', ['color', 'talle', 'talle_numerico'])
->exists());
$this->assertSame(
['fecha'],
Attribute::query()->where('tenant_codigo', $tenant->codigo)->pluck('codigo')->all()
);
$event = Event::query()
->where('tenant_code', $tenant->codigo)
->with('dates')
->sole();
$this->assertSame($event->id, $tenant->fresh()->active_event_id);
$this->assertCount(4, $event->dates);
$this->assertSame(1, Event::query()->where('tenant_code', $tenant->codigo)->count());
$this->assertSame(4, EventDate::query()->where('event_id', $event->id)->count());
$generalAdmission = CatalogItem::query()
->where('tenant_code', $tenant->codigo)
->where('slug', 'entrada-general')
->with('variants.definitions')
->with('variants.eventDate', 'itemAttributes')
->sole();
$this->assertNull($generalAdmission->inventory_id);
$this->assertTrue($generalAdmission->event->is($event));
$this->assertSame(EventProductType::Entry, $generalAdmission->event_product_type);
$this->assertCount(0, $generalAdmission->itemAttributes);
$this->assertCount(4, $generalAdmission->variants);
$this->assertEqualsCanonicalizing(
['2026-10-09', '2026-10-10', '2026-10-11', '2026-10-12'],
$generalAdmission->variants->map(fn ($variant) => $variant->definitions->sole()->value)->all()
$generalAdmission->variants
->map(fn ($variant) => $variant->eventDate->date->format('Y-m-d'))
->all()
);
$this->assertSame(
[
@@ -89,10 +102,10 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
['2026-10-12 00:00:00', '2026-10-12 23:59:59'],
],
$generalAdmission->variants
->sortBy(fn ($variant) => $variant->definitions->sole()->value)
->sortBy(fn ($variant) => $variant->eventDate->date)
->map(fn ($variant): array => [
$variant->minimum_use_date->format('Y-m-d H:i:s'),
$variant->maximum_use_date->format('Y-m-d H:i:s'),
$variant->getMinimumUseDate()->format('Y-m-d H:i:s'),
$variant->getMaximumUseDate()->format('Y-m-d H:i:s'),
])
->values()
->all()
@@ -105,6 +118,7 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
$this->assertCount(7, $standardItems);
foreach ($standardItems as $standardItem) {
$this->assertSame($event->id, $standardItem->event_id);
$this->assertSame(
'2026-10-09 00:00:00',
$standardItem->minimum_use_date->format('Y-m-d H:i:s'),
@@ -118,18 +132,20 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
$allDaysItem = CatalogItem::query()
->where('tenant_code', $tenant->codigo)
->where('nombre', 'Entrada General - Todos los días')
->with('bundleComponents.variant.definitions')
->with('bundleComponents.variant.eventDate')
->sole();
$this->assertSame(CatalogItemType::Bundle, $allDaysItem->type);
$this->assertSame('40000.00', $allDaysItem->precio);
$this->assertNull($allDaysItem->inventory_id);
$this->assertFalse($allDaysItem->has_tickets);
$this->assertSame($event->id, $allDaysItem->event_id);
$this->assertSame(EventProductType::Entry, $allDaysItem->event_product_type);
$this->assertCount(4, $allDaysItem->bundleComponents);
$this->assertEqualsCanonicalizing(
['2026-10-09', '2026-10-10', '2026-10-11', '2026-10-12'],
$allDaysItem->bundleComponents
->map(fn ($component) => $component->variant->definitions->sole()->value)
->map(fn ($component) => $component->variant->eventDate->date->format('Y-m-d'))
->all()
);
@@ -142,6 +158,7 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
$this->assertSame(CatalogItemType::Bundle, $foodCombo->type);
$this->assertSame('24000.00', $foodCombo->precio);
$this->assertNull($foodCombo->inventory_id);
$this->assertSame(EventProductType::Product, $foodCombo->event_product_type);
$this->assertSame(
[
'hamburguesa-papa-frita' => 2,

View File

@@ -128,7 +128,8 @@ class TicketGeneratorServiceTest extends TestCase
$tickets = $this->service->generate($bundle, $this->user, 2);
$this->assertCount(6, $tickets);
$this->assertCount(6, $tickets->where('source_catalog_item_id', $bundle->id));
$this->assertCount(4, $tickets->where('source_catalog_item_id', $first->id));
$this->assertCount(2, $tickets->where('source_catalog_item_id', $second->id));
$this->assertCount(4, $tickets->where('name', $first->nombre));
$this->assertCount(2, $tickets->where('name', $second->nombre));
}
@@ -157,6 +158,8 @@ class TicketGeneratorServiceTest extends TestCase
->generate($bundle, $this->user)
->firstOrFail();
$this->assertSame($component->id, $ticket->source_catalog_item_id);
$this->assertSame($variant->id, $ticket->source_variant_id);
$this->assertTrue($ticket->starts_at->equalTo($variant->minimum_use_date));
$this->assertTrue($ticket->expires_at->equalTo($variant->maximum_use_date));
}