Fix pharmacy Call next to FIFO shared pool with one patient per counter.
Deploy Ladill Queue / deploy (push) Successful in 46s
Deploy Ladill Queue / deploy (push) Successful in 46s
Pharmacy/lab/billing now use a shared waiting pool claimed in order on Call next. A counter cannot stack another called ticket while one is already called or being served, so pharmacists no longer pull randomly or multiple patients at once. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Models\Counter;
|
||||
use App\Models\DisplayScreen;
|
||||
use App\Models\Organization;
|
||||
use App\Models\ServiceQueue;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use App\Services\Qms\DisplayService;
|
||||
use App\Services\Qms\OrganizationResolver;
|
||||
@@ -197,6 +198,80 @@ class ServicePointRoutingTest extends TestCase
|
||||
$this->assertSame($ticket->id, $called->id);
|
||||
}
|
||||
|
||||
public function test_shared_pool_call_next_is_fifo_and_one_at_a_time_per_counter(): void
|
||||
{
|
||||
$user = User::create([
|
||||
'public_id' => 'pharm-owner',
|
||||
'name' => 'Pharmacy',
|
||||
'email' => 'pharm@example.com',
|
||||
'password' => bcrypt('password'),
|
||||
]);
|
||||
$org = app(OrganizationResolver::class)->completeOnboarding($user, [
|
||||
'organization_name' => 'Clinic Pharmacy',
|
||||
'industry' => 'custom',
|
||||
'appointment_mode' => 'walk_in_only',
|
||||
'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' => 'Pharmacy',
|
||||
'prefix' => 'P',
|
||||
'strategy' => 'fifo',
|
||||
'is_active' => true,
|
||||
'settings' => ['routing_mode' => 'shared_pool'],
|
||||
]);
|
||||
$c1 = Counter::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Counter 1',
|
||||
'destination' => 'Counter 1',
|
||||
'status' => 'available',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$c2 = Counter::create([
|
||||
'owner_ref' => $user->public_id,
|
||||
'organization_id' => $org->id,
|
||||
'branch_id' => $branch->id,
|
||||
'name' => 'Counter 2',
|
||||
'destination' => 'Counter 2',
|
||||
'status' => 'available',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$c1->serviceQueues()->sync([$queue->id]);
|
||||
$c2->serviceQueues()->sync([$queue->id]);
|
||||
|
||||
$engine = app(QueueEngine::class);
|
||||
$first = $engine->issueTicket($queue, $user->public_id, ['customer_name' => 'A']);
|
||||
$second = $engine->issueTicket($queue->fresh(), $user->public_id, ['customer_name' => 'B']);
|
||||
$third = $engine->issueTicket($queue->fresh(), $user->public_id, ['customer_name' => 'C']);
|
||||
|
||||
// Pre-assign first ticket to the "wrong" counter — shared pool must still allow FIFO claim.
|
||||
$first->update(['assigned_counter_id' => $c2->id]);
|
||||
|
||||
$called1 = $engine->callNext($queue, $c1, $user->public_id);
|
||||
$this->assertSame($first->id, $called1->id);
|
||||
$this->assertSame('called', $called1->status);
|
||||
$this->assertSame($c1->id, $called1->counter_id);
|
||||
|
||||
// Second Call next at same counter recalls the same patient — does not stack.
|
||||
$again = $engine->callNext($queue, $c1, $user->public_id);
|
||||
$this->assertSame($first->id, $again->id);
|
||||
$this->assertSame(1, Ticket::where('service_queue_id', $queue->id)->where('status', 'called')->count());
|
||||
|
||||
$engine->startServing($called1->fresh(), $user->public_id);
|
||||
$this->assertNull($engine->callNext($queue, $c1, $user->public_id));
|
||||
|
||||
// Other counter still gets the next waiting patient in FIFO order.
|
||||
$called2 = $engine->callNext($queue, $c2, $user->public_id);
|
||||
$this->assertSame($second->id, $called2->id);
|
||||
$this->assertSame($third->id, $engine->waitingTickets($queue)[0]->id);
|
||||
}
|
||||
|
||||
public function test_care_api_can_issue_assigned_ticket(): void
|
||||
{
|
||||
config(['qms.service_api_keys.care' => 'test-care-key']);
|
||||
|
||||
Reference in New Issue
Block a user