Add service-point routing so call-next cannot steal assigned tickets.
Deploy Ladill Queue / deploy (push) Successful in 2m17s

Counters gain destination/staff metadata; tickets can be pre-assigned to a
service point with assigned_only queues for healthcare while shared_pool
preserves generic bank/government behavior. Display and announcements expose
ticket, staff, and destination clearly for Care and public boards.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-17 17:21:56 +00:00
co-authored by Cursor
parent 2d1f8c1eff
commit 0854b431bc
17 changed files with 753 additions and 42 deletions
@@ -50,12 +50,14 @@ class ServiceQueueController extends Controller
'max_capacity' => ['nullable', 'integer', 'min:1'],
'is_active' => ['nullable', 'boolean'],
'external_key' => ['nullable', 'string', 'max:191'],
'routing_mode' => ['nullable', 'string', 'in:shared_pool,assigned_only'],
]);
$branch = $this->resolveBranch($organization->id, $owner, $validated);
abort_unless($branch, 422, 'A valid branch_id or branch_name is required.');
$externalKey = isset($validated['external_key']) ? trim((string) $validated['external_key']) : '';
$routingMode = $validated['routing_mode'] ?? null;
if ($externalKey !== '') {
$existing = ServiceQueue::owned($owner)
->where('organization_id', $organization->id)
@@ -63,6 +65,10 @@ class ServiceQueueController extends Controller
->first();
if ($existing) {
$settings = array_merge($existing->settings ?? [], ['external_key' => $externalKey]);
if ($routingMode) {
$settings['routing_mode'] = $routingMode;
}
$existing->update([
'name' => $validated['name'],
'description' => $validated['description'] ?? $existing->description,
@@ -76,7 +82,7 @@ class ServiceQueueController extends Controller
'is_active' => array_key_exists('is_active', $validated)
? (bool) $validated['is_active']
: true,
'settings' => array_merge($existing->settings ?? [], ['external_key' => $externalKey]),
'settings' => $settings,
]);
AuditLogger::record($owner, 'service_queue.updated', $organization->id, $owner, ServiceQueue::class, $existing->id);
@@ -96,6 +102,9 @@ class ServiceQueueController extends Controller
if ($externalKey !== '') {
$settings['external_key'] = $externalKey;
}
if ($routingMode) {
$settings['routing_mode'] = $routingMode;
}
$byName->update([
'prefix' => $validated['prefix'],
'strategy' => $validated['strategy'] ?? $byName->strategy,
@@ -114,6 +123,14 @@ class ServiceQueueController extends Controller
'Queue limit reached for current plan.',
);
$settings = [];
if ($externalKey !== '') {
$settings['external_key'] = $externalKey;
}
if ($routingMode) {
$settings['routing_mode'] = $routingMode;
}
$queue = ServiceQueue::create([
'owner_ref' => $owner,
'organization_id' => $organization->id,
@@ -127,7 +144,7 @@ class ServiceQueueController extends Controller
'avg_service_seconds' => $validated['avg_service_seconds'] ?? 300,
'max_capacity' => $validated['max_capacity'] ?? null,
'is_active' => array_key_exists('is_active', $validated) ? (bool) $validated['is_active'] : true,
'settings' => $externalKey !== '' ? ['external_key' => $externalKey] : null,
'settings' => $settings !== [] ? $settings : null,
]);
AuditLogger::record($owner, 'service_queue.created', $organization->id, $owner, ServiceQueue::class, $queue->id);
@@ -148,8 +165,16 @@ class ServiceQueueController extends Controller
'is_active' => ['sometimes', 'boolean'],
'avg_service_seconds' => ['nullable', 'integer', 'min:60', 'max:7200'],
'max_capacity' => ['nullable', 'integer', 'min:1'],
'routing_mode' => ['nullable', 'string', 'in:shared_pool,assigned_only'],
]);
$settings = $serviceQueue->settings ?? [];
if (! empty($validated['routing_mode'])) {
$settings['routing_mode'] = $validated['routing_mode'];
unset($validated['routing_mode']);
$validated['settings'] = $settings;
}
$serviceQueue->update($validated);
AuditLogger::record(
@@ -233,6 +258,8 @@ class ServiceQueueController extends Controller
'is_paused' => $q->is_paused,
'branch' => $q->branch?->name,
'external_key' => data_get($q->settings, 'external_key'),
'routing_mode' => $q->routingMode(),
'department_id' => $q->department_id,
];
}
}