token()) ->acceptJson() ->timeout(12) ->withQueryParameters(['owner' => $owner]); } public function configured(): bool { return $this->token() !== '' && $this->base() !== ''; } /** * @return array */ public function status(string $owner): array { $response = $this->http($owner)->get($this->base().'/integrations/status'); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @return array */ public function enable(string $owner, string $organizationName, ?string $branchName = null): array { $this->http($owner)->post($this->base().'/integrations/provision', array_filter([ 'organization_name' => $organizationName, 'branch_name' => $branchName, 'industry' => 'healthcare', ]))->throw(); return $this->syncIntegration($owner, true); } /** * @return array */ public function syncIntegration(string $owner, bool $enabled = true): array { $response = $this->http($owner)->patch($this->base().'/integrations', [ 'care_enabled' => $enabled, ]); $response->throw(); return (array) ($response->json('data') ?? []); } public function disable(string $owner): void { // Local Care setting only; Queue must be disabled separately in Queue settings. } public function isLinked(string $owner): bool { if (! $this->configured()) { return false; } try { $status = $this->status($owner); return (bool) ($status['provisioned'] ?? false) && (bool) data_get($status, 'integrations.care', false); } catch (RequestException) { return false; } } /** * @return list> */ public function counters(string $owner): array { $response = $this->http($owner)->get($this->base().'/counters'); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @return list> */ public function branches(string $owner): array { $response = $this->http($owner)->get($this->base().'/branches'); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @param array $payload * @return array */ public function ensureBranch(string $owner, array $payload): array { $response = $this->http($owner)->post($this->base().'/branches', $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @param array $payload * @return array */ public function ensureQueue(string $owner, array $payload): array { $response = $this->http($owner)->post($this->base().'/queues', $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @param array $payload * @return array */ public function ensureCounter(string $owner, array $payload): array { $response = $this->http($owner)->post($this->base().'/counters', $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * Soft-deactivate a Queue counter without destroying history. * * @return array */ public function updateCounter(string $owner, string $counterUuid, array $payload): array { $response = $this->http($owner)->patch($this->base().'/counters/'.$counterUuid, $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * Soft-deactivate a Queue service queue without destroying history. * * @return array */ public function updateQueue(string $owner, string $queueUuid, array $payload): array { $response = $this->http($owner)->patch($this->base().'/queues/'.$queueUuid, $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @return array */ public function console(string $owner, string $counterUuid): array { $response = $this->http($owner)->get($this->base().'/counters/'.$counterUuid.'/console'); $response->throw(); return (array) ($response->json('data') ?? []); } /** * @param array $payload * @return array */ public function consoleAction(string $owner, string $counterUuid, array $payload): array { $response = $this->http($owner)->post($this->base().'/counters/'.$counterUuid.'/console', $payload); $response->throw(); return (array) ($response->json('data') ?? []); } /** * Create or link real Queue queues/counters for Care specialty stubs. * Idempotent via external_key (and Queue-side name+branch fallback). * * @param list> $stubs * @return list> */ public function syncSpecialtyQueueStubs(string $owner, array $stubs): array { if (! $this->configured() || $stubs === []) { return $stubs; } try { if (! $this->isLinked($owner)) { return $stubs; } } catch (\Throwable) { return $stubs; } foreach ($stubs as $i => $stub) { if (! ($stub['active'] ?? true)) { continue; } try { $stubs[$i] = $this->ensureSpecialtyStub($owner, $stub); } catch (\Throwable $e) { Log::warning('queue.specialty_stub_sync_failed', [ 'owner' => $owner, 'stub' => $stub['name'] ?? null, 'branch' => $stub['branch_name'] ?? null, 'message' => $e->getMessage(), ]); $stubs[$i]['synced'] = false; } } return $stubs; } /** * Soft-deactivate Queue resources linked on Care stubs (leaves history intact). * * @param list> $stubs * @return list> */ public function deactivateSpecialtyQueueStubs(string $owner, array $stubs): array { if (! $this->configured() || $stubs === []) { return $stubs; } foreach ($stubs as $i => $stub) { try { if (! empty($stub['counter_uuid'])) { $this->updateCounter($owner, (string) $stub['counter_uuid'], ['is_active' => false]); } if (! empty($stub['queue_uuid'])) { $this->updateQueue($owner, (string) $stub['queue_uuid'], ['is_active' => false]); } } catch (\Throwable $e) { Log::warning('queue.specialty_stub_deactivate_failed', [ 'owner' => $owner, 'counter_uuid' => $stub['counter_uuid'] ?? null, 'queue_uuid' => $stub['queue_uuid'] ?? null, 'message' => $e->getMessage(), ]); } $stubs[$i]['active'] = false; } return $stubs; } /** * @param array $stub * @return array */ protected function ensureSpecialtyStub(string $owner, array $stub): array { $branchName = trim((string) ($stub['branch_name'] ?? '')); $name = trim((string) ($stub['name'] ?? '')); $prefix = trim((string) ($stub['prefix'] ?? 'A')); $module = (string) ($stub['module'] ?? 'specialty'); $careBranchId = (string) ($stub['branch_id'] ?? '0'); if ($branchName === '' || $name === '') { $stub['synced'] = false; return $stub; } $queueKey = (string) ($stub['queue_external_key'] ?? "care:specialty:{$module}:queue:{$careBranchId}"); $counterKey = (string) ($stub['counter_external_key'] ?? "care:specialty:{$module}:counter:{$careBranchId}"); try { $this->ensureBranch($owner, ['name' => $branchName]); } catch (RequestException $e) { // Free Queue plans may already be at branch cap — continue if a branch can be resolved. if ($e->response?->status() !== 422) { throw $e; } $branches = collect($this->branches($owner)); $existing = $branches->first( fn ($b) => strcasecmp((string) ($b['name'] ?? ''), $branchName) === 0 ); if (! $existing && $branches->count() === 1) { // Single-location Queue orgs often use a different default name (e.g. "Main Branch"). $existing = $branches->first(); $branchName = (string) ($existing['name'] ?? $branchName); } if (! $existing) { throw $e; } } $queue = $this->ensureQueue($owner, [ 'name' => $name, 'prefix' => $prefix !== '' ? $prefix : 'A', 'branch_name' => $branchName, 'strategy' => 'fifo', 'external_key' => $queueKey, 'is_active' => true, ]); $counter = $this->ensureCounter($owner, [ 'name' => $name.' counter', 'branch_name' => $branchName, 'queue_uuids' => array_values(array_filter([(string) ($queue['uuid'] ?? '')])), 'external_key' => $counterKey, 'is_active' => true, ]); $stub['queue_external_key'] = $queueKey; $stub['counter_external_key'] = $counterKey; $stub['queue_uuid'] = $queue['uuid'] ?? null; $stub['counter_uuid'] = $counter['uuid'] ?? null; $stub['synced'] = ! empty($stub['queue_uuid']) && ! empty($stub['counter_uuid']); return $stub; } }