feat: [hr] 슈퍼관리자 근태/신청 삭제 및 영구삭제 기능 추가
- AttendanceService: forceDeleteAttendance 메서드 추가 - LeaveService: deleteLeave(모든 상태), forceDeleteLeave 메서드 추가 - Controller: force 파라미터 + 슈퍼관리자 권한 분기 - 근태 테이블: 슈퍼관리자에게 삭제/영구삭제 버튼 표시 - 신청 테이블: 슈퍼관리자에게 삭제/영구삭제 버튼 표시
This commit is contained in:
@@ -334,7 +334,18 @@ public function update(Request $request, int $id): JsonResponse
|
||||
public function destroy(Request $request, int $id): JsonResponse|Response
|
||||
{
|
||||
try {
|
||||
$result = $this->attendanceService->deleteAttendance($id);
|
||||
$force = $request->boolean('force');
|
||||
|
||||
if ($force) {
|
||||
if (! auth()->user()->isSuperAdmin()) {
|
||||
return response()->json(['success' => false, 'message' => '권한이 없습니다.'], 403);
|
||||
}
|
||||
$result = $this->attendanceService->forceDeleteAttendance($id);
|
||||
$message = '근태가 영구 삭제되었습니다.';
|
||||
} else {
|
||||
$result = $this->attendanceService->deleteAttendance($id);
|
||||
$message = '근태가 삭제되었습니다.';
|
||||
}
|
||||
|
||||
if (! $result) {
|
||||
return response()->json([
|
||||
@@ -354,7 +365,7 @@ public function destroy(Request $request, int $id): JsonResponse|Response
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '근태가 삭제되었습니다.',
|
||||
'message' => $message,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
@@ -177,12 +177,27 @@ public function cancel(Request $request, int $id): JsonResponse
|
||||
}
|
||||
|
||||
/**
|
||||
* pending 상태 신청 삭제
|
||||
* 신청 삭제 (일반: pending만 / 슈퍼관리자: 모든 상태, force 영구삭제)
|
||||
*/
|
||||
public function destroy(Request $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$leave = $this->leaveService->deletePendingLeave($id);
|
||||
$force = $request->boolean('force');
|
||||
$isSuperAdmin = auth()->user()->isSuperAdmin();
|
||||
|
||||
if ($force) {
|
||||
if (! $isSuperAdmin) {
|
||||
return response()->json(['success' => false, 'message' => '권한이 없습니다.'], 403);
|
||||
}
|
||||
$leave = $this->leaveService->forceDeleteLeave($id);
|
||||
$message = '신청이 영구 삭제되었습니다.';
|
||||
} elseif ($isSuperAdmin) {
|
||||
$leave = $this->leaveService->deleteLeave($id);
|
||||
$message = '신청이 삭제되었습니다.';
|
||||
} else {
|
||||
$leave = $this->leaveService->deletePendingLeave($id);
|
||||
$message = '신청이 삭제되었습니다.';
|
||||
}
|
||||
|
||||
if (! $leave) {
|
||||
return response()->json([
|
||||
@@ -193,7 +208,7 @@ public function destroy(Request $request, int $id): JsonResponse
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '신청이 삭제되었습니다.',
|
||||
'message' => $message,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
@@ -288,6 +288,26 @@ public function deleteAttendance(int $id): bool
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 근태 영구삭제 (슈퍼관리자 전용)
|
||||
*/
|
||||
public function forceDeleteAttendance(int $id): bool
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
$attendance = Attendance::withTrashed()
|
||||
->forTenant($tenantId)
|
||||
->find($id);
|
||||
|
||||
if (! $attendance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$attendance->forceDelete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 일괄 삭제
|
||||
*/
|
||||
|
||||
@@ -275,6 +275,89 @@ public function deletePendingLeave(int $id): ?Leave
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 휴가/신청 삭제 (슈퍼관리자 전용 — 모든 상태 허용)
|
||||
*/
|
||||
public function deleteLeave(int $id): ?Leave
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
$leave = Leave::query()
|
||||
->forTenant($tenantId)
|
||||
->find($id);
|
||||
|
||||
if (! $leave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($leave, $tenantId) {
|
||||
// 연결된 결재 취소 시도
|
||||
if ($leave->approval_id) {
|
||||
$approval = Approval::find($leave->approval_id);
|
||||
if ($approval && in_array($approval->status, ['draft', 'pending'])) {
|
||||
try {
|
||||
app(ApprovalService::class)->cancel($approval->id);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 승인된 연차 차감 복원
|
||||
if ($leave->status === 'approved' && $leave->is_deductible) {
|
||||
$balance = LeaveBalance::query()
|
||||
->forTenant($tenantId)
|
||||
->forUser($leave->user_id)
|
||||
->forYear($leave->start_date->year)
|
||||
->first();
|
||||
$balance?->restoreLeave($leave->days);
|
||||
}
|
||||
|
||||
$leave->update(['deleted_by' => auth()->id()]);
|
||||
$leave->delete();
|
||||
|
||||
return $leave;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 휴가/신청 영구삭제 (슈퍼관리자 전용)
|
||||
*/
|
||||
public function forceDeleteLeave(int $id): ?Leave
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
$leave = Leave::withTrashed()
|
||||
->forTenant($tenantId)
|
||||
->find($id);
|
||||
|
||||
if (! $leave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($leave, $tenantId) {
|
||||
// 승인된 연차 차감 복원 (아직 soft-deleted 아닌 경우)
|
||||
if ($leave->status === 'approved' && $leave->is_deductible && ! $leave->trashed()) {
|
||||
$balance = LeaveBalance::query()
|
||||
->forTenant($tenantId)
|
||||
->forUser($leave->user_id)
|
||||
->forYear($leave->start_date->year)
|
||||
->first();
|
||||
$balance?->restoreLeave($leave->days);
|
||||
}
|
||||
|
||||
// 연결된 결재 정리
|
||||
if ($leave->approval_id) {
|
||||
$approval = Approval::withTrashed()->find($leave->approval_id);
|
||||
$approval?->forceDelete();
|
||||
}
|
||||
|
||||
$leave->forceDelete();
|
||||
|
||||
return $leave;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재 승인에 의한 휴가/근태신청/사유서 자동 승인
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user