queries->forSource('operations_replica'); $flowers = $query->select( 'SELECT TOP (2) Id, name, flowerName, deptId, status, empStatus, leaveDate FROM rpt.hr_flowerName_book WHERE flowerNameId = ? AND leaveDate IS NULL ORDER BY Id DESC', [$userId] ); if (count($flowers) !== 1) { return null; } $flower = $flowers[0]; if ($this->isResigned($flower['status'] ?? null) || $this->isResigned($flower['empStatus'] ?? null)) { return null; } if ($query->first('SELECT TOP (1) userid FROM rpt.hr_employee_dimission WHERE userid = ?', [$userId])) { return null; } $employees = $query->select('SELECT TOP (2) active, dept_id_list FROM rpt.hr_employee WHERE userid = ?', [$userId]); if (count($employees) > 1 || (isset($employees[0]['active']) && ! (bool) $employees[0]['active'])) { return null; } $registrations = $query->select( 'SELECT TOP (20) [sys01-employeeStatus] AS employment_status, [sys00-deptIds] AS department_ids, [sys00-mainDeptId] AS main_department_id FROM rpt.hr_employee_register WHERE userid = ?', [$userId] ); if (count($registrations) === 20) { return null; } $departmentIds = $this->departmentIds($flower['deptId'] ?? null); foreach ($employees as $employee) { $departmentIds = array_merge($departmentIds, $this->departmentIds($employee['dept_id_list'] ?? null)); } foreach ($registrations as $registration) { if ($this->isResigned($registration['employment_status'] ?? null)) { return null; } $departmentIds = array_merge($departmentIds, $this->departmentIds($registration['department_ids'] ?? null), $this->departmentIds($registration['main_department_id'] ?? null)); } $departmentIds = array_values(array_unique($departmentIds)); if ($departmentIds === [] || count($departmentIds) > 64) { return null; } $placeholders = implode(',', array_fill(0, count($departmentIds), '?')); $ancestors = $query->select( 'WITH lineage AS ( SELECT Id, parent_id, 0 AS depth FROM rpt.hr_groups WHERE Id IN ('.$placeholders.') UNION ALL SELECT parent.Id, parent.parent_id, child.depth + 1 FROM rpt.hr_groups parent JOIN lineage child ON parent.Id = child.parent_id WHERE child.depth < 20 ) SELECT TOP (2048) Id, parent_id, depth FROM lineage', $departmentIds ); if (count($ancestors) === 2048 || array_filter($ancestors, fn ($row) => (int) $row['depth'] >= 20)) { return null; } $allowed = array_map('strval', config('dingtalk.finance_department_ids', [])); if (! self::isDesignatedSuperAdmin($userId) && ! array_intersect($allowed, array_map('strval', array_column($ancestors, 'Id')))) { return null; } return [ 'roster_id' => (string) $flower['Id'], 'display_name' => trim((string) ($flower['flowerName'] ?: $flower['name'])), 'department_ids' => $departmentIds, ]; } private function isResigned(mixed $value): bool { $status = trim((string) $value); return $status === '5' || preg_match('/离职|停用|退休/u', $status) === 1; } private function departmentIds(mixed $value): array { $value = trim((string) $value); $parts = json_decode($value, true); if (! is_array($parts)) { $parts = preg_split('/[\[\]\/>,,;;||\s]+/u', $value, -1, PREG_SPLIT_NO_EMPTY); } return array_values(array_filter(array_map( fn ($id) => is_scalar($id) ? trim((string) $id) : '', $parts ), fn ($id) => ctype_digit($id) && (int) $id > 0)); } }