diff --git a/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php b/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php new file mode 100644 index 00000000..0a3957d9 --- /dev/null +++ b/app/Http/Controllers/Api/Admin/HR/EmployeeSalaryController.php @@ -0,0 +1,134 @@ +user()->name, self::ALLOWED_SALARY_USERS)) { + return response()->json([ + 'success' => false, + 'message' => '연봉 정보는 권한이 있는 관계자만 열람할 수 있습니다.', + ], 403); + } + + return null; + } + + /** + * 사원 연봉 정보 조회 + */ + public function show(int $id): JsonResponse + { + if ($denied = $this->checkSalaryAccess()) { + return $denied; + } + + $employee = Employee::forTenant()->find($id); + + if (! $employee) { + return response()->json([ + 'success' => false, + 'message' => '사원 정보를 찾을 수 없습니다.', + ], 404); + } + + return response()->json([ + 'success' => true, + 'data' => $employee->getSalaryInfo(), + ]); + } + + /** + * 사원 연봉 정보 저장/수정 + */ + public function update(Request $request, int $id): JsonResponse + { + if ($denied = $this->checkSalaryAccess()) { + return $denied; + } + + $validated = $request->validate([ + 'annual_salary' => 'nullable|integer|min:0', + 'effective_date' => 'nullable|date', + 'notes' => 'nullable|string|max:500', + ]); + + $employee = Employee::forTenant()->find($id); + + if (! $employee) { + return response()->json([ + 'success' => false, + 'message' => '사원 정보를 찾을 수 없습니다.', + ], 404); + } + + try { + $employee->setSalaryInfo($validated); + $employee->save(); + + return response()->json([ + 'success' => true, + 'message' => '연봉 정보가 저장되었습니다.', + 'data' => $employee->getSalaryInfo(), + ]); + } catch (\Throwable $e) { + report($e); + + return response()->json([ + 'success' => false, + 'message' => '연봉 정보 저장 중 오류가 발생했습니다.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + + /** + * 연봉 이력 삭제 (특정 인덱스) + */ + public function deleteHistory(Request $request, int $id, int $historyIndex): JsonResponse + { + if ($denied = $this->checkSalaryAccess()) { + return $denied; + } + + $employee = Employee::forTenant()->find($id); + + if (! $employee) { + return response()->json([ + 'success' => false, + 'message' => '사원 정보를 찾을 수 없습니다.', + ], 404); + } + + $salaryInfo = $employee->getSalaryInfo(); + $history = $salaryInfo['history'] ?? []; + + if (! isset($history[$historyIndex])) { + return response()->json([ + 'success' => false, + 'message' => '해당 이력을 찾을 수 없습니다.', + ], 404); + } + + array_splice($history, $historyIndex, 1); + $salaryInfo['history'] = $history; + + $employee->setJsonExtraValue('salary_info', $salaryInfo); + $employee->save(); + + return response()->json([ + 'success' => true, + 'message' => '이력이 삭제되었습니다.', + 'data' => $employee->getSalaryInfo(), + ]); + } +} diff --git a/app/Http/Controllers/HR/EmployeeController.php b/app/Http/Controllers/HR/EmployeeController.php index 635c3346..7d310515 100644 --- a/app/Http/Controllers/HR/EmployeeController.php +++ b/app/Http/Controllers/HR/EmployeeController.php @@ -9,10 +9,17 @@ class EmployeeController extends Controller { + private const ALLOWED_SALARY_USERS = ['이의찬', '전진선', '김보곤']; + public function __construct( private EmployeeService $employeeService ) {} + private function canViewSalary(): bool + { + return in_array(auth()->user()->name, self::ALLOWED_SALARY_USERS); + } + /** * 사원 목록 페이지 */ @@ -62,9 +69,13 @@ public function show(int $id): View ->orderBy('created_at', 'desc') ->get(); + $canViewSalary = $this->canViewSalary(); + return view('hr.employees.show', [ 'employee' => $employee, 'files' => $files, + 'canViewSalary' => $canViewSalary, + 'salaryInfo' => $canViewSalary ? $employee->getSalaryInfo() : null, ]); } @@ -89,6 +100,8 @@ public function edit(int $id): View ->orderBy('created_at', 'desc') ->get(); + $canViewSalary = $this->canViewSalary(); + return view('hr.employees.edit', [ 'employee' => $employee, 'departments' => $departments, @@ -96,6 +109,8 @@ public function edit(int $id): View 'titles' => $titles, 'banks' => config('banks', []), 'files' => $files, + 'canViewSalary' => $canViewSalary, + 'salaryInfo' => $canViewSalary ? $employee->getSalaryInfo() : null, ]); } } diff --git a/app/Models/HR/Employee.php b/app/Models/HR/Employee.php index 64cf438f..9550cc74 100644 --- a/app/Models/HR/Employee.php +++ b/app/Models/HR/Employee.php @@ -174,6 +174,58 @@ public function setJsonExtraValue(string $key, mixed $value): void $this->json_extra = $extra; } + // ========================================================================= + // 연봉 정보 (salary_info) — 민감 데이터, 별도 접근 제어 + // ========================================================================= + + public function getSalaryInfo(): array + { + return $this->json_extra['salary_info'] ?? [ + 'annual_salary' => null, + 'effective_date' => null, + 'notes' => null, + 'history' => [], + ]; + } + + public function setSalaryInfo(array $data): void + { + $current = $this->getSalaryInfo(); + $history = $current['history'] ?? []; + + // 기존 연봉이 있으면 이력에 추가 + if ($current['annual_salary'] !== null) { + $history[] = [ + 'annual_salary' => $current['annual_salary'], + 'effective_date' => $current['effective_date'], + 'notes' => $current['notes'], + 'recorded_at' => now()->format('Y-m-d H:i:s'), + 'recorded_by' => auth()->user()?->name ?? '-', + ]; + } + + $this->setJsonExtraValue('salary_info', [ + 'annual_salary' => $data['annual_salary'] ?? null, + 'effective_date' => $data['effective_date'] ?? null, + 'notes' => $data['notes'] ?? null, + 'history' => $history, + ]); + } + + /** + * toArray 시 salary_info 제거 (일반 API 응답에서 연봉 정보 노출 방지) + */ + public function toArray(): array + { + $array = parent::toArray(); + + if (isset($array['json_extra']['salary_info'])) { + unset($array['json_extra']['salary_info']); + } + + return $array; + } + // ========================================================================= // 스코프 // ========================================================================= diff --git a/resources/views/hr/employees/edit.blade.php b/resources/views/hr/employees/edit.blade.php index fffb5dac..28652cc7 100644 --- a/resources/views/hr/employees/edit.blade.php +++ b/resources/views/hr/employees/edit.blade.php @@ -371,6 +371,11 @@ class="text-red-400 hover:text-red-600 shrink-0 ml-2" title="삭제"> {{-- 업로드 진행 상태 --}}
| 연봉 | +적용일 | +비고 | +기록일 | +기록자 | +
|---|---|---|---|---|
| + | + | + | + | + |