departmentRepository()->list(); } public function listPaged(array $options): array { if (!empty($options['tenantUserId'])) { $tenantUserId = (int) $options['tenantUserId']; if ($tenantUserId > 0 && $this->scopeGateway()->hasGlobalAccess($tenantUserId)) { unset($options['tenantUserId'], $options['tenantIds']); } } return $this->departmentRepository()->listPaged($options); } public function listByTenantIds(array $tenantIds): array { return $this->departmentRepository()->listByTenantIds($tenantIds); } public function groupActiveByTenantIds(array $tenantIds): array { $tenantIds = array_values(array_unique(array_map('intval', $tenantIds))); $tenantIds = array_values(array_filter($tenantIds, static fn ($id) => $id > 0)); if (!$tenantIds) { return []; } $departments = $this->listByTenantIds($tenantIds); if (!$departments) { return []; } $grouped = []; foreach ($departments as $department) { $tenantId = (int) ($department['tenant_id'] ?? 0); if ($tenantId <= 0) { continue; } $grouped[$tenantId] ??= []; $grouped[$tenantId][] = $department; } foreach ($grouped as &$items) { usort($items, static function (array $a, array $b): int { return strcmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? '')); }); } unset($items); return $grouped; } public function listByIds(array $departmentIds): array { return $this->departmentRepository()->listByIds($departmentIds); } public function listForUserAssignments(array $tenantIds, array $selectedDepartmentIds): array { $departments = $tenantIds ? $this->listByTenantIds($tenantIds) : $this->list(); $extraDepartments = $selectedDepartmentIds ? $this->listByIds($selectedDepartmentIds) : []; if (!$extraDepartments) { return $departments; } $departmentMap = []; foreach ($departments as $department) { if (isset($department['id'])) { $departmentMap[(int) $department['id']] = $department; } } foreach ($extraDepartments as $department) { if (isset($department['id'])) { $departmentMap[(int) $department['id']] = $department; } } return array_values($departmentMap); } public function findByUuid(string $uuid): ?array { return $this->departmentRepository()->findByUuid($uuid); } public function findById(int $id): ?array { return $this->departmentRepository()->find($id); } public function createFromAdmin(array $input, int $currentUserId = 0): array { $form = $this->sanitizeBase($input); $errors = $this->validateBase($form); $warnings = $this->warningsForCode($form, 0); if ($errors) { return ['ok' => false, 'errors' => $errors, 'warnings' => $warnings, 'form' => $form]; } $createdId = $this->departmentRepository()->create([ 'description' => $form['description'], 'tenant_id' => $form['tenant_id'], 'code' => $form['code'] ?: null, 'cost_center' => $form['cost_center'] ?: null, 'active' => $form['active'], 'created_by' => $currentUserId > 0 ? $currentUserId : null, ]); if (!$createdId) { return ['ok' => false, 'errors' => [t('Department can not be created')], 'form' => $form]; } $createdDepartment = $this->departmentRepository()->find((int) $createdId); $uuid = $createdDepartment['uuid'] ?? null; if (!empty($input['is_default'])) { $this->settingsGateway()->setDefaultDepartmentId((int) $createdId); } return ['ok' => true, 'form' => $form, 'warnings' => $warnings, 'uuid' => $uuid, 'id' => (int) $createdId]; } public function updateFromAdmin(int $departmentId, array $input, int $currentUserId = 0): array { $form = $this->sanitizeBase($input); $errors = $this->validateBase($form); $warnings = $this->warningsForCode($form, $departmentId); if ($errors) { return ['ok' => false, 'errors' => $errors, 'warnings' => $warnings, 'form' => $form]; } $updated = $this->departmentRepository()->update($departmentId, [ 'description' => $form['description'], 'tenant_id' => $form['tenant_id'], 'code' => $form['code'] ?: null, 'cost_center' => $form['cost_center'] ?: null, 'active' => $form['active'], 'modified_by' => $currentUserId > 0 ? $currentUserId : null, ]); if (!$updated) { return ['ok' => false, 'errors' => [t('Department can not be updated')], 'form' => $form]; } return ['ok' => true, 'form' => $form, 'warnings' => $warnings]; } public function syncTenant(int $departmentId, int $tenantId): int { $updated = $this->departmentRepository()->setTenant($departmentId, $tenantId); if (!$updated) { return -1; } return $this->cleanupUserAssignments($departmentId); } public function syncTenants(int $departmentId, array $tenantIds): int { $tenantId = (int) ($tenantIds[0] ?? 0); if ($tenantId <= 0) { return -1; } return $this->syncTenant($departmentId, $tenantId); } public function cleanupUserAssignments(int $departmentId): int { return $this->userServicesFactory() ->createUserDepartmentRepository() ->removeInvalidForDepartment($departmentId); } public function deleteByUuid(string $uuid): array { $uuid = trim($uuid); if ($uuid === '') { return ['ok' => false, 'status' => 404, 'error' => 'not_found']; } $department = $this->departmentRepository()->findByUuid($uuid); if (!$department || !isset($department['id'])) { return ['ok' => false, 'status' => 404, 'error' => 'not_found']; } $deleted = $this->departmentRepository()->delete((int) $department['id']); if (!$deleted) { return ['ok' => false, 'status' => 500, 'error' => 'delete_failed']; } return ['ok' => true, 'department' => $department]; } private function sanitizeBase(array $input): array { return [ 'description' => trim((string) ($input['description'] ?? '')), 'tenant_id' => (int) ($input['tenant_id'] ?? 0), 'code' => trim((string) ($input['code'] ?? '')), 'cost_center' => trim((string) ($input['cost_center'] ?? '')), 'active' => $this->normalizeActive($input['active'] ?? 1), ]; } private function validateBase(array $form): array { $errors = []; if ($form['description'] === '') { $errors[] = t('Description cannot be empty'); } if ((int) ($form['tenant_id'] ?? 0) <= 0) { $errors[] = t('Please select at least one tenant'); } return $errors; } private function warningsForCode(array $form, int $excludeId): array { $warnings = []; $code = $form['code'] ?? ''; if ($code !== '' && $this->departmentRepository()->existsByCode($code, $excludeId)) { $warnings[] = t('Department code already exists'); } return $warnings; } private function normalizeActive($value): int { $value = strtolower(trim((string) $value)); if (in_array($value, ['0', 'false', 'inactive'], true)) { return 0; } return 1; } private function departmentRepository(): DepartmentRepository { return $this->departmentRepository ?? new DepartmentRepository(); } private function userServicesFactory(): UserServicesFactory { return $this->userServicesFactory ?? new UserServicesFactory(); } private function settingsGateway(): DirectorySettingsGateway { if ($this->settingsGateway instanceof DirectorySettingsGateway) { return $this->settingsGateway; } return new DirectorySettingsGateway( (new SettingServicesFactory())->createSettingGateway() ); } private function scopeGateway(): DirectoryScopeGateway { return $this->scopeGateway ?? new DirectoryScopeGateway(); } }