Refactor ticket validity handling and improve tests
- Updated tests for Accommodation, Entry, Food, Merchandise, and Sale controllers to use soft deletes for variants and ensure proper inventory counts. - Enhanced ticket generation logic to resolve validity from soft-deleted catalog sources. - Introduced a new TicketValidityResolver service to manage ticket validity based on event dates and variant definitions. - Removed unnecessary database assertions and improved the clarity of validity checks in tests. - Added comprehensive tests for the new TicketValidityResolver service, ensuring correct handling of event dates and multi-select options. - Cleaned up unused code and assertions in existing tests for better maintainability.
This commit is contained in:
@@ -287,7 +287,7 @@ class BundleCatalogItemTest extends TestCase
|
||||
->assertJsonValidationErrors(['real_stock']);
|
||||
}
|
||||
|
||||
public function test_bundle_components_are_deleted_with_the_bundle(): void
|
||||
public function test_bundle_components_are_preserved_when_the_bundle_is_soft_deleted(): void
|
||||
{
|
||||
$component = $this->createStandardItem('deletion-component', 5);
|
||||
$bundle = $this->createBundle('deletable-bundle', [
|
||||
@@ -295,8 +295,8 @@ class BundleCatalogItemTest extends TestCase
|
||||
]);
|
||||
$this->catalogService->delete($bundle);
|
||||
|
||||
$this->assertDatabaseMissing('catalog_items', ['id' => $bundle->id]);
|
||||
$this->assertDatabaseMissing('bundle_components', [
|
||||
$this->assertSoftDeleted('catalog_items', ['id' => $bundle->id]);
|
||||
$this->assertDatabaseHas('bundle_components', [
|
||||
'bundle_catalog_item_id' => $bundle->id,
|
||||
]);
|
||||
$this->assertDatabaseHas('catalog_items', ['id' => $component->id]);
|
||||
|
||||
@@ -33,7 +33,6 @@ class CatalogSchemaTest extends TestCase
|
||||
{
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'id',
|
||||
'validity_time_id',
|
||||
'tenant_code',
|
||||
'category_id',
|
||||
'brand_id',
|
||||
@@ -46,7 +45,6 @@ class CatalogSchemaTest extends TestCase
|
||||
'inventory_policy',
|
||||
'max_units_per_user',
|
||||
'has_tickets',
|
||||
'ticket_generation_policy',
|
||||
'validity_time_id',
|
||||
], Schema::getColumnListing('catalog_items'));
|
||||
}
|
||||
|
||||
@@ -93,6 +93,89 @@ class CatalogServiceTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function test_it_soft_deletes_an_item_and_its_variants_without_removing_their_sources(): void
|
||||
{
|
||||
$attribute = $this->createAttribute('size');
|
||||
$item = $this->service->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'slug' => 'archived-item',
|
||||
'nombre' => 'Archived item',
|
||||
'precio' => 100,
|
||||
'attribute_codes' => [$attribute->codigo],
|
||||
'variants' => [[
|
||||
'real_stock' => 5,
|
||||
'values' => [$attribute->codigo => 'M'],
|
||||
]],
|
||||
]);
|
||||
$variant = $item->variants->sole();
|
||||
|
||||
$this->service->delete($item);
|
||||
|
||||
$this->assertSoftDeleted('catalog_items', ['id' => $item->id]);
|
||||
$this->assertSoftDeleted('variantes', ['id' => $variant->id]);
|
||||
$this->assertDatabaseHas('inventories', ['id' => $variant->inventory_id]);
|
||||
$this->assertDatabaseHas('variant_values', [
|
||||
'variant_id' => $variant->id,
|
||||
'value' => 'M',
|
||||
]);
|
||||
$this->assertNull(CatalogItem::query()->find($item->id));
|
||||
$this->assertNull(Variant::query()->find($variant->id));
|
||||
$this->assertNotNull(CatalogItem::withTrashed()->find($item->id));
|
||||
$this->assertNotNull(Variant::withTrashed()->find($variant->id));
|
||||
}
|
||||
|
||||
public function test_deleting_the_last_variant_soft_deletes_its_catalog_item(): void
|
||||
{
|
||||
$attribute = $this->createAttribute('size');
|
||||
$item = $this->service->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'slug' => 'last-variant',
|
||||
'nombre' => 'Last variant',
|
||||
'precio' => 100,
|
||||
'attribute_codes' => [$attribute->codigo],
|
||||
'variants' => [[
|
||||
'real_stock' => 5,
|
||||
'values' => [$attribute->codigo => 'M'],
|
||||
]],
|
||||
]);
|
||||
$variant = $item->variants->sole();
|
||||
|
||||
$this->service->deleteVariant($variant);
|
||||
|
||||
$this->assertSoftDeleted('variantes', ['id' => $variant->id]);
|
||||
$this->assertSoftDeleted('catalog_items', ['id' => $item->id]);
|
||||
$this->assertDatabaseHas('inventories', ['id' => $variant->inventory_id]);
|
||||
}
|
||||
|
||||
public function test_deleting_a_variant_keeps_the_item_active_when_an_inherited_price_variant_remains(): void
|
||||
{
|
||||
$attribute = $this->createAttribute('size');
|
||||
$item = $this->service->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'slug' => 'remaining-variant',
|
||||
'nombre' => 'Remaining variant',
|
||||
'precio' => 100,
|
||||
'attribute_codes' => [$attribute->codigo],
|
||||
'variants' => [
|
||||
[
|
||||
'real_stock' => 5,
|
||||
'values' => [$attribute->codigo => 'M'],
|
||||
],
|
||||
[
|
||||
'real_stock' => 5,
|
||||
'values' => [$attribute->codigo => 'L'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$deletedVariant = $item->variants->first();
|
||||
|
||||
$this->service->deleteVariant($deletedVariant);
|
||||
|
||||
$this->assertSoftDeleted('variantes', ['id' => $deletedVariant->id]);
|
||||
$this->assertFalse($item->fresh()->trashed());
|
||||
$this->assertSame(1, $item->variants()->count());
|
||||
}
|
||||
|
||||
public function test_it_can_hide_an_item_attribute_from_the_product_selector(): void
|
||||
{
|
||||
$attribute = $this->createAttribute('internal_type');
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Menu\Models\Menu;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -141,9 +142,10 @@ class AccommodationControllerTest extends TestCase
|
||||
$this->deleteJson("/api/v1/adminapp/tenant/accommodations/{$accommodationId}")
|
||||
->assertNoContent();
|
||||
|
||||
$this->assertDatabaseCount('catalog_items', 0);
|
||||
$this->assertDatabaseCount('variantes', 0);
|
||||
$this->assertDatabaseCount('inventories', 0);
|
||||
$this->assertSame(0, CatalogItem::query()->count());
|
||||
$this->assertSoftDeleted('variantes', ['id' => $accommodationId]);
|
||||
$this->assertSame(0, Variant::query()->count());
|
||||
$this->assertDatabaseCount('inventories', 1);
|
||||
}
|
||||
|
||||
public function test_it_rejects_duplicate_normalized_titles(): void
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Menu\Models\Menu;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -97,7 +98,7 @@ class EntryControllerTest extends TestCase
|
||||
->where('nombre', 'Entradas')
|
||||
->sole();
|
||||
|
||||
CatalogItem::query()->each(function (CatalogItem $entry) use ($tenant, $entryCategory): void {
|
||||
CatalogItem::query()->orderBy('id')->each(function (CatalogItem $entry) use ($tenant, $entryCategory): void {
|
||||
$this->assertSame($tenant->codigo, $entry->tenant_code);
|
||||
$this->assertSame($entryCategory->id, $entry->category_id);
|
||||
$this->assertSame('tracked', $entry->inventory_policy->value);
|
||||
@@ -191,9 +192,10 @@ class EntryControllerTest extends TestCase
|
||||
$this->deleteJson("/api/v1/adminapp/tenant/entries/{$entryId}")
|
||||
->assertNoContent();
|
||||
|
||||
$this->assertDatabaseCount('catalog_items', 0);
|
||||
$this->assertDatabaseCount('variantes', 0);
|
||||
$this->assertDatabaseCount('inventories', 0);
|
||||
$this->assertSoftDeleted('catalog_items', ['id' => $entryId]);
|
||||
$this->assertSame(0, CatalogItem::query()->count());
|
||||
$this->assertSame(0, Variant::query()->count());
|
||||
$this->assertDatabaseCount('inventories', 1);
|
||||
}
|
||||
|
||||
public function test_dates_must_belong_to_the_authenticated_tenant(): void
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Menu\Models\Menu;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -163,15 +164,17 @@ class FoodControllerTest extends TestCase
|
||||
'slug' => 'comida',
|
||||
'precio' => 10000,
|
||||
]);
|
||||
$this->assertDatabaseCount('variantes', 1);
|
||||
$this->assertDatabaseCount('inventories', 1);
|
||||
$this->assertSoftDeleted('variantes', ['id' => $secondId]);
|
||||
$this->assertSame(1, Variant::query()->count());
|
||||
$this->assertDatabaseCount('inventories', 2);
|
||||
|
||||
$this->deleteJson("/api/v1/adminapp/tenant/foods/{$firstId}")
|
||||
->assertNoContent();
|
||||
|
||||
$this->assertDatabaseCount('catalog_items', 0);
|
||||
$this->assertDatabaseCount('variantes', 0);
|
||||
$this->assertDatabaseCount('inventories', 0);
|
||||
$this->assertSoftDeleted('variantes', ['id' => $firstId]);
|
||||
$this->assertSame(0, CatalogItem::query()->count());
|
||||
$this->assertSame(0, Variant::query()->count());
|
||||
$this->assertDatabaseCount('inventories', 2);
|
||||
}
|
||||
|
||||
public function test_it_rejects_duplicate_combinations(): void
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Menu\Models\Menu;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
@@ -164,14 +165,16 @@ class MerchandiseControllerTest extends TestCase
|
||||
'id' => $itemId,
|
||||
'precio' => 15000,
|
||||
]);
|
||||
$this->assertDatabaseCount('variantes', 1);
|
||||
$this->assertSoftDeleted('variantes', ['id' => $firstId]);
|
||||
$this->assertSame(1, Variant::query()->count());
|
||||
|
||||
$this->deleteJson("/api/v1/adminapp/tenant/merchandise/{$secondId}")
|
||||
->assertNoContent();
|
||||
|
||||
$this->assertDatabaseMissing('catalog_items', ['id' => $itemId]);
|
||||
$this->assertDatabaseCount('variantes', 0);
|
||||
$this->assertDatabaseCount('inventories', 0);
|
||||
$this->assertSoftDeleted('catalog_items', ['id' => $itemId]);
|
||||
$this->assertSoftDeleted('variantes', ['id' => $secondId]);
|
||||
$this->assertSame(0, Variant::query()->count());
|
||||
$this->assertDatabaseCount('inventories', 2);
|
||||
}
|
||||
|
||||
public function test_it_rejects_duplicate_color_and_size_combinations(): void
|
||||
|
||||
@@ -161,8 +161,9 @@ class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
||||
$this->assertSame('Entrada', $catalogItem->nombre);
|
||||
$this->assertSame('tracked', $catalogItem->inventory_policy);
|
||||
$this->assertSame(1, $catalogItem->has_tickets);
|
||||
$this->assertSame('one_per_unit', $catalogItem->ticket_generation_policy);
|
||||
$this->assertSame($eventDate->validity_time_id, $catalogItem->validity_time_id);
|
||||
$this->assertDatabaseHas('variant_event_dates', [
|
||||
'event_date_id' => $eventDate->id,
|
||||
]);
|
||||
$this->assertDatabaseHas('catalog_items_attachments', [
|
||||
'catalog_item_id' => $catalogItem->id,
|
||||
'variant_id' => null,
|
||||
|
||||
@@ -167,8 +167,7 @@ class NotificationMailServiceTest extends TestCase
|
||||
$ticket = Ticket::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'ticket' => fake()->uuid(),
|
||||
'name' => 'Entrada general',
|
||||
'description' => 'Entrada general',
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
$service = app(NotificationMailService::class);
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Tests\Feature\Sale;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Purchase\Events\PurchasePaid;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Purchase\Models\PurchaseItem;
|
||||
@@ -97,20 +98,26 @@ class AdminAppSaleControllerTest extends TestCase
|
||||
'status' => Purchase::STATUS_PAID,
|
||||
'total' => '20000.00',
|
||||
]);
|
||||
$catalogItem = CatalogItem::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'slug' => 'abono-general',
|
||||
'nombre' => 'Abono general',
|
||||
'descripcion' => 'Acceso general',
|
||||
'precio' => 20000,
|
||||
'has_tickets' => true,
|
||||
]);
|
||||
$firstTicket = Ticket::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'ticket' => '11111111-1111-4111-8111-111111111111',
|
||||
'name' => 'Abono general',
|
||||
'description' => 'Acceso general',
|
||||
'source_purchase_id' => $purchase->id,
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'user_id' => $admin->id,
|
||||
]);
|
||||
$usedTicket = Ticket::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'ticket' => '22222222-2222-4222-8222-222222222222',
|
||||
'name' => 'Abono general',
|
||||
'description' => 'Acceso general',
|
||||
'source_purchase_id' => $purchase->id,
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'used_at' => now()->subMinute(),
|
||||
'user_id' => $admin->id,
|
||||
]);
|
||||
|
||||
@@ -12,7 +12,6 @@ use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\TicketGenerationPolicy;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use Database\Seeders\AttributeSeeder;
|
||||
@@ -77,12 +76,6 @@ class FiestaFutbolInfantilProductSeederTest extends TestCase
|
||||
->get()
|
||||
->every(fn (CatalogItem $item): bool => $item->has_tickets),
|
||||
);
|
||||
$this->assertTrue(
|
||||
CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->get()
|
||||
->every(fn (CatalogItem $item): bool => $item->ticket_generation_policy === TicketGenerationPolicy::OnePerUnit),
|
||||
);
|
||||
|
||||
$expectedVariantCounts = [
|
||||
'camiseta' => 12,
|
||||
|
||||
@@ -322,8 +322,6 @@ class ScannerTicketControllerTest extends TestCase
|
||||
return Ticket::query()->create(array_merge([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'ticket' => $uuid,
|
||||
'name' => 'Entrada general',
|
||||
'description' => 'Acceso general',
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'user_id' => $this->ticketOwner->id,
|
||||
], $attributes));
|
||||
|
||||
@@ -5,10 +5,11 @@ namespace Tests\Feature\Ticket;
|
||||
use App\Domains\Attachable\Enums\AttachmentType;
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Inventory;
|
||||
use App\Domains\Event\Models\EventDate;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\TestCase;
|
||||
@@ -23,35 +24,52 @@ class TicketControllerTest extends TestCase
|
||||
$user = User::factory()->create();
|
||||
$olderTicket = $this->createTicket($tenant, $user, 'Older ticket');
|
||||
$newerTicket = $this->createTicket($tenant, $user, 'Newer ticket');
|
||||
$validityTimes = collect([
|
||||
ValidityTime::query()->create([
|
||||
'type' => ValidityTimeType::FixedWindow,
|
||||
'fixed_starts_at' => now()->subHour(),
|
||||
'fixed_expires_at' => now()->addHour(),
|
||||
$catalogItem = CatalogItem::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'slug' => 'dated-ticket',
|
||||
'nombre' => 'Dated ticket',
|
||||
'descripcion' => 'Dated ticket',
|
||||
'precio' => 10,
|
||||
'has_tickets' => true,
|
||||
]);
|
||||
$eventDates = collect([
|
||||
EventDate::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'time_start' => now()->subHour()->format('H:i:s'),
|
||||
'time_end' => now()->addHour()->format('H:i:s'),
|
||||
]),
|
||||
ValidityTime::query()->create([
|
||||
'type' => ValidityTimeType::FixedWindow,
|
||||
'fixed_starts_at' => now()->addDay(),
|
||||
'fixed_expires_at' => now()->addDays(2),
|
||||
EventDate::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'date' => now()->addDay()->format('Y-m-d'),
|
||||
'time_start' => '00:00:00',
|
||||
'time_end' => '23:59:59',
|
||||
]),
|
||||
]);
|
||||
$validityTimes->each(function (ValidityTime $validityTime) use ($newerTicket): void {
|
||||
$group = $newerTicket->validityGroups()->create();
|
||||
$group->validityTimes()->attach($validityTime);
|
||||
});
|
||||
$variant = $catalogItem->variants()->create([
|
||||
'inventory_id' => Inventory::query()->create()->id,
|
||||
]);
|
||||
$variant->eventDates()->sync($eventDates->pluck('id'));
|
||||
$newerTicket->update([
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'source_variant_id' => $variant->id,
|
||||
]);
|
||||
$expectedName = 'Dated ticket ('.$eventDates
|
||||
->pluck('date')
|
||||
->map(fn ($date): string => $date->format('d/m/Y'))
|
||||
->implode(', ').')';
|
||||
|
||||
$this->actingAs($user, 'sanctum')
|
||||
->getJson("/api/tenants/{$tenant->codigo}/tickets")
|
||||
->assertOk()
|
||||
->assertJsonCount(2, 'data')
|
||||
->assertJsonPath('data.0.id', $newerTicket->id)
|
||||
->assertJsonPath('data.0.name', 'Newer ticket')
|
||||
->assertJsonPath('data.0.name', $expectedName)
|
||||
->assertJsonPath('data.0.is_valid', true)
|
||||
->assertJsonPath('data.0.is_expired', false)
|
||||
->assertJsonPath('data.0.is_used', false)
|
||||
->assertJsonCount(2, 'data.0.validity_times')
|
||||
->assertJsonCount(2, 'data.0.validity_groups')
|
||||
->assertJsonCount(1, 'data.0.validity_groups.0.validity_times')
|
||||
->assertJsonMissingPath('data.0.validity_times')
|
||||
->assertJsonMissingPath('data.0.validity_groups')
|
||||
->assertJsonMissingPath('data.0.validity_time')
|
||||
->assertJsonPath('data.1.id', $olderTicket->id)
|
||||
->assertJsonMissingPath('meta')
|
||||
@@ -122,11 +140,19 @@ class TicketControllerTest extends TestCase
|
||||
|
||||
private function createTicket(Tenant $tenant, User $user, string $name): Ticket
|
||||
{
|
||||
$catalogItem = CatalogItem::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'slug' => Str::slug($name).'-'.Str::lower(Str::random(8)),
|
||||
'nombre' => $name,
|
||||
'descripcion' => "Description for {$name}",
|
||||
'precio' => 10,
|
||||
'has_tickets' => true,
|
||||
]);
|
||||
|
||||
return Ticket::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'ticket' => (string) Str::uuid(),
|
||||
'name' => $name,
|
||||
'description' => "Description for {$name}",
|
||||
'source_catalog_item_id' => $catalogItem->id,
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ use App\Domains\Catalog\Enums\CatalogItemType;
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Inventory;
|
||||
use App\Domains\Catalog\Services\CatalogService;
|
||||
use App\Domains\Event\Models\EventDate;
|
||||
use App\Domains\Notification\Events\TicketsAvailable;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\TicketGenerationPolicy;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Exceptions\TicketGenerationException;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
@@ -70,8 +70,14 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
$this->assertSame($item->descripcion, $ticket->description);
|
||||
$this->assertSame($item->id, $ticket->source_catalog_item_id);
|
||||
$this->assertNull($ticket->source_variant_id);
|
||||
$this->assertTrue($ticket->validityGroups->isEmpty());
|
||||
$this->assertTrue($ticket->resolvedValidityGroups()->isEmpty());
|
||||
}
|
||||
|
||||
$this->assertDatabaseHas('tickets', [
|
||||
'id' => $tickets->first()->id,
|
||||
'name' => null,
|
||||
'description' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_it_rejects_an_item_without_tickets_enabled(): void
|
||||
@@ -98,6 +104,10 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
'value' => 'black',
|
||||
'label' => 'Negro',
|
||||
]);
|
||||
$color->options()->create([
|
||||
'value' => 'blue',
|
||||
'label' => 'Azul',
|
||||
]);
|
||||
$size = Attribute::query()->create([
|
||||
'tenant_codigo' => $this->tenant->codigo,
|
||||
'codigo' => 'size',
|
||||
@@ -118,17 +128,33 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
]);
|
||||
$variant = $item->variants()->create([
|
||||
'inventory_id' => Inventory::query()->create()->id,
|
||||
'descripcion' => 'Descripción de la variante',
|
||||
]);
|
||||
$variant->definitions()->createMany([
|
||||
['item_attribute_id' => $itemColor->id, 'value' => 'black'],
|
||||
['item_attribute_id' => $itemSize->id, 'value' => 'xl'],
|
||||
]);
|
||||
$colorDefinition = $variant->definitions()
|
||||
->where('item_attribute_id', $itemColor->id)
|
||||
->sole();
|
||||
|
||||
$ticket = $this->service
|
||||
->generate($item, $this->user, 1, $variant->id)
|
||||
->sole();
|
||||
|
||||
$this->assertSame('Shirt (Negro, XL)', $ticket->name);
|
||||
$this->assertSame('Descripción de la variante', $ticket->description);
|
||||
|
||||
$item->update([
|
||||
'nombre' => 'Remera',
|
||||
'descripcion' => 'Descripción actualizada del producto',
|
||||
]);
|
||||
$colorDefinition->update(['value' => 'blue']);
|
||||
$variant->update(['descripcion' => 'Descripción actualizada de la variante']);
|
||||
$ticket = $ticket->fresh();
|
||||
|
||||
$this->assertSame('Remera (Azul, XL)', $ticket->name);
|
||||
$this->assertSame('Descripción actualizada de la variante', $ticket->description);
|
||||
}
|
||||
|
||||
public function test_it_generates_tickets_for_every_bundle_component_and_quantity(): void
|
||||
@@ -273,9 +299,9 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
$tickets = $this->service->generate($item, $this->user, 2, $variant->id);
|
||||
|
||||
$this->assertCount(2, $tickets);
|
||||
$this->assertTrue($tickets->every(fn ($ticket): bool => $ticket->validityGroups->count() === 1));
|
||||
$this->assertTrue($tickets->every(fn ($ticket): bool => $ticket->resolvedValidityGroups()->count() === 1));
|
||||
$this->assertTrue($tickets->every(
|
||||
fn ($ticket): bool => $ticket->validityGroups->sole()->validityTimes
|
||||
fn ($ticket): bool => $ticket->resolvedValidityGroups()->sole()->validityTimes
|
||||
->pluck('id')
|
||||
->sort()
|
||||
->values()
|
||||
@@ -291,7 +317,7 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function test_a_multi_date_variant_generates_one_ticket_for_each_selected_date(): void
|
||||
public function test_it_generates_one_ticket_per_unit_covering_all_selected_dates(): void
|
||||
{
|
||||
$item = $this->createTicketableItem('multi-date-pass');
|
||||
$dates = collect(['2026-08-20', '2026-08-21'])->map(fn (string $date) => EventDate::query()->create([
|
||||
@@ -305,61 +331,27 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
]);
|
||||
$variant->eventDates()->sync($dates->pluck('id'));
|
||||
|
||||
$tickets = $this->service->generate($item, $this->user, 1, $variant->id);
|
||||
$tickets->each->loadMissing('validityGroups.validityTimes');
|
||||
|
||||
$this->assertCount(2, $tickets);
|
||||
$this->assertSame(
|
||||
$dates->pluck('validity_time_id')->all(),
|
||||
$tickets->map(fn ($ticket): int => $ticket->validityGroups->sole()->validityTimes->sole()->id)->all(),
|
||||
);
|
||||
$this->assertSame(
|
||||
['2026-08-20 00:00:00', '2026-08-21 00:00:00'],
|
||||
$tickets->map(fn ($ticket): string => $ticket->validityGroups->sole()->validityTimes->sole()->fixed_starts_at->format('Y-m-d H:i:s'))->all(),
|
||||
);
|
||||
$this->assertSame(
|
||||
['Multi-date-pass (20/08/2026)', 'Multi-date-pass (21/08/2026)'],
|
||||
$tickets->pluck('name')->all(),
|
||||
);
|
||||
$this->assertSame([$variant->id], $tickets->pluck('source_variant_id')->unique()->values()->all());
|
||||
}
|
||||
|
||||
public function test_one_per_unit_policy_generates_one_ticket_covering_all_selected_dates(): void
|
||||
{
|
||||
$item = $this->createTicketableItem('multi-date-pass');
|
||||
$item->update([
|
||||
'ticket_generation_policy' => TicketGenerationPolicy::OnePerUnit,
|
||||
]);
|
||||
$dates = collect(['2026-08-20', '2026-08-21'])->map(fn (string $date) => EventDate::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'date' => $date,
|
||||
'time_start' => '00:00:00',
|
||||
'time_end' => '23:59:59',
|
||||
]));
|
||||
$variant = $item->variants()->create([
|
||||
'inventory_id' => Inventory::query()->create()->id,
|
||||
]);
|
||||
$variant->eventDates()->sync($dates->pluck('id'));
|
||||
|
||||
$tickets = $this->service->generate($item, $this->user, 2, $variant->id);
|
||||
$tickets->each->loadMissing('validityGroups.validityTimes');
|
||||
|
||||
$this->assertCount(2, $tickets);
|
||||
$this->assertTrue($tickets->every(fn ($ticket): bool => $ticket->validityGroups->count() === 2));
|
||||
$this->assertTrue($tickets->every(fn ($ticket): bool => $ticket->resolvedValidityGroups()->count() === 2));
|
||||
$this->assertTrue($tickets->every(
|
||||
fn ($ticket): bool => $ticket->validityGroups->every(
|
||||
fn ($ticket): bool => $ticket->resolvedValidityGroups()->every(
|
||||
fn ($group): bool => $group->validityTimes->count() === 1
|
||||
)
|
||||
));
|
||||
$this->assertEqualsCanonicalizing(
|
||||
$dates->pluck('validity_time_id')->all(),
|
||||
$tickets->flatMap(fn ($ticket) => $ticket->allValidityTimes())->pluck('id')->unique()->all(),
|
||||
$tickets->flatMap(
|
||||
fn ($ticket) => $ticket->resolvedValidityGroups()
|
||||
->flatMap(fn ($group) => $group->validityTimes)
|
||||
)->pluck('id')->unique()->all(),
|
||||
);
|
||||
$this->assertTrue($tickets->every(
|
||||
fn ($ticket): bool => $ticket->name === 'Multi-date-pass (20/08/2026, 21/08/2026)'
|
||||
));
|
||||
$this->assertTrue($tickets->every(
|
||||
fn ($ticket): bool => $ticket->allValidityTimes()
|
||||
fn ($ticket): bool => $ticket->resolvedValidityGroups()
|
||||
->flatMap(fn ($group) => $group->validityTimes)
|
||||
->map(fn (ValidityTime $validityTime): array => [
|
||||
$validityTime->fixed_starts_at->format('Y-m-d H:i:s'),
|
||||
$validityTime->fixed_expires_at->format('Y-m-d H:i:s'),
|
||||
@@ -371,10 +363,36 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
));
|
||||
}
|
||||
|
||||
public function test_ticket_validity_is_resolved_from_soft_deleted_catalog_sources(): void
|
||||
{
|
||||
$item = $this->createTicketableItem('archived-ticket-source');
|
||||
$eventDate = EventDate::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'date' => '2026-07-21',
|
||||
'time_start' => '00:00:00',
|
||||
'time_end' => '23:59:59',
|
||||
]);
|
||||
$variant = $item->variants()->create([
|
||||
'inventory_id' => Inventory::query()->create()->id,
|
||||
]);
|
||||
$variant->eventDates()->attach($eventDate);
|
||||
$ticket = $this->service->generate($item, $this->user, 1, $variant->id)->sole();
|
||||
|
||||
app(CatalogService::class)->delete($item);
|
||||
$ticket = $ticket->fresh();
|
||||
|
||||
$this->assertTrue($ticket->sourceCatalogItem->trashed());
|
||||
$this->assertTrue($ticket->sourceVariant->trashed());
|
||||
$this->assertTrue($ticket->isValid());
|
||||
$this->assertSame(
|
||||
'2026-07-21 23:59:59',
|
||||
$ticket->getEffectiveExpiresAt()->format('Y-m-d H:i:s'),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_common_schedule_is_anded_into_each_alternative_event_date_group(): void
|
||||
{
|
||||
$item = $this->createTicketableItem('multi-date-lunch');
|
||||
$item->update(['ticket_generation_policy' => TicketGenerationPolicy::OnePerUnit]);
|
||||
$dates = collect(['2026-08-20', '2026-08-21'])->map(fn (string $date) => EventDate::query()->create([
|
||||
'tenant_code' => $this->tenant->codigo,
|
||||
'date' => $date,
|
||||
@@ -408,16 +426,14 @@ class TicketGeneratorServiceTest extends TestCase
|
||||
]);
|
||||
|
||||
$ticket = $this->service->generate($item, $this->user, 1, $variant->id)->sole();
|
||||
$ticket->loadMissing('validityGroups.validityTimes');
|
||||
|
||||
$this->assertCount(2, $ticket->validityGroups);
|
||||
$this->assertTrue($ticket->validityGroups->every(
|
||||
$this->assertCount(2, $ticket->resolvedValidityGroups());
|
||||
$this->assertTrue($ticket->resolvedValidityGroups()->every(
|
||||
fn ($group): bool => $group->validityTimes->count() === 2
|
||||
&& $group->validityTimes->contains($lunch)
|
||||
));
|
||||
$this->assertEqualsCanonicalizing(
|
||||
$dates->pluck('validity_time_id')->all(),
|
||||
$ticket->validityGroups
|
||||
$ticket->resolvedValidityGroups()
|
||||
->flatMap->validityTimes
|
||||
->reject(fn (ValidityTime $validityTime): bool => $validityTime->is($lunch))
|
||||
->pluck('id')
|
||||
|
||||
@@ -25,25 +25,20 @@ class TicketValiditySchemaTest extends TestCase
|
||||
|
||||
$this->assertFalse(Schema::hasColumn('tickets', 'validity_time_id'));
|
||||
$this->assertFalse(Schema::hasTable('ticket_validity_times'));
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'id',
|
||||
'ticket_id',
|
||||
], Schema::getColumnListing('ticket_validity_groups'));
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'ticket_validity_group_id',
|
||||
'validity_time_id',
|
||||
], Schema::getColumnListing('ticket_validity_group_times'));
|
||||
$this->assertFalse(Schema::hasTable('ticket_validity_groups'));
|
||||
$this->assertFalse(Schema::hasTable('ticket_validity_group_times'));
|
||||
$this->assertFalse(Schema::hasColumn('tickets', 'service_date'));
|
||||
$this->assertFalse(Schema::hasColumn('tickets', 'starts_at'));
|
||||
$this->assertFalse(Schema::hasColumn('tickets', 'expires_at'));
|
||||
|
||||
$this->assertTrue(Schema::hasColumn('catalog_items', 'validity_time_id'));
|
||||
$this->assertFalse(Schema::hasColumn('catalog_items', 'validity_time_id'));
|
||||
$this->assertFalse(Schema::hasColumn('catalog_items', 'minimum_use_date'));
|
||||
$this->assertFalse(Schema::hasColumn('catalog_items', 'maximum_use_date'));
|
||||
$this->assertTrue(Schema::hasColumn('catalog_items', 'deleted_at'));
|
||||
$this->assertTrue(Schema::hasColumn('attribute_options', 'validity_time_id'));
|
||||
$this->assertTrue(Schema::hasColumn('event_dates', 'validity_time_id'));
|
||||
$this->assertFalse(Schema::hasColumn('variantes', 'minimum_use_date'));
|
||||
$this->assertFalse(Schema::hasColumn('variantes', 'maximum_use_date'));
|
||||
|
||||
$this->assertTrue(Schema::hasColumn('variantes', 'deleted_at'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Models\TicketValidityGroup;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
use App\Domains\Ticket\Services\ResolvedTicketValidity;
|
||||
use App\Domains\Ticket\Services\ResolvedValidityGroup;
|
||||
use App\Domains\Ticket\Services\TicketValidityResolver;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
@@ -46,8 +47,6 @@ class TicketTest extends TestCase
|
||||
$this->assertInstanceOf(User::class, $ticket->scannerUser()->getRelated());
|
||||
$this->assertInstanceOf(CatalogItem::class, $ticket->sourceCatalogItem()->getRelated());
|
||||
$this->assertInstanceOf(Variant::class, $ticket->sourceVariant()->getRelated());
|
||||
$this->assertInstanceOf(TicketValidityGroup::class, $ticket->validityGroups()->getRelated());
|
||||
$this->assertInstanceOf(ValidityTime::class, (new TicketValidityGroup)->validityTimes()->getRelated());
|
||||
}
|
||||
|
||||
public function test_unused_ticket_without_validity_time_is_valid(): void
|
||||
@@ -190,13 +189,23 @@ class TicketTest extends TestCase
|
||||
private function ticketWithValidityGroups(array $validityGroups): Ticket
|
||||
{
|
||||
$ticket = new Ticket;
|
||||
$groups = collect($validityGroups)->map(function (array $validityTimes): TicketValidityGroup {
|
||||
$group = new TicketValidityGroup;
|
||||
$group->setRelation('validityTimes', new EloquentCollection($validityTimes));
|
||||
$resolved = new ResolvedTicketValidity(
|
||||
collect($validityGroups)->map(
|
||||
fn (array $validityTimes): ResolvedValidityGroup => new ResolvedValidityGroup(collect($validityTimes))
|
||||
)
|
||||
);
|
||||
$this->app->instance(
|
||||
TicketValidityResolver::class,
|
||||
new class($resolved) extends TicketValidityResolver
|
||||
{
|
||||
public function __construct(private readonly ResolvedTicketValidity $resolved) {}
|
||||
|
||||
return $group;
|
||||
});
|
||||
$ticket->setRelation('validityGroups', new EloquentCollection($groups->all()));
|
||||
public function resolveTicket(Ticket $ticket): ResolvedTicketValidity
|
||||
{
|
||||
return $this->resolved;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return $ticket;
|
||||
}
|
||||
|
||||
209
tests/Unit/Ticket/TicketValidityResolverTest.php
Normal file
209
tests/Unit/Ticket/TicketValidityResolverTest.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Ticket;
|
||||
|
||||
use App\Domains\Catalog\Models\Attribute;
|
||||
use App\Domains\Catalog\Models\AttributeOption;
|
||||
use App\Domains\Catalog\Models\ItemAttribute;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Catalog\Models\VariantDefinition;
|
||||
use App\Domains\Event\Models\EventDate;
|
||||
use App\Domains\Shared\Enums\FieldType;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use App\Domains\Ticket\Services\TicketValidityResolver;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TicketValidityResolverTest extends TestCase
|
||||
{
|
||||
private TicketValidityResolver $resolver;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->resolver = new TicketValidityResolver;
|
||||
}
|
||||
|
||||
public function test_event_dates_and_multi_select_options_expand_to_or_groups(): void
|
||||
{
|
||||
$dates = new EloquentCollection([
|
||||
$this->eventDate('2026-08-20'),
|
||||
$this->eventDate('2026-08-21'),
|
||||
]);
|
||||
[$itemAttribute, $definitions] = $this->attributeDimension(
|
||||
allowMultiSelect: true,
|
||||
options: [
|
||||
'Desayuno' => $this->timeWindow('07:00:00', '12:00:00'),
|
||||
'Cena' => $this->timeWindow('20:00:00', '24:00:00'),
|
||||
],
|
||||
);
|
||||
$variant = $this->variant($dates, $definitions);
|
||||
|
||||
$validity = $this->resolver->resolveVariant($variant);
|
||||
|
||||
$this->assertTrue($validity->isResolvable);
|
||||
$this->assertFalse($validity->isUnrestricted);
|
||||
$this->assertCount(4, $validity->groups);
|
||||
$this->assertTrue($validity->groups->every(
|
||||
fn ($group): bool => $group->validityTimes->count() === 2
|
||||
));
|
||||
$this->assertSame($itemAttribute, $definitions->first()->itemAttribute);
|
||||
}
|
||||
|
||||
public function test_different_temporal_attributes_are_anded_in_the_same_group(): void
|
||||
{
|
||||
[, $scheduleDefinitions] = $this->attributeDimension(
|
||||
allowMultiSelect: false,
|
||||
options: ['Almuerzo' => $this->timeWindow('12:00:00', '15:00:00')],
|
||||
);
|
||||
[, $admissionDefinitions] = $this->attributeDimension(
|
||||
allowMultiSelect: false,
|
||||
options: ['Ingreso' => $this->timeWindow('11:00:00', '14:00:00')],
|
||||
);
|
||||
$variant = $this->variant(
|
||||
new EloquentCollection([$this->eventDate('2026-08-20')]),
|
||||
new EloquentCollection([
|
||||
...$scheduleDefinitions,
|
||||
...$admissionDefinitions,
|
||||
]),
|
||||
);
|
||||
|
||||
$validity = $this->resolver->resolveVariant($variant);
|
||||
|
||||
$this->assertCount(1, $validity->groups);
|
||||
$this->assertCount(3, $validity->groups->sole()->validityTimes);
|
||||
$this->assertSame(
|
||||
'2026-08-20 12:00:00',
|
||||
$validity->effectiveStartsAt(Carbon::parse('2026-08-20 13:00:00'))->format('Y-m-d H:i:s'),
|
||||
);
|
||||
$this->assertSame(
|
||||
'2026-08-20 14:00:00',
|
||||
$validity->effectiveExpiresAt(Carbon::parse('2026-08-20 13:00:00'))->format('Y-m-d H:i:s'),
|
||||
);
|
||||
$this->assertTrue($validity->isValid(Carbon::parse('2026-08-20 13:00:00')));
|
||||
$this->assertFalse($validity->isValid(Carbon::parse('2026-08-20 14:00:00')));
|
||||
}
|
||||
|
||||
public function test_variant_without_temporal_dimensions_is_unrestricted(): void
|
||||
{
|
||||
$validity = $this->resolver->resolveVariant(
|
||||
$this->variant(new EloquentCollection, new EloquentCollection)
|
||||
);
|
||||
|
||||
$this->assertTrue($validity->isResolvable);
|
||||
$this->assertTrue($validity->isUnrestricted);
|
||||
$this->assertTrue($validity->isValid());
|
||||
$this->assertFalse($validity->isExpired());
|
||||
}
|
||||
|
||||
public function test_non_option_attributes_do_not_affect_validity(): void
|
||||
{
|
||||
$attribute = new Attribute(['type' => FieldType::String]);
|
||||
$attribute->setRelation('options', new EloquentCollection);
|
||||
$itemAttribute = new ItemAttribute(['allow_multi_select' => false]);
|
||||
$itemAttribute->setRelation('attribute', $attribute);
|
||||
$definition = new VariantDefinition(['value' => 'Comedor principal']);
|
||||
$definition->setAttribute('item_attribute_id', 123);
|
||||
$definition->setRelation('itemAttribute', $itemAttribute);
|
||||
|
||||
$validity = $this->resolver->resolveVariant(
|
||||
$this->variant(new EloquentCollection, new EloquentCollection([$definition]))
|
||||
);
|
||||
|
||||
$this->assertTrue($validity->isResolvable);
|
||||
$this->assertTrue($validity->isUnrestricted);
|
||||
}
|
||||
|
||||
public function test_multiple_values_for_a_single_select_attribute_are_unresolvable(): void
|
||||
{
|
||||
[, $definitions] = $this->attributeDimension(
|
||||
allowMultiSelect: false,
|
||||
options: [
|
||||
'Desayuno' => $this->timeWindow('07:00:00', '12:00:00'),
|
||||
'Cena' => $this->timeWindow('20:00:00', '24:00:00'),
|
||||
],
|
||||
);
|
||||
|
||||
$validity = $this->resolver->resolveVariant(
|
||||
$this->variant(new EloquentCollection, $definitions)
|
||||
);
|
||||
|
||||
$this->assertFalse($validity->isResolvable);
|
||||
$this->assertFalse($validity->isValid());
|
||||
}
|
||||
|
||||
private function eventDate(string $date): EventDate
|
||||
{
|
||||
$validityTime = new ValidityTime([
|
||||
'type' => ValidityTimeType::FixedWindow,
|
||||
'fixed_starts_at' => "{$date} 00:00:00",
|
||||
'fixed_expires_at' => "{$date} 23:59:59",
|
||||
]);
|
||||
$eventDate = new EventDate([
|
||||
'date' => $date,
|
||||
'time_start' => '00:00:00',
|
||||
'time_end' => '23:59:59',
|
||||
]);
|
||||
$eventDate->setRelation('validityTime', $validityTime);
|
||||
|
||||
return $eventDate;
|
||||
}
|
||||
|
||||
private function timeWindow(string $start, string $end): ValidityTime
|
||||
{
|
||||
return new ValidityTime([
|
||||
'type' => ValidityTimeType::TimeWindow,
|
||||
'start_time' => $start,
|
||||
'end_time' => $end,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ValidityTime|null> $options
|
||||
* @return array{ItemAttribute, EloquentCollection<int, VariantDefinition>}
|
||||
*/
|
||||
private function attributeDimension(bool $allowMultiSelect, array $options): array
|
||||
{
|
||||
$attribute = new Attribute([
|
||||
'type' => FieldType::Select,
|
||||
]);
|
||||
$attributeOptions = collect($options)->map(
|
||||
function (?ValidityTime $validityTime, string $value): AttributeOption {
|
||||
$option = new AttributeOption(['value' => $value, 'label' => $value]);
|
||||
$option->setRelation('validityTime', $validityTime);
|
||||
|
||||
return $option;
|
||||
}
|
||||
);
|
||||
$attribute->setRelation('options', new EloquentCollection($attributeOptions));
|
||||
|
||||
$itemAttribute = new ItemAttribute(['allow_multi_select' => $allowMultiSelect]);
|
||||
$itemAttribute->setRelation('attribute', $attribute);
|
||||
$definitions = $attributeOptions->map(function (AttributeOption $option) use ($itemAttribute): VariantDefinition {
|
||||
$definition = new VariantDefinition(['value' => $option->value]);
|
||||
$definition->setAttribute('item_attribute_id', spl_object_id($itemAttribute));
|
||||
$definition->setRelation('itemAttribute', $itemAttribute);
|
||||
|
||||
return $definition;
|
||||
});
|
||||
|
||||
return [$itemAttribute, new EloquentCollection($definitions)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EloquentCollection<int, EventDate> $eventDates
|
||||
* @param EloquentCollection<int, VariantDefinition> $definitions
|
||||
*/
|
||||
private function variant(EloquentCollection $eventDates, EloquentCollection $definitions): Variant
|
||||
{
|
||||
$variant = new Variant;
|
||||
$variant->setRelation('eventDates', $eventDates);
|
||||
$variant->setRelation('eventDate', null);
|
||||
$variant->setRelation('definitions', $definitions);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
namespace Tests\Unit\Ticket;
|
||||
|
||||
use App\Domains\Catalog\Models\AttributeOption;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\TicketValidityGroup;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
@@ -24,12 +22,7 @@ class ValidityTimeTest extends TestCase
|
||||
$this->assertSame(ValidityTimeType::FixedWindow, $validityTime->type);
|
||||
$this->assertInstanceOf(Carbon::class, $validityTime->fixed_starts_at);
|
||||
$this->assertInstanceOf(Carbon::class, $validityTime->fixed_expires_at);
|
||||
$this->assertInstanceOf(CatalogItem::class, $validityTime->catalogItems()->getRelated());
|
||||
$this->assertInstanceOf(AttributeOption::class, $validityTime->attributeOptions()->getRelated());
|
||||
$this->assertInstanceOf(
|
||||
TicketValidityGroup::class,
|
||||
$validityTime->ticketValidityGroups()->getRelated(),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_it_exposes_supported_type_values(): void
|
||||
|
||||
Reference in New Issue
Block a user