authorizeAbility($request, 'counters.view'); $owner = $this->ownerRef($request); $organization = $this->organization($request); $counters = Counter::owned($owner) ->where('organization_id', $organization->id) ->with(['serviceQueues', 'branch']) ->orderBy('name') ->get() ->map(fn (Counter $c) => $this->serializeCounter($c)); return response()->json(['data' => $counters]); } public function store(Request $request): JsonResponse { $this->authorizeAbility($request, 'counters.manage'); $owner = $this->ownerRef($request); $organization = $this->organization($request); $validated = $request->validate([ 'name' => ['required', 'string', 'max:255'], 'code' => ['nullable', 'string', 'max:50'], 'destination' => ['nullable', 'string', 'max:255'], 'staff_ref' => ['nullable', 'string', 'max:191'], 'staff_display_name' => ['nullable', 'string', 'max:255'], 'branch_id' => ['nullable', 'integer'], 'branch_name' => ['nullable', 'string', 'max:255'], 'department_id' => ['nullable', 'integer'], 'queue_ids' => ['nullable', 'array'], 'queue_ids.*' => ['uuid'], 'queue_uuids' => ['nullable', 'array'], 'queue_uuids.*' => ['uuid'], 'external_key' => ['nullable', 'string', 'max:191'], 'is_active' => ['nullable', 'boolean'], ]); $branch = $this->resolveBranch($request, $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']) : ''; if ($externalKey !== '') { $existing = Counter::owned($owner) ->where('organization_id', $organization->id) ->where('settings->external_key', $externalKey) ->first(); if ($existing) { $existing->update([ 'name' => $validated['name'], 'code' => $validated['code'] ?? $existing->code, 'destination' => array_key_exists('destination', $validated) ? $validated['destination'] : $existing->destination, 'staff_ref' => array_key_exists('staff_ref', $validated) ? $validated['staff_ref'] : $existing->staff_ref, 'staff_display_name' => array_key_exists('staff_display_name', $validated) ? $validated['staff_display_name'] : $existing->staff_display_name, 'branch_id' => $branch->id, 'department_id' => $validated['department_id'] ?? $existing->department_id, 'is_active' => array_key_exists('is_active', $validated) ? (bool) $validated['is_active'] : true, 'settings' => array_merge($existing->settings ?? [], ['external_key' => $externalKey]), ]); $this->syncQueues($existing, $owner, $validated); AuditLogger::record($owner, 'counter.updated', $organization->id, $owner, Counter::class, $existing->id); return response()->json(['data' => $this->serializeCounter($existing->fresh(['serviceQueues', 'branch']))]); } } $counter = Counter::create([ 'owner_ref' => $owner, 'organization_id' => $organization->id, 'branch_id' => $branch->id, 'department_id' => $validated['department_id'] ?? null, 'name' => $validated['name'], 'code' => $validated['code'] ?? null, 'destination' => $validated['destination'] ?? null, 'staff_ref' => $validated['staff_ref'] ?? null, 'staff_display_name' => $validated['staff_display_name'] ?? null, 'status' => 'offline', 'is_active' => array_key_exists('is_active', $validated) ? (bool) $validated['is_active'] : true, 'settings' => $externalKey !== '' ? ['external_key' => $externalKey] : null, ]); $this->syncQueues($counter, $owner, $validated); AuditLogger::record($owner, 'counter.created', $organization->id, $owner, Counter::class, $counter->id); return response()->json(['data' => $this->serializeCounter($counter->fresh(['serviceQueues', 'branch']))], 201); } public function update(Request $request, Counter $counter): JsonResponse { $this->authorizeAbility($request, 'counters.manage'); $this->authorizeOwner($request, $counter); $validated = $request->validate([ 'name' => ['sometimes', 'string', 'max:255'], 'code' => ['nullable', 'string', 'max:50'], 'destination' => ['nullable', 'string', 'max:255'], 'staff_ref' => ['nullable', 'string', 'max:191'], 'staff_display_name' => ['nullable', 'string', 'max:255'], 'is_active' => ['sometimes', 'boolean'], 'queue_ids' => ['nullable', 'array'], 'queue_ids.*' => ['uuid'], 'queue_uuids' => ['nullable', 'array'], 'queue_uuids.*' => ['uuid'], ]); $counter->update(array_filter([ 'name' => $validated['name'] ?? null, 'code' => array_key_exists('code', $validated) ? $validated['code'] : null, 'destination' => array_key_exists('destination', $validated) ? $validated['destination'] : null, 'staff_ref' => array_key_exists('staff_ref', $validated) ? $validated['staff_ref'] : null, 'staff_display_name' => array_key_exists('staff_display_name', $validated) ? $validated['staff_display_name'] : null, 'is_active' => array_key_exists('is_active', $validated) ? (bool) $validated['is_active'] : null, ], fn ($v) => $v !== null)); if (array_key_exists('queue_ids', $validated) || array_key_exists('queue_uuids', $validated)) { $this->syncQueues($counter, $this->ownerRef($request), $validated); } AuditLogger::record( $this->ownerRef($request), 'counter.updated', $counter->organization_id, $this->ownerRef($request), Counter::class, $counter->id, ); return response()->json(['data' => $this->serializeCounter($counter->fresh(['serviceQueues', 'branch']))]); } /** * @param array $validated */ protected function resolveBranch(Request $request, int $organizationId, string $owner, array $validated): ?Branch { if (! empty($validated['branch_id'])) { return Branch::owned($owner) ->where('organization_id', $organizationId) ->where('id', (int) $validated['branch_id']) ->first(); } $branchName = trim((string) ($validated['branch_name'] ?? '')); if ($branchName === '') { return null; } return Branch::owned($owner) ->where('organization_id', $organizationId) ->whereRaw('LOWER(name) = ?', [strtolower($branchName)]) ->first(); } /** * @param array $validated */ protected function syncQueues(Counter $counter, string $owner, array $validated): void { $uuids = $validated['queue_uuids'] ?? $validated['queue_ids'] ?? null; if ($uuids === null) { return; } $queueIds = ServiceQueue::owned($owner)->whereIn('uuid', $uuids)->pluck('id'); $counter->serviceQueues()->sync($queueIds); } /** * @return array */ protected function serializeCounter(Counter $c): array { return [ 'uuid' => $c->uuid, 'name' => $c->name, 'code' => $c->code, 'destination' => $c->displayDestination(), 'staff_ref' => $c->staff_ref, 'staff_display_name' => $c->staff_display_name, 'status' => $c->status, 'is_active' => $c->is_active, 'branch' => $c->branch?->name, 'department_id' => $c->department_id, 'external_key' => data_get($c->settings, 'external_key'), 'queues' => $c->serviceQueues->map(fn (ServiceQueue $q) => [ 'uuid' => $q->uuid, 'name' => $q->name, 'prefix' => $q->prefix, ])->values()->all(), ]; } }