diff --git a/app/Services/HR/LeaveService.php b/app/Services/HR/LeaveService.php index 388fc6b4..5c25b9e1 100644 --- a/app/Services/HR/LeaveService.php +++ b/app/Services/HR/LeaveService.php @@ -273,9 +273,27 @@ public function getBalanceSummary(?int $year = null): Collection ->keyBy('user_id'); } - // (5) Employee 정보를 balance에 연결하여 반환 + // (5) Employee 정보를 balance에 연결 $employeesByUserId = $employees->keyBy('user_id'); + // (6) 현재연도 + 1년 미만 직원은 매번 재계산 (월별 발생 방식) + if ($year === (int) now()->year) { + foreach ($existingBalances as $balance) { + $employee = $employeesByUserId->get($balance->user_id); + if (! $employee || ! $employee->hire_date) { + continue; + } + + $hire = Carbon::parse($employee->hire_date); + if ($hire->diffInMonths(today()) < 12) { + $recalculated = $this->calculateAnnualLeaveDays($employee, $year, $policy); + if (abs($balance->total_days - $recalculated) > 0.001) { + $balance->update(['total_days' => $recalculated]); + } + } + } + } + return $existingBalances ->filter(fn ($balance) => $employeesByUserId->has($balance->user_id)) ->map(function ($balance) use ($employeesByUserId) { @@ -292,7 +310,7 @@ public function getBalanceSummary(?int $year = null): Collection * 입사일 기반 연차일수 자동 산출 (근로기준법 제60조) * * - 입사일 없음 → default_annual_leave (기본 15일) - * - 1년 미만 → 근무 개월수 (최대 11일) + * - 1년 미만 → 입사일~기준일 완료 월수 (최대 11일, 월별 발생) * - 1년 이상 → 15일 + 매 2년마다 +1일 (최대 max_annual_leave) */ private function calculateAnnualLeaveDays(Employee $employee, int $year, ?LeavePolicy $policy): float @@ -306,28 +324,27 @@ private function calculateAnnualLeaveDays(Employee $employee, int $year, ?LeaveP } $hire = Carbon::parse($hireDate); - $yearStart = Carbon::create($year, 1, 1); - // 대상연도 시작일 기준 근속년수 - $yearsWorked = $hire->diffInYears($yearStart); + // 기준일: 현재연도면 오늘, 과거연도면 연말 + $referenceDate = $year === (int) now()->year + ? today() + : Carbon::create($year, 12, 31); - // 대상연도 시작 전에 입사하지 않은 경우 (입사예정) - if ($hire->greaterThanOrEqualTo($yearStart)) { - // 해당 연도 내 근무 개월수 - $yearEnd = Carbon::create($year, 12, 31); - $monthsInYear = (int) $hire->diffInMonths($yearEnd); - - return (float) min($monthsInYear, 11); + // 아직 입사 전이면 0일 + if ($hire->greaterThan($referenceDate)) { + return 0; } - // 1년 미만 (전년도 입사) - if ($yearsWorked < 1) { - $monthsWorked = (int) $hire->diffInMonths($yearStart); + // 입사일~기준일 완료 월수 + $totalMonthsWorked = (int) $hire->diffInMonths($referenceDate); - return (float) min($monthsWorked, 11); + // 1년 미만: 완료된 월수 × 1일 (최대 11일) + if ($totalMonthsWorked < 12) { + return (float) min($totalMonthsWorked, 11); } // 1년 이상: 15일 + 매 2년마다 +1일 + $yearsWorked = (int) $hire->diffInYears($referenceDate); $additionalDays = (int) floor(($yearsWorked - 1) / 2); $totalDays = $defaultDays + $additionalDays; diff --git a/resources/markdown/휴가관리가이드.md b/resources/markdown/휴가관리가이드.md index 832ffd1f..1147254b 100644 --- a/resources/markdown/휴가관리가이드.md +++ b/resources/markdown/휴가관리가이드.md @@ -22,13 +22,14 @@ ### 1.2 연차발생일수 테이블 > **참고**: 매 2년 근속 시 1일이 가산됩니다. (예: 3년차 16일, 5년차 17일, ...) -### 1.3 회계일 기준 vs 입사일 기준 +### 1.3 입사일 기준 월별 발생 -| 구분 | 회계일 기준 | 입사일 기준 | -|------|-----------|-----------| -| 1년차 (당해 입사) | 1달 만근 시 1일씩 발생 | 입사일 기준 11일 | -| 2년차 | 1달 만근분 + 1년차 비례분 | 15일 | -| 3년차~ | 15일 + 가산일 | 15일 + 가산일 | +| 구분 | 산출 방식 | 예시 | +|------|-----------|------| +| 1년 미만 | 입사일~오늘 완료 월수 × 1일 | 1/2 입사 → 2/27 기준 = 1일 | +| 1년 이상 | 15일 + 매 2년 가산 | 3년차 = 16일 | + +> **참고**: 1년 미만 직원의 부여일수는 매월 자동 갱신됩니다. 잔여연차 조회 시점의 완료 월수가 반영됩니다. --- @@ -60,7 +61,7 @@ ### 3.1 주요 항목 | 항목 | 설명 | |------|------| -| **부여** | 연초 배정된 총 연차일수 | +| **부여** | 연차 부여일수 (1년 미만: 완료 월수, 1년 이상: 근속 기반) | | **사용** | 승인 완료된 연차/반차 합계 | | **잔여** | 부여 - 사용 | | **소진율** | (사용 / 부여) x 100% |