diff --git a/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php b/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php index 417eb39e..76a4b543 100644 --- a/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php +++ b/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php @@ -61,6 +61,8 @@ public function update(Request $request, int $id): JsonResponse $validated = $request->validate([ 'annual_salary' => 'nullable|integer|min:0', + 'meal_allowance' => 'nullable|integer|min:0|max:1000000', + 'fixed_overtime_hours' => 'nullable|integer|min:0|max:100', 'effective_date' => 'nullable|date', 'notes' => 'nullable|string|max:500', ]); diff --git a/app/Models/HR/Employee.php b/app/Models/HR/Employee.php index 9550cc74..083a544c 100644 --- a/app/Models/HR/Employee.php +++ b/app/Models/HR/Employee.php @@ -180,12 +180,24 @@ public function setJsonExtraValue(string $key, mixed $value): void public function getSalaryInfo(): array { - return $this->json_extra['salary_info'] ?? [ + $defaults = [ 'annual_salary' => null, 'effective_date' => null, 'notes' => null, + 'fixed_overtime_hours' => null, + 'meal_allowance' => 200000, + 'monthly_salary' => null, + 'base_salary' => null, + 'fixed_overtime_pay' => null, + 'hourly_wage' => null, + 'monthly_work_hours' => 209, + 'overtime_multiplier' => 1.5, 'history' => [], ]; + + $data = $this->json_extra['salary_info'] ?? []; + + return array_merge($defaults, $data); } public function setSalaryInfo(array $data): void @@ -197,6 +209,10 @@ public function setSalaryInfo(array $data): void if ($current['annual_salary'] !== null) { $history[] = [ 'annual_salary' => $current['annual_salary'], + 'fixed_overtime_hours' => $current['fixed_overtime_hours'], + 'meal_allowance' => $current['meal_allowance'], + 'base_salary' => $current['base_salary'], + 'fixed_overtime_pay' => $current['fixed_overtime_pay'], 'effective_date' => $current['effective_date'], 'notes' => $current['notes'], 'recorded_at' => now()->format('Y-m-d H:i:s'), @@ -204,12 +220,56 @@ public function setSalaryInfo(array $data): void ]; } - $this->setJsonExtraValue('salary_info', [ - 'annual_salary' => $data['annual_salary'] ?? null, + $annualSalary = $data['annual_salary'] ?? null; + $mealAllowance = $data['meal_allowance'] ?? 200000; + $fixedOvertimeHours = $data['fixed_overtime_hours'] ?? null; + $breakdown = $this->calculateSalaryBreakdown($annualSalary, $mealAllowance, $fixedOvertimeHours); + + $this->setJsonExtraValue('salary_info', array_merge([ + 'annual_salary' => $annualSalary, 'effective_date' => $data['effective_date'] ?? null, 'notes' => $data['notes'] ?? null, - 'history' => $history, - ]); + 'fixed_overtime_hours' => $fixedOvertimeHours, + 'meal_allowance' => $mealAllowance, + ], $breakdown, ['history' => $history])); + } + + /** + * 급여 산정 계산 + * + * 공식: (기본급 + 식대) = 월급여 × 209 / (209 + 고정연장근로시간 × 1.5) + */ + private function calculateSalaryBreakdown(?int $annualSalary, int $mealAllowance, ?int $fixedOvertimeHours): array + { + $monthlyWorkHours = 209; + $overtimeMultiplier = 1.5; + + if (! $annualSalary) { + return [ + 'monthly_salary' => null, + 'base_salary' => null, + 'fixed_overtime_pay' => null, + 'hourly_wage' => null, + 'monthly_work_hours' => $monthlyWorkHours, + 'overtime_multiplier' => $overtimeMultiplier, + ]; + } + + $monthlySalary = (int) round($annualSalary / 12); + $otFactor = ($fixedOvertimeHours ?? 0) * $overtimeMultiplier; + $basePlusMeal = (int) round($monthlySalary * $monthlyWorkHours / ($monthlyWorkHours + $otFactor)); + $baseSalary = $basePlusMeal - $mealAllowance; + $hourlyWage = (int) floor($basePlusMeal / $monthlyWorkHours); + $fixedOvertimePay = $monthlySalary - $baseSalary - $mealAllowance; + + return [ + 'monthly_salary' => $monthlySalary, + 'base_salary' => $baseSalary, + 'fixed_overtime_pay' => $fixedOvertimePay, + 'hourly_wage' => $hourlyWage, + 'monthly_work_hours' => $monthlyWorkHours, + 'overtime_multiplier' => $overtimeMultiplier, + ]; } /** diff --git a/resources/views/hr/employees/partials/salary-info.blade.php b/resources/views/hr/employees/partials/salary-info.blade.php index f53dc51c..be157734 100644 --- a/resources/views/hr/employees/partials/salary-info.blade.php +++ b/resources/views/hr/employees/partials/salary-info.blade.php @@ -26,51 +26,245 @@ class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg + {{-- ============================================================ --}} {{-- 조회 모드 --}} -
-
-
연봉
-
- - + {{-- ============================================================ --}} +
+ {{-- 기본 연봉 정보 --}} +
+
+
연봉
+
+ + +
+
+
+
적용일
+
+
+
+
비고
+
-
-
적용일
-
-
-
-
비고
-
-
+ + {{-- 급여 산정 테이블 (저장된 데이터가 있을 때) --}} +
+ {{-- ============================================================ --}} {{-- 수정 모드 --}} + {{-- ============================================================ --}}
-
- - -

+ {{-- 입력 필드 --}} +
+
+ + +
+
+ + +

비과세 한도: 200,000원

+
+
+ + +

변동값 (사원별 상이)

+
-
- - -
-
- - +
+
+ + +
+
+ + +
+ + {{-- 실시간 급여 산정 미리보기 --}} + + + {{-- 버튼 --}}
+ {{-- ============================================================ --}} {{-- 연봉 변경 이력 --}} + {{-- ============================================================ --}}