with(['user', 'user.tenantProfiles' => fn ($q) => $q->where('tenant_id', $tenantId), 'approver']) ->forTenant($tenantId) ->orderByRaw("FIELD(status, 'pending', 'approved', 'rejected')") ->orderBy('created_at', 'desc'); if (! empty($filters['status'])) { $query->where('status', $filters['status']); } if (! empty($filters['user_id'])) { $query->where('user_id', $filters['user_id']); } return $query->paginate($perPage); } /** * 신청 등록 */ public function storeRequest(array $data): AttendanceRequest { $tenantId = session('selected_tenant_id'); return AttendanceRequest::create([ 'tenant_id' => $tenantId, 'user_id' => $data['user_id'], 'request_type' => $data['request_type'], 'start_date' => $data['start_date'], 'end_date' => $data['end_date'], 'reason' => $data['reason'] ?? null, 'status' => 'pending', 'json_details' => $data['json_details'] ?? null, ]); } /** * 승인 처리 */ public function approve(int $id): ?AttendanceRequest { $tenantId = session('selected_tenant_id'); $request = AttendanceRequest::query() ->forTenant($tenantId) ->where('status', 'pending') ->find($id); if (! $request) { return null; } return DB::transaction(function () use ($request, $tenantId) { $request->update([ 'status' => 'approved', 'approved_by' => auth()->id(), 'approved_at' => now(), ]); // 승인 시 해당 기간의 근태 레코드 자동 생성 $this->createAttendanceRecords($request, $tenantId); return $request->fresh(['user', 'approver']); }); } /** * 반려 처리 */ public function reject(int $id, ?string $reason = null): ?AttendanceRequest { $tenantId = session('selected_tenant_id'); $request = AttendanceRequest::query() ->forTenant($tenantId) ->where('status', 'pending') ->find($id); if (! $request) { return null; } $request->update([ 'status' => 'rejected', 'approved_by' => auth()->id(), 'approved_at' => now(), 'reject_reason' => $reason, ]); return $request->fresh(['user', 'approver']); } /** * 승인 후 근태 레코드 자동 생성 */ private function createAttendanceRecords(AttendanceRequest $request, int $tenantId): void { $statusMap = [ 'vacation' => 'vacation', 'businessTrip' => 'businessTrip', 'remote' => 'remote', 'fieldWork' => 'fieldWork', ]; $status = $statusMap[$request->request_type] ?? $request->request_type; $period = CarbonPeriod::create($request->start_date, $request->end_date); foreach ($period as $date) { // 주말 제외 if ($date->isWeekend()) { continue; } Attendance::updateOrCreate( [ 'tenant_id' => $tenantId, 'user_id' => $request->user_id, 'base_date' => $date->toDateString(), ], [ 'status' => $status, 'remarks' => $request->reason ? mb_substr($request->reason, 0, 100) : null, 'updated_by' => auth()->id(), ] ); } } }