From bde4be412367775eb4664d46b111446a66518304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Tue, 10 Mar 2026 12:44:09 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20[payroll]=20=EC=A0=84=ED=91=9C=20?= =?UTF-8?q?=EA=B8=B0=ED=83=80=EA=B3=B5=EC=A0=9C=20=ED=95=AD=EB=AA=A9?= =?UTF-8?q?=EB=B3=84=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=9D=8C=EC=88=98?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기타공제를 합산 단일 라인에서 항목별(연말정산소득세, 연말정산지방소득세 등) 분리 - formatInputCurrency/parseInputCurrency 음수 부호 처리 추가 - JournalEntryController validation에서 min:0 제거하여 음수 credit_amount 허용 --- .../Api/Admin/HR/PayrollController.php | 20 ++++++++++++------- .../Finance/JournalEntryController.php | 16 +++++++-------- .../views/finance/journal-entries.blade.php | 8 ++++++-- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/Http/Controllers/Api/Admin/HR/PayrollController.php b/app/Http/Controllers/Api/Admin/HR/PayrollController.php index 9fc3335c..2ad457f6 100644 --- a/app/Http/Controllers/Api/Admin/HR/PayrollController.php +++ b/app/Http/Controllers/Api/Admin/HR/PayrollController.php @@ -749,13 +749,18 @@ public function generateJournalEntry(Request $request): JsonResponse ], 422); } - // 기타공제(deductions JSON) 합산 포함 - $extraDeductionsTotal = 0; + // 기타공제(deductions JSON) 항목별 합산 + $extraDeductionsByName = []; foreach ($payrolls as $p) { foreach ($p->deductions ?? [] as $d) { - $extraDeductionsTotal += (int) ($d['amount'] ?? 0); + $name = $d['name'] ?? '기타공제'; + $amount = (int) ($d['amount'] ?? 0); + if ($amount != 0) { + $extraDeductionsByName[$name] = ($extraDeductionsByName[$name] ?? 0) + $amount; + } } } + $extraDeductionsTotal = array_sum($extraDeductionsByName); $sums = (object) [ 'total_gross' => $payrolls->sum('gross_salary'), @@ -827,10 +832,11 @@ public function generateJournalEntry(Request $request): JsonResponse [(int) $sums->total_resident_tax, '강서구청', "{$monthLabel} 지방소득세"], ]; - // 기타공제 - $extraDeductions = (int) $sums->total_extra_deductions; - if ($extraDeductions != 0) { - $deductionItems[] = [$extraDeductions, '임직원', '기타공제']; + // 기타공제 (항목별) + foreach ($extraDeductionsByName as $deductionName => $deductionAmount) { + if ($deductionAmount != 0) { + $deductionItems[] = [$deductionAmount, '임직원', $deductionName]; + } } // 1. 차변: 801 급여 / 임직원 — 총지급액 diff --git a/app/Http/Controllers/Finance/JournalEntryController.php b/app/Http/Controllers/Finance/JournalEntryController.php index 69a81698..4b72635d 100644 --- a/app/Http/Controllers/Finance/JournalEntryController.php +++ b/app/Http/Controllers/Finance/JournalEntryController.php @@ -149,8 +149,8 @@ public function store(Request $request): JsonResponse 'lines.*.account_name' => 'required|string|max:100', 'lines.*.trading_partner_id' => 'nullable|integer', 'lines.*.trading_partner_name' => 'nullable|string|max:100', - 'lines.*.debit_amount' => 'required|integer|min:0', - 'lines.*.credit_amount' => 'required|integer|min:0', + 'lines.*.debit_amount' => 'required|integer', + 'lines.*.credit_amount' => 'required|integer', 'lines.*.description' => 'nullable|string|max:300', ]); @@ -265,8 +265,8 @@ public function update(Request $request, int $id): JsonResponse 'lines.*.account_name' => 'required|string|max:100', 'lines.*.trading_partner_id' => 'nullable|integer', 'lines.*.trading_partner_name' => 'nullable|string|max:100', - 'lines.*.debit_amount' => 'required|integer|min:0', - 'lines.*.credit_amount' => 'required|integer|min:0', + 'lines.*.debit_amount' => 'required|integer', + 'lines.*.credit_amount' => 'required|integer', 'lines.*.description' => 'nullable|string|max:300', ]); @@ -570,8 +570,8 @@ public function storeFromBank(Request $request): JsonResponse 'lines.*.account_name' => 'required|string|max:100', 'lines.*.trading_partner_id' => 'nullable|integer', 'lines.*.trading_partner_name' => 'nullable|string|max:100', - 'lines.*.debit_amount' => 'required|integer|min:0', - 'lines.*.credit_amount' => 'required|integer|min:0', + 'lines.*.debit_amount' => 'required|integer', + 'lines.*.credit_amount' => 'required|integer', 'lines.*.description' => 'nullable|string|max:300', ]); @@ -1038,8 +1038,8 @@ public function storeFromCard(Request $request): JsonResponse 'lines.*.account_name' => 'required|string|max:100', 'lines.*.trading_partner_id' => 'nullable|integer', 'lines.*.trading_partner_name' => 'nullable|string|max:100', - 'lines.*.debit_amount' => 'required|integer|min:0', - 'lines.*.credit_amount' => 'required|integer|min:0', + 'lines.*.debit_amount' => 'required|integer', + 'lines.*.credit_amount' => 'required|integer', 'lines.*.description' => 'nullable|string|max:300', ]); diff --git a/resources/views/finance/journal-entries.blade.php b/resources/views/finance/journal-entries.blade.php index b00c136b..d886a8d9 100644 --- a/resources/views/finance/journal-entries.blade.php +++ b/resources/views/finance/journal-entries.blade.php @@ -65,12 +65,16 @@ const formatCurrency = (num) => num ? Number(num).toLocaleString() : '0'; const formatInputCurrency = (value) => { if (!value && value !== 0) return ''; + const isNegative = Number(value) < 0; const num = String(value).replace(/[^\d]/g, ''); - return num ? Number(num).toLocaleString() : ''; + if (!num) return ''; + return (isNegative ? '-' : '') + Number(num).toLocaleString(); }; const parseInputCurrency = (value) => { + const isNegative = String(value).includes('-'); const num = String(value).replace(/[^\d]/g, ''); - return num ? parseInt(num, 10) : 0; + const parsed = num ? parseInt(num, 10) : 0; + return isNegative ? -parsed : parsed; }; const notify = (message, type = 'info') => {