Hard-delete Care remote Queue adapter (Phase 5).
Deploy Ladill Care / deploy (push) Failing after 1m13s

Care Queue Engine is the only path; remove QueueClient, driver config, and remote HTTP tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 11:16:41 +00:00
co-authored by Cursor
parent 966f0496b2
commit dd4bc493b4
31 changed files with 441 additions and 2108 deletions
+3 -122
View File
@@ -8,36 +8,22 @@ use App\Models\CareServiceQueue;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Practitioner;
use App\Services\Queue\QueueClient;
use Illuminate\Support\Facades\Log;
/**
* Idempotently provisions service queues and service points from Care staff /
* branch configuration. Native driver writes Care Queue Engine tables; remote
* driver syncs to Ladill Queue over HTTP (legacy cutover).
* Idempotently provisions Care Queue Engine service queues and service points
* from Care staff / branch configuration.
*/
class CareQueueProvisioner
{
public function __construct(
protected QueueClient $queue,
protected PlanService $plans,
) {}
public function usesNative(): bool
{
return config('care.queue.driver', 'native') === 'native';
}
public function shouldProvision(Organization $organization): bool
{
$enabled = $this->plans->canUseQueueIntegration($organization)
return $this->plans->canUseQueueIntegration($organization)
&& (bool) data_get($organization->settings, 'queue_integration_enabled');
if (! $enabled) {
return false;
}
return $this->usesNative() || $this->queue->configured();
}
/**
@@ -121,95 +107,6 @@ class CareQueueProvisioner
'synced' => false,
];
if ($this->usesNative()) {
return $this->provisionBranchDepartmentNative($organization, $owner, $context, $meta, $branch, $stub);
}
try {
$this->ensureBranchName($owner, $branch->name);
$department = $this->queue->ensureDepartment($owner, [
'name' => $meta['name'],
'type' => $meta['type'] ?? 'general',
'branch_name' => $branch->name,
'external_key' => $stub['department_external_key'],
'is_active' => true,
]);
$stub['department_id'] = $department['id'] ?? $stub['department_id'];
$queue = $this->queue->ensureQueue($owner, [
'name' => $meta['name'],
'prefix' => $meta['prefix'],
'branch_name' => $branch->name,
'strategy' => 'fifo',
'external_key' => $stub['queue_external_key'],
'routing_mode' => $meta['routing_mode'],
'department_id' => $stub['department_id'],
'is_active' => true,
]);
$stub['queue_uuid'] = $queue['uuid'] ?? $stub['queue_uuid'];
$points = $this->buildPointsForContext($organization, $context, $branch, $stub);
$syncedPoints = [];
foreach ($points as $point) {
try {
$counter = $this->queue->ensureCounter($owner, [
'name' => $point['name'],
'destination' => $point['destination'],
'staff_ref' => $point['staff_ref'],
'staff_display_name' => $point['staff_display_name'],
'branch_name' => $branch->name,
'department_id' => $stub['department_id'],
'queue_uuids' => array_values(array_filter([(string) $stub['queue_uuid']])),
'external_key' => $point['external_key'],
'is_active' => true,
]);
$point['counter_uuid'] = $counter['uuid'] ?? null;
$point['synced'] = ! empty($point['counter_uuid']);
} catch (\Throwable $e) {
Log::warning('care.queue_point_provision_failed', [
'context' => $context,
'branch_id' => $branch->id,
'point' => $point['external_key'] ?? null,
'message' => $e->getMessage(),
]);
$point['synced'] = false;
}
$syncedPoints[] = $point;
}
$stub['points'] = $syncedPoints;
// Legacy single counter: first point (or dedicated default) for older callers.
$first = collect($syncedPoints)->first(fn ($p) => ! empty($p['counter_uuid']));
if ($first) {
$stub['counter_uuid'] = $first['counter_uuid'];
$stub['counter_external_key'] = $first['external_key'];
}
$stub['synced'] = ! empty($stub['queue_uuid']) && collect($syncedPoints)->contains(fn ($p) => ! empty($p['synced']));
} catch (\Throwable $e) {
Log::warning('care.queue_department_provision_failed', [
'context' => $context,
'branch_id' => $branch->id,
'message' => $e->getMessage(),
]);
}
return $stub;
}
/**
* @param array<string, mixed> $meta
* @param array<string, mixed> $stub
* @return array<string, mixed>
*/
protected function provisionBranchDepartmentNative(
Organization $organization,
string $owner,
string $context,
array $meta,
Branch $branch,
array $stub,
): array {
try {
$queue = CareServiceQueue::query()->updateOrCreate(
[
@@ -264,7 +161,6 @@ class CareQueueProvisioner
$syncedPoints[] = $point;
}
// Soft-deactivate points no longer in the staff roster.
CareServicePoint::query()
->where('service_queue_id', $queue->id)
->when(
@@ -302,7 +198,6 @@ class CareQueueProvisioner
Branch $branch,
array $stub,
): array {
$owner = (string) $organization->owner_ref;
$priorByKey = collect($stub['points'] ?? [])->keyBy(fn ($p) => (string) ($p['external_key'] ?? ''));
$points = match (true) {
@@ -362,7 +257,6 @@ class CareQueueProvisioner
default => [],
};
// Always keep at least one default point so call-next / least-load have a target.
if ($points === []) {
$key = CareQueueContexts::pointExternalKey($context, $branch->id, 'default', 0);
$prior = $priorByKey->get($key, []);
@@ -487,17 +381,6 @@ class CareQueueProvisioner
return $points;
}
protected function ensureBranchName(string $owner, string $branchName): void
{
try {
$this->queue->ensureBranch($owner, ['name' => $branchName]);
} catch (\Illuminate\Http\Client\RequestException $e) {
if ($e->response?->status() !== 422) {
throw $e;
}
}
}
/**
* @return array{queue_uuid: ?string, counter_uuid: ?string, queue_external_key: string, counter_external_key: string, synced: bool, points: list<array<string, mixed>>, routing_mode: string}|null
*/
@@ -632,8 +515,6 @@ class CareQueueProvisioner
if ($existing && ! empty($existing['queue_uuid']) && (
! empty($existing['points']) || ! empty($existing['counter_uuid'])
) && $modeMatches) {
// Specialty module stubs often only store a legacy counter — still provision
// practitioner points so check-in / sync can assign real desks.
if (! CareQueueContexts::isSpecialty($context) || ! empty($existing['points'])) {
return $existing;
}