fix: [bank-transaction] uniqueKey에 적요(summary) 추가하여 동일 금액·시간 거래 구분

- BankTransaction 모델: getUniqueKeyAttribute, generateUniqueKey에 summary 추가
- EaccountController: API 응답 및 DB upsert 시 summary 포함 매칭
- JournalEntry, JournalEntryController: 레거시(5필드) 키 호환 처리
- BankTransactionOverride: 레거시 키 호환 조회
This commit is contained in:
김보곤
2026-02-23 16:02:36 +09:00
parent a1c9c68607
commit 005020f5ec
5 changed files with 324 additions and 205 deletions

View File

@@ -3,11 +3,11 @@
namespace App\Http\Controllers\Finance;
use App\Http\Controllers\Controller;
use App\Models\Barobill\AccountCode;
use App\Models\Barobill\BankTransaction;
use App\Models\Finance\JournalEntry;
use App\Models\Finance\JournalEntryLine;
use App\Models\Finance\TradingPartner;
use App\Models\Barobill\AccountCode;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -224,7 +224,7 @@ public function store(Request $request): JsonResponse
return response()->json([
'success' => false,
'message' => '전표 저장 실패: ' . $lastError->getMessage(),
'message' => '전표 저장 실패: '.$lastError->getMessage(),
], 500);
}
@@ -399,7 +399,7 @@ public function bankTransactions(Request $request): JsonResponse
$accountNum = $request->input('accountNum', '');
// barobill_bank_transactions 테이블에서 직접 조회 (중복 제거)
$normalizedAccNum = !empty($accountNum) ? str_replace('-', '', $accountNum) : null;
$normalizedAccNum = ! empty($accountNum) ? str_replace('-', '', $accountNum) : null;
$dedupQuery = BankTransaction::where('tenant_id', $tenantId)
->whereBetween('trans_date', [$startDate, $endDate]);
@@ -462,16 +462,29 @@ public function bankTransactions(Request $request): JsonResponse
$journaledKeys = JournalEntry::getJournaledSourceKeys($tenantId, 'bank_transaction', $uniqueKeys);
$journaledKeysMap = array_flip($journaledKeys);
// 분개된 전표 ID도 조회
// 분개된 전표 ID도 조회 (레거시 키 포함)
$journalMap = [];
if (!empty($journaledKeys)) {
if (! empty($journaledKeys)) {
// 새 키 + 레거시 키 모두 검색
$allSearchKeys = $journaledKeys;
$legacyMap = [];
foreach ($journaledKeys as $key) {
$parts = explode('|', $key);
if (count($parts) === 6) {
$legacyKey = implode('|', array_slice($parts, 0, 5));
$allSearchKeys[] = $legacyKey;
$legacyMap[$legacyKey] = $key;
}
}
$journals = JournalEntry::where('tenant_id', $tenantId)
->where('source_type', 'bank_transaction')
->whereIn('source_key', $journaledKeys)
->whereIn('source_key', array_unique($allSearchKeys))
->select('id', 'source_key', 'entry_no')
->get();
foreach ($journals as $j) {
$journalMap[$j->source_key] = ['id' => $j->id, 'entry_no' => $j->entry_no];
$mappedKey = $legacyMap[$j->source_key] ?? $j->source_key;
$journalMap[$mappedKey] = ['id' => $j->id, 'entry_no' => $j->entry_no];
}
}
@@ -514,10 +527,11 @@ public function bankTransactions(Request $request): JsonResponse
],
]);
} catch (\Throwable $e) {
Log::error('은행거래 목록 조회 오류: ' . $e->getMessage());
Log::error('은행거래 목록 조회 오류: '.$e->getMessage());
return response()->json([
'success' => false,
'message' => '은행거래 목록 조회 실패: ' . $e->getMessage(),
'message' => '은행거래 목록 조회 실패: '.$e->getMessage(),
], 500);
}
}
@@ -560,7 +574,7 @@ public function storeFromBank(Request $request): JsonResponse
if ($existing) {
return response()->json([
'success' => false,
'message' => '이미 분개가 완료된 거래입니다. (전표번호: ' . $existing->entry_no . ')',
'message' => '이미 분개가 완료된 거래입니다. (전표번호: '.$existing->entry_no.')',
], 422);
}
@@ -621,11 +635,11 @@ public function storeFromBank(Request $request): JsonResponse
}
}
Log::error('은행거래 분개 저장 오류: ' . $lastError->getMessage());
Log::error('은행거래 분개 저장 오류: '.$lastError->getMessage());
return response()->json([
'success' => false,
'message' => '분개 저장 실패: ' . $lastError->getMessage(),
'message' => '분개 저장 실패: '.$lastError->getMessage(),
], 500);
}
@@ -637,17 +651,24 @@ public function bankJournals(Request $request): JsonResponse
$tenantId = session('selected_tenant_id', 1);
$sourceKey = $request->get('source_key');
if (!$sourceKey) {
if (! $sourceKey) {
return response()->json(['success' => false, 'message' => 'source_key가 필요합니다.'], 422);
}
// 레거시(summary 미포함) 형식과 신규(summary 포함) 형식 모두 매칭
$keys = [$sourceKey];
$parts = explode('|', $sourceKey);
if (count($parts) === 6) {
$keys[] = implode('|', array_slice($parts, 0, 5));
}
$entry = JournalEntry::forTenant($tenantId)
->where('source_type', 'bank_transaction')
->where('source_key', $sourceKey)
->whereIn('source_key', $keys)
->with('lines')
->first();
if (!$entry) {
if (! $entry) {
return response()->json(['success' => true, 'data' => null]);
}
@@ -729,7 +750,7 @@ private function getPreviousBalances(int $tenantId, string $startDate, ?string $
$balances = [];
foreach ($transactions as $tx) {
$accNum = $tx->bank_account_num;
if (!$tx->is_manual && (float) $tx->balance != 0) {
if (! $tx->is_manual && (float) $tx->balance != 0) {
// API 데이터: 바로빌이 제공한 잔액을 앵커로 사용
$balances[$accNum] = (float) $tx->balance;
} else {
@@ -797,7 +818,7 @@ public function accountCodeStore(Request $request): JsonResponse
public function accountCodeUpdate(Request $request, int $id): JsonResponse
{
$accountCode = AccountCode::find($id);
if (!$accountCode) {
if (! $accountCode) {
return response()->json(['success' => false, 'error' => '계정과목을 찾을 수 없습니다.'], 404);
}
@@ -829,7 +850,7 @@ public function accountCodeUpdate(Request $request, int $id): JsonResponse
public function accountCodeDestroy(int $id): JsonResponse
{
$accountCode = AccountCode::find($id);
if (!$accountCode) {
if (! $accountCode) {
return response()->json(['success' => false, 'error' => '계정과목을 찾을 수 없습니다.'], 404);
}