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:
@@ -101,6 +101,27 @@ class QueueEngine
|
||||
|
||||
public function callNext(ServiceQueue $queue, Counter $counter, ?string $actorRef = null): ?Ticket
|
||||
{
|
||||
// One patient at a time per service point: finish serving before calling another.
|
||||
$activeServing = Ticket::query()
|
||||
->where('service_queue_id', $queue->id)
|
||||
->where('counter_id', $counter->id)
|
||||
->where('status', 'serving')
|
||||
->exists();
|
||||
if ($activeServing) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Already called someone at this counter — re-announce instead of stacking another patient.
|
||||
$alreadyCalled = Ticket::query()
|
||||
->where('service_queue_id', $queue->id)
|
||||
->where('counter_id', $counter->id)
|
||||
->where('status', 'called')
|
||||
->orderByDesc('called_at')
|
||||
->first();
|
||||
if ($alreadyCalled) {
|
||||
return $this->recall($alreadyCalled, $actorRef);
|
||||
}
|
||||
|
||||
$ticket = $this->nextWaitingTicket($queue, $counter);
|
||||
if (! $ticket) {
|
||||
return null;
|
||||
@@ -111,14 +132,18 @@ class QueueEngine
|
||||
|
||||
public function callTicket(Ticket $ticket, Counter $counter, ?string $actorRef = null): Ticket
|
||||
{
|
||||
if ($ticket->assigned_counter_id && (int) $ticket->assigned_counter_id !== (int) $counter->id) {
|
||||
$ticket->loadMissing('serviceQueue');
|
||||
$queue = $ticket->serviceQueue;
|
||||
if ($queue?->usesAssignedOnlyRouting()
|
||||
&& $ticket->assigned_counter_id
|
||||
&& (int) $ticket->assigned_counter_id !== (int) $counter->id) {
|
||||
throw new \RuntimeException('Ticket is assigned to another service point.');
|
||||
}
|
||||
|
||||
$ticket->update([
|
||||
'status' => 'called',
|
||||
'counter_id' => $counter->id,
|
||||
'assigned_counter_id' => $ticket->assigned_counter_id ?: $counter->id,
|
||||
'assigned_counter_id' => $counter->id,
|
||||
'called_at' => now(),
|
||||
]);
|
||||
|
||||
@@ -402,7 +427,8 @@ class QueueEngine
|
||||
->where('service_queue_id', $queue->id)
|
||||
->where('status', 'waiting')
|
||||
->orderByRaw($this->priorityOrderSql())
|
||||
->orderBy('issued_at');
|
||||
->orderBy('issued_at')
|
||||
->orderBy('id');
|
||||
|
||||
if (! $counter) {
|
||||
return $query;
|
||||
@@ -412,10 +438,9 @@ class QueueEngine
|
||||
return $query->where('assigned_counter_id', $counter->id);
|
||||
}
|
||||
|
||||
return $query->where(function ($q) use ($counter) {
|
||||
$q->whereNull('assigned_counter_id')
|
||||
->orWhere('assigned_counter_id', $counter->id);
|
||||
});
|
||||
// Shared pool (pharmacy, bank tellers, etc.): FIFO across the whole queue.
|
||||
// Prior counter assignment does not block another desk from claiming the next waiting ticket.
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user