Add self-service kiosk for queue ticket issuance.
Deploy Ladill Queue / deploy (push) Successful in 36s
Deploy Ladill Queue / deploy (push) Successful in 36s
Customers can pick a service, optionally enter details, and receive a ticket on a branded touchscreen flow with admin-configurable queues and auto-reset. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Device;
|
||||
use App\Models\Organization;
|
||||
use App\Models\ServiceQueue;
|
||||
use App\Models\User;
|
||||
use App\Services\Qms\DeviceService;
|
||||
use App\Services\Qms\OrganizationResolver;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class KioskDeviceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* @return array{0: User, 1: Organization, 2: Branch, 3: ServiceQueue, 4: Device, 5: string}
|
||||
*/
|
||||
protected function setUpKiosk(): array
|
||||
{
|
||||
$user = User::create([
|
||||
'public_id' => 'test-owner-uuid',
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => bcrypt('password'),
|
||||
]);
|
||||
$resolver = app(OrganizationResolver::class);
|
||||
$org = $resolver->completeOnboarding($user, [
|
||||
'organization_name' => 'Test Org',
|
||||
'industry' => 'retail',
|
||||
'appointment_mode' => 'hybrid',
|
||||
'branch_name' => 'Main',
|
||||
'timezone' => 'UTC',
|
||||
]);
|
||||
$branch = Branch::first();
|
||||
$queue = ServiceQueue::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Reception',
|
||||
'prefix' => 'A',
|
||||
'strategy' => 'fifo',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$device = Device::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Lobby Kiosk',
|
||||
'type' => 'kiosk',
|
||||
'status' => 'offline',
|
||||
'config' => [
|
||||
'service_queue_ids' => [$queue->id],
|
||||
'collect_name' => false,
|
||||
'collect_phone' => false,
|
||||
'reset_seconds' => 15,
|
||||
],
|
||||
]);
|
||||
|
||||
$token = app(DeviceService::class)->generateToken($device);
|
||||
|
||||
return [$user, $org, $branch, $queue, $device, $token];
|
||||
}
|
||||
|
||||
public function test_kiosk_page_loads_with_assigned_queues(): void
|
||||
{
|
||||
[, , , $queue, , $token] = $this->setUpKiosk();
|
||||
|
||||
$response = $this->get(route('qms.kiosk.device', $token));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSee('Welcome', false);
|
||||
$response->assertSee($queue->name, false);
|
||||
$response->assertSee('Powered by', false);
|
||||
}
|
||||
|
||||
public function test_kiosk_issues_ticket_for_allowed_queue(): void
|
||||
{
|
||||
[, , , $queue, , $token] = $this->setUpKiosk();
|
||||
|
||||
$response = $this->postJson(route('qms.kiosk.device.issue', $token), [
|
||||
'queue_id' => $queue->id,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('data.queue.name', 'Reception');
|
||||
$response->assertJsonPath('data.source', 'kiosk');
|
||||
$this->assertNotEmpty($response->json('data.ticket_number'));
|
||||
}
|
||||
|
||||
public function test_kiosk_rejects_unassigned_queue(): void
|
||||
{
|
||||
[$user, $org, $branch, , , $token] = $this->setUpKiosk();
|
||||
|
||||
$otherQueue = ServiceQueue::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Billing',
|
||||
'prefix' => 'B',
|
||||
'strategy' => 'fifo',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$response = $this->postJson(route('qms.kiosk.device.issue', $token), [
|
||||
'queue_id' => $otherQueue->id,
|
||||
]);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_kiosk_rejects_paused_queue(): void
|
||||
{
|
||||
[, , , $queue, , $token] = $this->setUpKiosk();
|
||||
$queue->update(['is_paused' => true]);
|
||||
|
||||
$response = $this->postJson(route('qms.kiosk.device.issue', $token), [
|
||||
'queue_id' => $queue->id,
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_non_kiosk_device_cannot_access_kiosk_routes(): void
|
||||
{
|
||||
[$user, $org, $branch] = array_slice($this->setUpKiosk(), 0, 3);
|
||||
|
||||
$printer = Device::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Printer',
|
||||
'type' => 'printer',
|
||||
'status' => 'offline',
|
||||
]);
|
||||
$token = app(DeviceService::class)->generateToken($printer);
|
||||
|
||||
$this->get(route('qms.kiosk.device', $token))->assertForbidden();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user