fix: [payroll] 급여 등록 중복 체크 Race Condition 수정
- 중복 체크를 트랜잭션 내부로 이동 + lockForUpdate() - UniqueConstraintViolationException 방어 처리 (500→422)
This commit is contained in:
@@ -103,6 +103,11 @@ public function store(Request $request): JsonResponse
|
||||
'success' => false,
|
||||
'message' => $e->getMessage(),
|
||||
], 422);
|
||||
} catch (\Illuminate\Database\UniqueConstraintViolationException $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '해당 직원의 동일 기간 급여가 이미 등록되어 있습니다.',
|
||||
], 422);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
|
||||
|
||||
@@ -110,25 +110,25 @@ public function storePayroll(array $data): Payroll
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
|
||||
// 동일 대상/기간 중복 체크 (soft-deleted 포함 — DB 유니크 제약과 일치)
|
||||
$existing = Payroll::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('user_id', $data['user_id'])
|
||||
->where('pay_year', $data['pay_year'])
|
||||
->where('pay_month', $data['pay_month'])
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
if ($existing->trashed()) {
|
||||
$existing->forceDelete();
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
"해당 직원의 {$data['pay_year']}년 {$data['pay_month']}월 급여가 이미 등록되어 있습니다."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($data, $tenantId) {
|
||||
// 동일 대상/기간 중복 체크 (트랜잭션 내 + 행 잠금으로 Race Condition 방지)
|
||||
$existing = Payroll::withTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('user_id', $data['user_id'])
|
||||
->where('pay_year', $data['pay_year'])
|
||||
->where('pay_month', $data['pay_month'])
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
if ($existing->trashed()) {
|
||||
$existing->forceDelete();
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
"해당 직원의 {$data['pay_year']}년 {$data['pay_month']}월 급여가 이미 등록되어 있습니다."
|
||||
);
|
||||
}
|
||||
}
|
||||
$familyCount = $data['family_count'] ?? $this->resolveFamilyCount($data['user_id']);
|
||||
$calculated = $this->calculateAmounts($data, null, $familyCount);
|
||||
$this->applyDeductionOverrides($calculated, $data['deduction_overrides'] ?? null);
|
||||
|
||||
Reference in New Issue
Block a user