Files
ladill-care/tests/Feature/CareDisplayVoiceTest.php
T
isaaccladandCursor 03befd1e7f
Deploy Ladill Care / deploy (push) Failing after 57s
Add Care waiting-area TV displays with browser TTS voice.
Call-next and recall queue announcements for lobby screens without Ladill Queue.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-18 11:23:15 +00:00

233 lines
8.1 KiB
PHP

<?php
namespace Tests\Feature;
use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Branch;
use App\Models\CareDisplayScreen;
use App\Models\CareQueueTicket;
use App\Models\CareServicePoint;
use App\Models\CareServiceQueue;
use App\Models\CareVoiceAnnouncement;
use App\Models\Member;
use App\Models\Organization;
use App\Models\User;
use App\Services\Care\CareQueueEngine;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class CareDisplayVoiceTest extends TestCase
{
use RefreshDatabase;
protected User $owner;
protected Organization $organization;
protected Branch $branch;
protected CareServiceQueue $queue;
protected CareServicePoint $point;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware(EnsurePlatformSession::class);
$this->owner = User::create([
'public_id' => 'display-voice-owner',
'name' => 'Owner',
'email' => 'display-voice@example.com',
]);
$this->organization = Organization::create([
'owner_ref' => $this->owner->public_id,
'name' => 'Display Voice Clinic',
'slug' => 'display-voice-clinic',
'settings' => [
'onboarded' => true,
'facility_type' => 'clinic',
'plan' => 'pro',
'plan_expires_at' => now()->addMonth()->toIso8601String(),
'queue_integration_enabled' => true,
],
]);
Member::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'user_ref' => $this->owner->public_id,
'role' => 'hospital_admin',
]);
$this->branch = Branch::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'name' => 'Main',
'is_active' => true,
]);
$this->queue = CareServiceQueue::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'context' => 'consultation',
'name' => 'Reception',
'prefix' => 'A',
'routing_mode' => 'shared_pool',
'is_active' => true,
]);
$this->point = CareServicePoint::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'service_queue_id' => $this->queue->id,
'name' => 'Counter 1',
'is_active' => true,
]);
}
public function test_display_data_includes_pending_announcement_after_call(): void
{
$screen = CareDisplayScreen::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'name' => 'Lobby',
'layout' => 'standard',
'service_queue_ids' => [$this->queue->id],
'is_active' => true,
]);
$engine = app(CareQueueEngine::class);
$engine->issueTicket($this->organization, [
'service_queue_id' => $this->queue->uuid,
]);
$engine->callNext($this->organization, $this->queue->uuid, $this->point->uuid);
$response = $this->getJson(route('care.display.data', $screen->access_token));
$response->assertOk()
->assertJsonPath('announcements.0.message', 'Ticket A001, please proceed to Counter 1.')
->assertJsonPath('waiting_count', 0)
->assertJsonPath('now_serving.0.ticket_number', 'A001')
->assertJsonPath('now_serving.0.queue_name', 'Reception')
->assertJsonPath('now_serving.0.counter', 'Counter 1');
$this->get(route('care.display.public', $screen->access_token))
->assertOk()
->assertSee('Please proceed to')
->assertSee('A001')
->assertSee('Reception')
->assertSee('Counter 1');
}
public function test_display_shows_only_latest_ticket_per_service_point(): void
{
$room12 = CareServicePoint::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'service_queue_id' => $this->queue->id,
'name' => 'Room 12',
'is_active' => true,
]);
$room14 = CareServicePoint::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'service_queue_id' => $this->queue->id,
'name' => 'Room 14',
'is_active' => true,
]);
$screen = CareDisplayScreen::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'name' => 'Busy Lobby',
'layout' => 'standard',
'service_queue_ids' => [$this->queue->id],
'is_active' => true,
]);
foreach ([
['A001', $room12->id, 6],
['A002', $room12->id, 5],
['A003', $room12->id, 2],
['A004', $room14->id, 4],
['A005', $room14->id, 1],
] as [$number, $pointId, $minutesAgo]) {
CareQueueTicket::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'service_queue_id' => $this->queue->id,
'service_point_id' => $pointId,
'ticket_number' => $number,
'status' => CareQueueTicket::STATUS_CALLED,
'called_at' => now()->subMinutes($minutesAgo),
]);
}
$payload = $this->getJson(route('care.display.data', $screen->access_token))
->assertOk()
->assertJsonCount(2, 'now_serving')
->json('now_serving');
$byCounter = collect($payload)->keyBy('counter');
$this->assertSame('A003', $byCounter['Room 12']['ticket_number']);
$this->assertSame('A005', $byCounter['Room 14']['ticket_number']);
$this->assertSame(['Room 12', 'Room 14'], collect($payload)->pluck('counter')->all());
}
public function test_display_falls_back_to_branch_queues_when_none_assigned(): void
{
$screen = CareDisplayScreen::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'name' => 'Lobby',
'layout' => 'standard',
'service_queue_ids' => [],
'is_active' => true,
]);
app(CareQueueEngine::class)->issueTicket($this->organization, [
'service_queue_id' => $this->queue->uuid,
]);
$this->getJson(route('care.display.data', $screen->access_token))
->assertOk()
->assertJsonPath('waiting_count', 1)
->assertJsonPath('queues.0.name', 'Reception');
}
public function test_display_marks_announcement_played(): void
{
$screen = CareDisplayScreen::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'name' => 'Lobby',
'layout' => 'standard',
'service_queue_ids' => [$this->queue->id],
'is_active' => true,
]);
$announcement = CareVoiceAnnouncement::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'locale' => 'en',
'message' => 'Ticket A001, please proceed to Counter 1.',
'status' => 'pending',
]);
$this->postJson(route('care.display.announcement.played', [
'token' => $screen->access_token,
'announcement' => $announcement->id,
]))->assertOk();
$this->assertSame('played', $announcement->fresh()->status);
}
}