feat(tickets): refine FFI variant filters
This commit is contained in:
@@ -102,17 +102,25 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
->assertJsonPath('data.fields.2.name', 'type')
|
||||
->assertJsonPath('data.fields.2.query_param', 'type')
|
||||
->assertJsonPath('data.fields.2.depends_on', 'product')
|
||||
->assertJsonPath('data.fields.3.name', 'date')
|
||||
->assertJsonPath('data.fields.3.query_param', 'date')
|
||||
->assertJsonPath('data.fields.4.name', 'status')
|
||||
->assertJsonPath('data.fields.4.query_param', 'status')
|
||||
->assertJsonPath('data.fields.3.name', 'size')
|
||||
->assertJsonPath('data.fields.3.query_param', 'size')
|
||||
->assertJsonPath('data.fields.3.depends_on', 'type')
|
||||
->assertJsonPath('data.fields.4.name', 'date')
|
||||
->assertJsonPath('data.fields.4.query_param', 'date')
|
||||
->assertJsonPath('data.fields.4.depends_on', 'category')
|
||||
->assertJsonPath('data.fields.5.name', 'status')
|
||||
->assertJsonPath('data.fields.5.query_param', 'status')
|
||||
->assertJsonPath('data.columns.0.key', 'order_number')
|
||||
->assertJsonPath('data.columns.0.sort_param', 'order_number')
|
||||
->assertJsonPath('data.columns.1.key', 'category')
|
||||
->assertJsonPath('data.columns.2.key', 'product')
|
||||
->assertJsonPath('data.columns.2.sortable', false)
|
||||
->assertJsonPath('data.columns.3.key', 'type')
|
||||
->assertJsonPath('data.columns.3.sortable', false);
|
||||
->assertJsonPath('data.columns.3.sortable', false)
|
||||
->assertJsonPath('data.columns.4.key', 'date')
|
||||
->assertJsonPath('data.columns.4.sortable', false)
|
||||
->assertJsonPath('data.columns.5.key', 'size')
|
||||
->assertJsonPath('data.columns.5.sortable', false);
|
||||
|
||||
$categories = collect($response->json('data.fields.0.options'));
|
||||
$this->assertSame(
|
||||
@@ -121,22 +129,63 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
);
|
||||
|
||||
$entries = $categories->firstWhere('value', 'entradas');
|
||||
$this->assertSame('Abono', $entries['children']['options'][0]['label']);
|
||||
$this->assertTrue($entries['children']['options'][0]['children']['disabled']);
|
||||
$this->assertSame('Abono', $entries['children'][0]['options'][0]['label']);
|
||||
$this->assertTrue($entries['children'][0]['options'][0]['children'][0]['disabled']);
|
||||
$this->assertTrue($entries['children'][1]['disabled']);
|
||||
|
||||
$camping = $categories->firstWhere('value', 'alojamientos');
|
||||
$this->assertSame(
|
||||
['Carpa', 'Motorhome'],
|
||||
collect($camping['children']['options'])->pluck('label')->all(),
|
||||
collect($camping['children'][0]['options'])->pluck('label')->all(),
|
||||
);
|
||||
$this->assertTrue($camping['children']['options'][0]['children']['disabled']);
|
||||
$this->assertTrue($camping['children'][0]['options'][0]['children'][0]['disabled']);
|
||||
|
||||
$merchandise = $categories->firstWhere('value', 'merchandising');
|
||||
$this->assertSame('Camiseta', $merchandise['children']['options'][0]['label']);
|
||||
$merchandiseProduct = $merchandise['children'][0]['options'][0];
|
||||
$this->assertSame('Camiseta', $merchandiseProduct['label']);
|
||||
$this->assertSame(
|
||||
['Verde', 'Blanco'],
|
||||
collect($merchandise['children']['options'][0]['children']['options'])->pluck('label')->all(),
|
||||
collect($merchandiseProduct['children'][0]['options'])->pluck('label')->all(),
|
||||
);
|
||||
$this->assertSame(
|
||||
['14', 'S', 'M', 'L', 'XL', 'XXL'],
|
||||
collect($merchandiseProduct['children'][0]['options'][0]['children'][0]['options'])
|
||||
->pluck('label')
|
||||
->all(),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_merchandise_sizes_are_scoped_to_the_selected_product_and_color(): void
|
||||
{
|
||||
$tenant = $this->createFiestaFutbolInfantilTenant();
|
||||
$this->grantTicketsMenu($tenant);
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$merchandise = CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->where('slug', 'camiseta')
|
||||
->with([
|
||||
'itemAttributes.attribute.options',
|
||||
'variants.definitions.itemAttribute.attribute.options',
|
||||
])
|
||||
->firstOrFail();
|
||||
$whiteXxl = $merchandise->variants->first(fn ($variant): bool => $variant->selectionValues()->get('color') === 'Blanco'
|
||||
&& $variant->selectionValues()->get('talle') === 'XXL');
|
||||
$this->assertNotNull($whiteXxl);
|
||||
app(CatalogService::class)->deleteVariant($whiteXxl);
|
||||
|
||||
$response = $this->getJson('/api/v1/adminapp/forms/tickets-filter')->assertOk();
|
||||
$merchandiseCategory = collect($response->json('data.fields.0.options'))
|
||||
->firstWhere('value', 'merchandising');
|
||||
$product = $merchandiseCategory['children'][0]['options'][0];
|
||||
$colors = collect($product['children'][0]['options']);
|
||||
$greenSizes = collect($colors->firstWhere('value', 'Verde')['children'][0]['options'])
|
||||
->pluck('value');
|
||||
$whiteSizes = collect($colors->firstWhere('value', 'Blanco')['children'][0]['options'])
|
||||
->pluck('value');
|
||||
|
||||
$this->assertContains('XXL', $greenSizes);
|
||||
$this->assertNotContains('XXL', $whiteSizes);
|
||||
}
|
||||
|
||||
public function test_a_food_schedule_is_only_returned_when_a_variant_exists_for_the_date(): void
|
||||
@@ -145,7 +194,6 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
$this->grantTicketsMenu($tenant);
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$date = $tenant->eventDates()->orderByDesc('date')->firstOrFail();
|
||||
$food = CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->where('slug', 'comida')
|
||||
@@ -158,15 +206,12 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
->firstOrFail();
|
||||
|
||||
$food->variants
|
||||
->filter(fn ($variant): bool => $variant->selectedEventDates()->contains('id', $date->id)
|
||||
&& $variant->selectionValues()->get('horario') === 'Almuerzo')
|
||||
->filter(fn ($variant): bool => $variant->selectionValues()->get('horario') === 'Almuerzo')
|
||||
->each->delete();
|
||||
|
||||
$response = $this->getJson('/api/v1/adminapp/forms/tickets-filter')->assertOk();
|
||||
$foodCategory = collect($response->json('data.fields.0.options'))->firstWhere('value', 'comidas');
|
||||
$dateProduct = collect($foodCategory['children']['options'])
|
||||
->firstWhere('value', (string) $date->id);
|
||||
$schedules = collect($dateProduct['children']['options'])->pluck('value');
|
||||
$schedules = collect($foodCategory['children'][0]['options'])->pluck('value');
|
||||
|
||||
$this->assertNotContains('Almuerzo', $schedules);
|
||||
$this->assertContains('Desayuno', $schedules);
|
||||
@@ -195,6 +240,7 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
&& $variant->selectionValues()->get('horario') === 'Cena';
|
||||
});
|
||||
$this->assertNotNull($historicalVariant);
|
||||
$historicalService = $historicalVariant->selectionValues()->get('servicio');
|
||||
|
||||
$ticket = Ticket::query()->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
@@ -213,26 +259,29 @@ class AdminAppTicketFilterFormControllerTest extends TestCase
|
||||
|
||||
$response = $this->getJson('/api/v1/adminapp/forms/tickets-filter')->assertOk();
|
||||
$foodCategory = collect($response->json('data.fields.0.options'))->firstWhere('value', 'comidas');
|
||||
$products = collect($foodCategory['children']['options']);
|
||||
$products = collect($foodCategory['children'][0]['options']);
|
||||
|
||||
$this->assertCount(1, $products);
|
||||
$this->assertSame('12/10', $products->first()['label']);
|
||||
$this->assertSame('Cena', $products->first()['label']);
|
||||
$this->assertSame(
|
||||
['Cena'],
|
||||
collect($products->first()['children']['options'])->pluck('label')->all(),
|
||||
[$historicalService],
|
||||
collect($products->first()['children'][0]['options'])->pluck('label')->all(),
|
||||
);
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets?'.http_build_query([
|
||||
'category' => 'comidas',
|
||||
'product' => $products->first()['value'],
|
||||
'type' => 'Cena',
|
||||
'type' => $historicalService,
|
||||
'date' => '2026-10-12',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.id', $ticket->id)
|
||||
->assertJsonPath('data.0.values.category', 'Comida')
|
||||
->assertJsonPath('data.0.values.product', '12/10')
|
||||
->assertJsonPath('data.0.values.type', 'Cena');
|
||||
->assertJsonPath('data.0.values.product', 'Cena')
|
||||
->assertJsonPath('data.0.values.type', $historicalService)
|
||||
->assertJsonPath('data.0.values.date', '12/10')
|
||||
->assertJsonPath('data.0.values.size', '-');
|
||||
}
|
||||
|
||||
private function createFiestaFutbolInfantilTenant(): Tenant
|
||||
|
||||
@@ -73,7 +73,8 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
->assertJsonPath('data.0.values.id', $ticket->id)
|
||||
->assertJsonPath('data.0.values.status', Ticket::STATUS_ACTIVE)
|
||||
->assertJsonMissingPath('data.0.values.ticket')
|
||||
->assertJsonMissingPath('data.0.values.date')
|
||||
->assertJsonPath('data.0.values.date', '-')
|
||||
->assertJsonPath('data.0.values.size', '-')
|
||||
->assertJsonMissingPath('data.0.date')
|
||||
->assertJsonPath('meta.total', 1);
|
||||
}
|
||||
@@ -278,6 +279,13 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
&& $variant->selectionValues()->get('horario') === 'Almuerzo');
|
||||
$this->assertNotNull($dinner);
|
||||
$this->assertNotNull($lunch);
|
||||
$dinnerService = $dinner->selectionValues()->get('servicio');
|
||||
$otherDate = $tenant->eventDates()->where('id', '!=', $date->id)->firstOrFail();
|
||||
$otherDinner = $food->variants->first(fn (Variant $variant): bool => $variant
|
||||
->selectedEventDates()->contains('id', $otherDate->id)
|
||||
&& $variant->selectionValues()->get('horario') === 'Cena'
|
||||
&& $variant->selectionValues()->get('servicio') === $dinnerService);
|
||||
$this->assertNotNull($otherDinner);
|
||||
|
||||
$matchingPurchase = $this->createPurchase($tenant, $admin, '2026-08-20 10:00:00');
|
||||
$otherPurchase = $this->createPurchase($tenant, $admin, '2026-08-21 10:00:00');
|
||||
@@ -296,24 +304,75 @@ class AdminAppTicketControllerTest extends TestCase
|
||||
$this->createTicket($tenant, $admin, [
|
||||
'source_purchase_id' => $otherPurchase->id,
|
||||
'source_catalog_item_id' => $food->id,
|
||||
'source_variant_id' => $dinner->id,
|
||||
'source_variant_id' => $otherDinner->id,
|
||||
'used_at' => now(),
|
||||
]);
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets?'.http_build_query([
|
||||
'category' => 'comidas',
|
||||
'product' => (string) $date->id,
|
||||
'type' => 'Cena',
|
||||
'date' => '2026-08-20',
|
||||
'product' => 'Cena',
|
||||
'type' => $dinnerService,
|
||||
'date' => $date->date->format('Y-m-d'),
|
||||
'status' => Ticket::STATUS_USED,
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.id', $matching->id)
|
||||
->assertJsonPath('data.0.values.product', 'Cena')
|
||||
->assertJsonPath('data.0.values.type', $dinnerService)
|
||||
->assertJsonPath('data.0.values.date', $date->date->format('d/m'))
|
||||
->assertJsonPath('scanned_tickets', 1)
|
||||
->assertJsonPath('total_tickets', 1);
|
||||
}
|
||||
|
||||
public function test_it_exposes_and_filters_merchandise_color_and_size(): void
|
||||
{
|
||||
$tenant = $this->createTenant('fiesta_futbol_infantil');
|
||||
$admin = $this->createAdminAppUser($tenant);
|
||||
$this->grantTicketsMenu($tenant);
|
||||
$this->seed([AttributeSeeder::class, FiestaFutbolInfantilProductSeeder::class]);
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$merchandise = CatalogItem::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->where('slug', 'camiseta')
|
||||
->with([
|
||||
'variants.definitions.itemAttribute.attribute.options',
|
||||
'variants.eventDates',
|
||||
'variants.eventDate',
|
||||
])
|
||||
->firstOrFail();
|
||||
$greenMedium = $merchandise->variants->first(fn (Variant $variant): bool => $variant->selectionValues()->get('color') === 'Verde'
|
||||
&& $variant->selectionValues()->get('talle') === 'M');
|
||||
$whiteMedium = $merchandise->variants->first(fn (Variant $variant): bool => $variant->selectionValues()->get('color') === 'Blanco'
|
||||
&& $variant->selectionValues()->get('talle') === 'M');
|
||||
$this->assertNotNull($greenMedium);
|
||||
$this->assertNotNull($whiteMedium);
|
||||
|
||||
$matching = $this->createTicket($tenant, $admin, [
|
||||
'source_catalog_item_id' => $merchandise->id,
|
||||
'source_variant_id' => $greenMedium->id,
|
||||
]);
|
||||
$this->createTicket($tenant, $admin, [
|
||||
'source_catalog_item_id' => $merchandise->id,
|
||||
'source_variant_id' => $whiteMedium->id,
|
||||
]);
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/tickets?'.http_build_query([
|
||||
'category' => 'merchandising',
|
||||
'product' => 'camiseta',
|
||||
'type' => 'Verde',
|
||||
'size' => 'M',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.id', $matching->id)
|
||||
->assertJsonPath('data.0.values.product', 'Camiseta')
|
||||
->assertJsonPath('data.0.values.type', 'Verde')
|
||||
->assertJsonPath('data.0.values.date', '-')
|
||||
->assertJsonPath('data.0.values.size', 'M');
|
||||
}
|
||||
|
||||
public function test_it_filters_computed_active_and_expired_statuses(): void
|
||||
{
|
||||
$tenant = $this->createTenant('fiesta_futbol_infantil');
|
||||
|
||||
Reference in New Issue
Block a user