diff --git a/app/Http/Controllers/Finance/PayableController.php b/app/Http/Controllers/Finance/PayableController.php index ac979710..b3c43e64 100644 --- a/app/Http/Controllers/Finance/PayableController.php +++ b/app/Http/Controllers/Finance/PayableController.php @@ -197,6 +197,62 @@ public function integrated(Request $request): JsonResponse $accountCodes = $account === 'all' ? ['204', '205'] : [$account]; + // 0. 이월 잔액 계산 (startDate 이전의 누적 잔액) + $priorBalanceMap = []; + + // 이월 - 홈택스 대변(발생) + $priorHometax = HometaxInvoiceJournal::where('tenant_id', $tenantId) + ->whereIn('account_code', $accountCodes) + ->where('dc_type', 'credit') + ->where('credit_amount', '>', 0) + ->where('write_date', '<', $startDate); + if ($vendor) { + $priorHometax->where('trading_partner_name', 'like', "%{$vendor}%"); + } + $priorHometax->select('trading_partner_name', 'account_code', 'account_name', DB::raw('SUM(credit_amount) as total_credit')) + ->groupBy('trading_partner_name', 'account_code', 'account_name') + ->get() + ->each(function ($row) use (&$priorBalanceMap) { + $key = $row->trading_partner_name.'|'.$row->account_code; + if (! isset($priorBalanceMap[$key])) { + $priorBalanceMap[$key] = ['vendorName' => $row->trading_partner_name, 'accountCode' => $row->account_code, 'accountName' => $row->account_name, 'occurred' => 0, 'offset' => 0]; + } + $priorBalanceMap[$key]['occurred'] += $row->total_credit; + }); + + // 이월 - 일반전표 차변(상계) + 대변(발생) + $priorJournal = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId) + ->whereIn('journal_entry_lines.account_code', $accountCodes) + ->join('journal_entries', function ($join) { + $join->on('journal_entries.id', '=', 'journal_entry_lines.journal_entry_id') + ->whereNull('journal_entries.deleted_at'); + }) + ->where('journal_entries.entry_date', '<', $startDate); + if ($vendor) { + $priorJournal->where('journal_entry_lines.trading_partner_name', 'like', "%{$vendor}%"); + } + $priorJournal->select( + 'journal_entry_lines.trading_partner_name', + 'journal_entry_lines.account_code', + 'journal_entry_lines.account_name', + 'journal_entry_lines.dc_type', + DB::raw('SUM(journal_entry_lines.debit_amount) as total_debit'), + DB::raw('SUM(journal_entry_lines.credit_amount) as total_credit') + ) + ->groupBy('journal_entry_lines.trading_partner_name', 'journal_entry_lines.account_code', 'journal_entry_lines.account_name', 'journal_entry_lines.dc_type') + ->get() + ->each(function ($row) use (&$priorBalanceMap) { + $key = $row->trading_partner_name.'|'.$row->account_code; + if (! isset($priorBalanceMap[$key])) { + $priorBalanceMap[$key] = ['vendorName' => $row->trading_partner_name, 'accountCode' => $row->account_code, 'accountName' => $row->account_name, 'occurred' => 0, 'offset' => 0]; + } + if ($row->dc_type === 'debit') { + $priorBalanceMap[$key]['offset'] += $row->total_debit; + } else { + $priorBalanceMap[$key]['occurred'] += $row->total_credit; + } + }); + // 1. 홈택스 매입세금계산서 - 대변(미지급금 발생) $hometaxQuery = HometaxInvoiceJournal::where('tenant_id', $tenantId) ->whereIn('account_code', $accountCodes) @@ -270,17 +326,18 @@ public function integrated(Request $request): JsonResponse ->orderByDesc('journal_entries.entry_date') ->get(); - // 3. 거래처별 잔액 계산 + // 3. 거래처별 잔액 계산 (이월 잔액 포함) $vendorMap = []; - // 홈택스 대변 = 발생 - foreach ($hometaxGrouped as $row) { - $key = $row->trading_partner_name.'|'.$row->account_code; + $initVendor = function ($key, $row) use (&$vendorMap, $priorBalanceMap) { if (! isset($vendorMap[$key])) { + $prior = $priorBalanceMap[$key] ?? null; + $priorBalance = $prior ? ($prior['occurred'] - $prior['offset']) : 0; $vendorMap[$key] = [ 'vendorName' => $row->trading_partner_name, 'accountCode' => $row->account_code, 'accountName' => $row->account_name, + 'priorBalance' => $priorBalance, 'occurred' => 0, 'offset' => 0, 'hometaxCount' => 0, @@ -288,6 +345,12 @@ public function integrated(Request $request): JsonResponse 'journalCreditCount' => 0, ]; } + }; + + // 홈택스 대변 = 발생 + foreach ($hometaxGrouped as $row) { + $key = $row->trading_partner_name.'|'.$row->account_code; + $initVendor($key, $row); $vendorMap[$key]['occurred'] += $row->total_credit; $vendorMap[$key]['hometaxCount'] += $row->cnt; } @@ -295,18 +358,7 @@ public function integrated(Request $request): JsonResponse // 일반전표 차변 = 상계, 대변 = 발생 foreach ($journalGrouped as $row) { $key = $row->trading_partner_name.'|'.$row->account_code; - if (! isset($vendorMap[$key])) { - $vendorMap[$key] = [ - 'vendorName' => $row->trading_partner_name, - 'accountCode' => $row->account_code, - 'accountName' => $row->account_name, - 'occurred' => 0, - 'offset' => 0, - 'hometaxCount' => 0, - 'journalDebitCount' => 0, - 'journalCreditCount' => 0, - ]; - } + $initVendor($key, $row); if ($row->dc_type === 'debit') { $vendorMap[$key]['offset'] += $row->total_debit; $vendorMap[$key]['journalDebitCount'] += $row->cnt; @@ -316,14 +368,35 @@ public function integrated(Request $request): JsonResponse } } - // 잔액 계산 및 정렬 + // 이월 잔액만 있고 당기 거래가 없는 거래처도 포함 + foreach ($priorBalanceMap as $key => $prior) { + if (! isset($vendorMap[$key])) { + $priorBalance = $prior['occurred'] - $prior['offset']; + if ($priorBalance != 0) { + $vendorMap[$key] = [ + 'vendorName' => $prior['vendorName'], + 'accountCode' => $prior['accountCode'], + 'accountName' => $prior['accountName'], + 'priorBalance' => $priorBalance, + 'occurred' => 0, + 'offset' => 0, + 'hometaxCount' => 0, + 'journalDebitCount' => 0, + 'journalCreditCount' => 0, + ]; + } + } + } + + // 잔액 계산 및 정렬: 이월잔액 + 당기발생 - 당기상계 $byVendor = collect($vendorMap)->map(function ($item) { - $item['balance'] = $item['occurred'] - $item['offset']; + $item['balance'] = $item['priorBalance'] + $item['occurred'] - $item['offset']; return $item; })->sortByDesc('balance')->values()->all(); // 4. 요약 통계 + $totalPriorBalance = array_sum(array_column($byVendor, 'priorBalance')); $totalOccurred = array_sum(array_column($byVendor, 'occurred')); $totalOffset = array_sum(array_column($byVendor, 'offset')); @@ -331,9 +404,10 @@ public function integrated(Request $request): JsonResponse 'success' => true, 'data' => [ 'summary' => [ + 'totalPriorBalance' => $totalPriorBalance, 'totalOccurred' => $totalOccurred, 'totalOffset' => $totalOffset, - 'totalBalance' => $totalOccurred - $totalOffset, + 'totalBalance' => $totalPriorBalance + $totalOccurred - $totalOffset, 'hometaxCount' => $hometaxDetails->count(), 'journalCount' => $journalDetails->count(), 'vendorCount' => count($byVendor), diff --git a/resources/views/finance/payables.blade.php b/resources/views/finance/payables.blade.php index def0f907..a14715a1 100644 --- a/resources/views/finance/payables.blade.php +++ b/resources/views/finance/payables.blade.php @@ -89,10 +89,20 @@ function IntegratedTab({ startDate, endDate, account, vendorSearch }) { return (
{formatCurrency(summary.totalPriorBalance)}원
+전월까지 누적 잔액
+{formatCurrency(summary.totalOccurred)}원
@@ -100,7 +110,7 @@ function IntegratedTab({ startDate, endDate, account, vendorSearch }) {{formatCurrency(summary.totalOffset)}원
@@ -114,7 +124,7 @@ function IntegratedTab({ startDate, endDate, account, vendorSearch }) {= 0 ? 'text-rose-600' : 'text-blue-600'}`}> {summary.totalBalance < 0 && '-'}{formatCurrency(Math.abs(summary.totalBalance))}원
-발생 - 상계
+이월 + 발생 - 상계