seed(AuthorizationSeeder::class); WebsiteType::query()->create(['codigo' => 'onticket', 'nombre' => 'OnTicket']); } public function test_authentication_is_required(): void { $this->getJson('/api/v1/adminapp/tenant/tickets')->assertUnauthorized(); } public function test_the_tenant_must_have_the_tickets_menu(): void { $tenant = $this->createTenant('fiesta_futbol_infantil'); Sanctum::actingAs($this->createAdminAppUser($tenant)); $this->getJson('/api/v1/adminapp/tenant/tickets')->assertNotFound(); } public function test_it_lists_only_tickets_from_the_authenticated_tenant(): void { $tenant = $this->createTenant('fiesta_futbol_infantil'); $otherTenant = $this->createTenant('other'); $admin = $this->createAdminAppUser($tenant); $otherUser = $this->createAdminAppUser($otherTenant); $this->grantTicketsMenu($tenant); Sanctum::actingAs($admin); $ticket = $this->createTicket($tenant, $admin); $this->createTicket($otherTenant, $otherUser); $this->getJson('/api/v1/adminapp/tenant/tickets') ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.id', $ticket->id) ->assertJsonPath('data.0.tenant_code', $tenant->codigo) ->assertJsonPath('meta.total', 1); } public function test_it_supports_id_and_uuid_search(): void { $tenant = $this->createTenant('fiesta_futbol_infantil'); $admin = $this->createAdminAppUser($tenant); $this->grantTicketsMenu($tenant); Sanctum::actingAs($admin); $matching = $this->createTicket($tenant, $admin); $this->createTicket($tenant, $admin); $this->getJson("/api/v1/adminapp/tenant/tickets?q={$matching->id}") ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.id', $matching->id); $this->getJson('/api/v1/adminapp/tenant/tickets?q='.substr($matching->ticket, 0, 8)) ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.ticket', $matching->ticket); } public function test_it_includes_tenant_scanned_and_total_ticket_counts(): void { $tenant = $this->createTenant('fiesta_futbol_infantil'); $otherTenant = $this->createTenant('other'); $admin = $this->createAdminAppUser($tenant); $otherUser = $this->createAdminAppUser($otherTenant); $this->grantTicketsMenu($tenant); Sanctum::actingAs($admin); $this->createTicket($tenant, $admin)->update(['used_at' => now()]); $this->createTicket($tenant, $admin); $this->createTicket($otherTenant, $otherUser)->update(['used_at' => now()]); $this->getJson('/api/v1/adminapp/tenant/tickets?q=does-not-match') ->assertOk() ->assertJsonCount(0, 'data') ->assertJsonPath('scanned_tickets', 0) ->assertJsonPath('total_tickets', 0); $this->getJson('/api/v1/adminapp/tenant/tickets') ->assertOk() ->assertJsonPath('scanned_tickets', 1) ->assertJsonPath('total_tickets', 2); } public function test_it_returns_structured_variant_properties(): void { $tenant = $this->createTenant('fiesta_futbol_infantil'); $admin = $this->createAdminAppUser($tenant); $this->grantTicketsMenu($tenant); Sanctum::actingAs($admin); $item = CatalogItem::query()->create([ 'tenant_code' => $tenant->codigo, 'slug' => 'remera', 'nombre' => 'Remera', 'precio' => '8000.00', 'has_tickets' => true, ]); $attribute = Attribute::query()->create([ 'tenant_codigo' => $tenant->codigo, 'codigo' => 'size', 'nombre' => 'Talle', 'type' => FieldType::Select, ]); $attribute->options()->create(['value' => 'xl', 'label' => 'XL']); $itemAttribute = $item->itemAttributes()->create([ 'attribute_id' => $attribute->id, 'sort_order' => 1, ]); $variant = Variant::query()->create([ 'catalog_item_id' => $item->id, 'inventory_id' => Inventory::query()->create()->id, ]); $variant->definitions()->create([ 'item_attribute_id' => $itemAttribute->id, 'value' => 'xl', ]); $purchase = Purchase::query()->create([ 'tenant_codigo' => $tenant->codigo, 'user_id' => $admin->id, 'status' => Purchase::STATUS_PAID, 'nombre_apellido' => 'Nombre Apellido', 'total' => '8000.00', ]); PurchaseItem::query()->create([ 'compra_id' => $purchase->id, 'source_catalog_item_id' => $item->id, 'source_variant_id' => $variant->id, 'nombre' => 'Remera', 'descripcion' => '', 'slug' => 'remera', 'item_nombre' => 'Remera', 'cantidad' => 1, 'precio_unitario' => '8000.00', 'total' => '8000.00', ]); $ticket = $this->createTicket($tenant, $admin, [ 'source_purchase_id' => $purchase->id, 'source_catalog_item_id' => $item->id, 'source_variant_id' => $variant->id, 'scanner_user_id' => $admin->id, 'used_at' => now(), ]); $this->getJson('/api/v1/adminapp/tenant/tickets') ->assertOk() ->assertJsonPath('data.0.id', $ticket->id) ->assertJsonPath('data.0.order_number', $purchase->id) ->assertJsonPath('data.0.product', 'Remera') ->assertJsonPath('data.0.amount', '8000.00') ->assertJsonPath('data.0.status', Ticket::STATUS_USED) ->assertJsonPath('data.0.scanned_by', $admin->nombre_apellido) ->assertJsonPath('data.0.variant_properties.0.code', 'size') ->assertJsonPath('data.0.variant_properties.0.label', 'Talle') ->assertJsonPath('data.0.variant_properties.0.values.0.value', 'xl') ->assertJsonPath('data.0.variant_properties.0.values.0.label', 'XL'); } private function createTenant(string $code): Tenant { $headerLogo = $this->createAttachment("{$code}-header.png"); $footerLogo = $this->createAttachment("{$code}-footer.png"); return Tenant::query()->create([ 'codigo' => $code, 'nombre' => ucfirst($code), 'dominio' => "{$code}.test", 'website_type_code' => 'onticket', 'primary_color' => '#111111', 'secondary_color' => '#222222', 'danger_color' => '#333333', 'success_color' => '#444444', 'header_bg_color' => '#ffffff', 'footer_bg_color' => '#ffffff', 'header_logo_id' => $headerLogo->id, 'footer_logo_id' => $footerLogo->id, ]); } private function createAttachment(string $filename): Attachment { return Attachment::query()->create([ 'path' => "test/{$filename}", 'filename' => $filename, 'type' => AttachmentType::Image, 'mime_type' => 'image/png', ]); } private function createAdminAppUser(Tenant $tenant): User { return User::factory()->create([ 'rol_codigo' => RoleCode::AdminApp->value, 'tenant_codigo' => $tenant->codigo, ]); } private function grantTicketsMenu(Tenant $tenant): void { $menu = Menu::query()->create([ 'code' => 'adminapp.tickets', 'label' => 'Tickets', 'route' => '/admin/tickets', ]); $tenant->menues()->attach($menu->code); } /** @param array $attributes */ private function createTicket(Tenant $tenant, User $user, array $attributes = []): Ticket { return Ticket::query()->create(array_merge([ 'tenant_code' => $tenant->codigo, 'ticket' => (string) Str::uuid(), 'user_id' => $user->id, ], $attributes)); } }