Files
ladill-queue/tests/Feature/QmsQueueTest.php
T
isaaccladandCursor cca98eefd2
Deploy Ladill Queue / deploy (push) Successful in 56s
Initial Ladill Queue release — enterprise QMS standalone app.
Phases 1–6: tickets, counters, displays, appointments, workflows, rules, analytics, reports, feedback, admin, device API, and Gitea deploy workflow for queue.ladill.com.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 20:19:52 +00:00

193 lines
6.6 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Branch;
use App\Models\Organization;
use App\Models\ServiceQueue;
use App\Models\User;
use App\Services\Qms\OrganizationResolver;
use App\Services\Qms\QueueEngine;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class QmsQueueTest extends TestCase
{
use RefreshDatabase;
protected function setUpOrg(): 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,
]);
return [$user, $org, $branch, $queue];
}
public function test_issue_ticket_increments_sequence(): void
{
[$user, , , $queue] = $this->setUpOrg();
$engine = app(QueueEngine::class);
$ticket = $engine->issueTicket($queue, $user->public_id, ['source' => 'api']);
$this->assertSame('A001', $ticket->ticket_number);
$this->assertSame('waiting', $ticket->status);
$ticket2 = $engine->issueTicket($queue->fresh(), $user->public_id);
$this->assertSame('A002', $ticket2->ticket_number);
}
public function test_health_endpoint(): void
{
$this->getJson('/api/health')->assertOk()->assertJson(['app' => 'queue']);
}
public function test_appointment_check_in_issues_ticket(): void
{
[$user, $org, $branch, $queue] = $this->setUpOrg();
$appointment = \App\Models\QueueAppointment::create([
'owner_ref' => $user->public_id,
'organization_id' => $org->id,
'branch_id' => $branch->id,
'service_queue_id' => $queue->id,
'customer_name' => 'Jane Doe',
'status' => 'scheduled',
'scheduled_at' => now()->addHour(),
'reference' => 'APT-TEST',
]);
$ticket = app(\App\Services\Qms\AppointmentService::class)->checkIn($appointment, $user->public_id);
$this->assertSame('appointment', $ticket->priority);
$this->assertSame('checked_in', $appointment->fresh()->status);
$this->assertSame($ticket->id, $appointment->fresh()->ticket_id);
}
public function test_workflow_metadata_attached_on_issue(): void
{
[$user, $org, $branch, $queue] = $this->setUpOrg();
$workflow = \App\Models\Workflow::create([
'owner_ref' => $user->public_id,
'organization_id' => $org->id,
'name' => 'Test flow',
'is_active' => true,
]);
\App\Models\WorkflowStep::create([
'workflow_id' => $workflow->id,
'service_queue_id' => $queue->id,
'name' => 'Step 1',
'sort_order' => 1,
]);
$ticket = app(QueueEngine::class)->issueTicket($queue, $user->public_id);
$this->assertSame($workflow->id, data_get($ticket->metadata, 'workflow_id'));
}
public function test_routing_rule_redirects_ticket(): void
{
[$user, $org, $branch, $queue] = $this->setUpOrg();
$target = ServiceQueue::create([
'owner_ref' => $user->public_id,
'organization_id' => $org->id,
'branch_id' => $branch->id,
'name' => 'VIP',
'prefix' => 'V',
'strategy' => 'fifo',
'is_active' => true,
]);
\App\Models\QueueRule::create([
'owner_ref' => $user->public_id,
'service_queue_id' => $queue->id,
'rule_type' => 'routing',
'conditions' => ['source' => 'api'],
'actions' => ['target_queue_id' => $target->id],
'sort_order' => 1,
'is_active' => true,
]);
$ticket = app(QueueEngine::class)->issueTicket($queue, $user->public_id, ['source' => 'api']);
$this->assertSame($target->id, $ticket->service_queue_id);
}
public function test_service_session_tracked(): void
{
[$user, , , $queue] = $this->setUpOrg();
$engine = app(QueueEngine::class);
$ticket = $engine->issueTicket($queue, $user->public_id);
$counter = \App\Models\Counter::create([
'owner_ref' => $user->public_id,
'organization_id' => $queue->organization_id,
'branch_id' => $queue->branch_id,
'name' => 'C1',
'status' => 'available',
'is_active' => true,
]);
$engine->callTicket($ticket, $counter, $user->public_id);
$engine->startServing($ticket->fresh(), $user->public_id);
$engine->completeTicket($ticket->fresh(), $user->public_id);
$this->assertDatabaseHas('queue_service_sessions', [
'ticket_id' => $ticket->id,
]);
$session = \App\Models\ServiceSession::where('ticket_id', $ticket->id)->first();
$this->assertNotNull($session->ended_at);
}
public function test_reports_sqlite_compatible(): void
{
[$user, $org, , $queue] = $this->setUpOrg();
app(QueueEngine::class)->issueTicket($queue, $user->public_id, ['source' => 'api']);
$reports = app(\App\Services\Qms\ReportService::class);
$from = now()->subDay();
$to = now()->addDay();
$data = $reports->ticketsReport($user->public_id, $org->id, $from, $to);
$this->assertArrayHasKey('total_issued', $data);
$this->assertGreaterThanOrEqual(1, $data['total_issued']);
}
public function test_device_heartbeat(): void
{
[$user, $org, $branch] = $this->setUpOrg();
$device = \App\Models\Device::create([
'owner_ref' => $user->public_id,
'organization_id' => $org->id,
'branch_id' => $branch->id,
'name' => 'Kiosk 1',
'type' => 'kiosk',
'device_token' => 'test-device-token-123',
]);
$this->postJson('/api/devices/heartbeat', [], [
'Authorization' => 'Bearer test-device-token-123',
])->assertOk()->assertJsonPath('status', 'ok');
$this->assertSame('online', $device->fresh()->status);
}
}