fix: [finance] 분리 카드거래를 개별 행으로 확장 표시

- 백엔드: 분리 항목을 CardTransactionSplit에서 조회하여 개별 행으로 확장
- 프론트: 분리#N 배지 추가, 각 분리 행이 자체 분개 표시
This commit is contained in:
김보곤
2026-03-19 22:36:56 +09:00
parent 140894ef9c
commit f068c96971
2 changed files with 78 additions and 81 deletions

View File

@@ -1008,11 +1008,63 @@ public function cardTransactions(Request $request): JsonResponse
// 각 거래의 uniqueKey 수집
$uniqueKeys = array_column($logs, 'uniqueKey');
// 분개 완료된 source_key 조회 (직접 매칭)
$journaledKeys = JournalEntry::getJournaledSourceKeys($tenantId, 'ecard_transaction', $uniqueKeys);
// 분리 데이터 조회 (uniqueKey별 splits)
$splitsGrouped = [];
if (! empty($uniqueKeys)) {
$splits = CardTransactionSplit::where('tenant_id', $tenantId)
->whereIn('original_unique_key', $uniqueKeys)
->orderBy('original_unique_key')
->orderBy('sort_order')
->get();
foreach ($splits as $s) {
$splitsGrouped[$s->original_unique_key][] = $s;
}
}
// 분리 거래 확장: 분리가 있는 카드거래는 분리 항목별 행으로 교체
$expandedLogs = [];
foreach ($logs as $log) {
$key = $log['uniqueKey'];
$logSplits = $splitsGrouped[$key] ?? [];
if (! empty($logSplits)) {
// 분리 거래: 각 split을 별도 행으로 확장
foreach ($logSplits as $split) {
$splitSupply = (int) ($split->split_supply_amount ?? 0);
$splitTax = (int) ($split->split_tax ?? 0);
$splitAmount = $splitSupply + $splitTax;
$expandedLogs[] = array_merge($log, [
'uniqueKey' => $key.'|split:'.$split->id,
'parentUniqueKey' => $key,
'isSplit' => true,
'splitIndex' => $split->sort_order + 1,
'splitTotal' => count($logSplits),
'merchantName' => $split->description ?: $log['merchantName'],
'deductionType' => $split->deduction_type ?? $log['deductionType'],
'supplyAmount' => $splitSupply,
'taxAmount' => $splitTax,
'approvalAmount' => $splitAmount,
'accountCode' => $split->account_code ?? $log['accountCode'],
'accountName' => $split->account_name ?? $log['accountName'],
]);
}
} else {
// 분리 없음: 원본 그대로
$log['isSplit'] = false;
$expandedLogs[] = $log;
}
}
$logs = $expandedLogs;
// 확장된 uniqueKey 수집
$allSourceKeys = array_column($logs, 'uniqueKey');
// 분개 완료된 source_key 조회 (직접 + 분리 키 모두 포함)
$journaledKeys = JournalEntry::getJournaledSourceKeys($tenantId, 'ecard_transaction', $allSourceKeys);
$journaledKeysMap = array_flip($journaledKeys);
// 분개된 전표 ID 조회 (직접 매칭)
// 분개된 전표 ID 조회
$journalMap = [];
if (! empty($journaledKeys)) {
$journals = JournalEntry::where('tenant_id', $tenantId)
@@ -1025,59 +1077,13 @@ public function cardTransactions(Request $request): JsonResponse
}
}
// 분리 거래의 분개 상태 조회 (source_key LIKE 'uniqueKey|split:%')
$splitJournalMap = []; // originalKey => [['id' => ..., 'entry_no' => ...], ...]
if (! empty($uniqueKeys)) {
$splitJournals = JournalEntry::where('tenant_id', $tenantId)
->where('source_type', 'ecard_transaction')
->where(function ($q) use ($uniqueKeys) {
foreach ($uniqueKeys as $key) {
$q->orWhere('source_key', 'LIKE', $key.'|split:%');
}
})
->select('id', 'source_key', 'entry_no')
->get();
foreach ($splitJournals as $j) {
$originalKey = explode('|split:', $j->source_key)[0];
$splitJournalMap[$originalKey][] = ['id' => $j->id, 'entry_no' => $j->entry_no];
}
}
// 분리 건수 조회 (전체 분개 완료 여부 판단용)
$splitCounts = [];
if (! empty($uniqueKeys)) {
$counts = CardTransactionSplit::where('tenant_id', $tenantId)
->whereIn('original_unique_key', $uniqueKeys)
->selectRaw('original_unique_key, COUNT(*) as cnt')
->groupBy('original_unique_key')
->pluck('cnt', 'original_unique_key');
$splitCounts = $counts->toArray();
}
// 각 거래에 분개 상태 추가
$journaledCount = 0;
foreach ($logs as &$log) {
$key = $log['uniqueKey'] ?? '';
$directMatch = isset($journaledKeysMap[$key]);
$splitCount = $splitCounts[$key] ?? 0;
$splitJournals = $splitJournalMap[$key] ?? [];
$allSplitsJournaled = $splitCount > 0 && count($splitJournals) >= $splitCount;
$log['hasJournal'] = $directMatch || $allSplitsJournaled;
$log['splitJournalIds'] = [];
if ($directMatch) {
$log['journalId'] = $journalMap[$key]['id'] ?? null;
$log['journalEntryNo'] = $journalMap[$key]['entry_no'] ?? null;
} elseif (! empty($splitJournals)) {
$log['journalId'] = $splitJournals[0]['id'];
$log['journalEntryNo'] = $splitJournals[0]['entry_no'];
$log['splitJournalIds'] = array_column($splitJournals, 'id');
} else {
$log['journalId'] = null;
$log['journalEntryNo'] = null;
}
$log['hasJournal'] = isset($journaledKeysMap[$key]);
$log['journalId'] = $journalMap[$key]['id'] ?? null;
$log['journalEntryNo'] = $journalMap[$key]['entry_no'] ?? null;
if ($log['hasJournal']) {
$journaledCount++;
@@ -1085,12 +1091,18 @@ public function cardTransactions(Request $request): JsonResponse
}
unset($log);
// 통계
$totalCount = count($logs);
$totalAmount = array_sum(array_column($logs, 'approvalAmount'));
// 통계 (원본 거래 기준)
$originalLogs = array_filter($logs, fn ($l) => ! ($l['isSplit'] ?? false));
$splitParentKeys = array_unique(array_column(
array_filter($logs, fn ($l) => ($l['isSplit'] ?? false) && ($l['splitIndex'] ?? 0) === 1),
'parentUniqueKey'
));
$totalCount = count($originalLogs) + count($splitParentKeys);
$totalAmount = 0;
$deductibleSum = 0;
$nonDeductibleSum = 0;
foreach ($logs as $log) {
$totalAmount += $log['approvalAmount'];
if ($log['deductionType'] === 'non_deductible') {
$nonDeductibleSum += $log['approvalAmount'];
} else {