fix:바로빌 계좌 입출금내역 긴 기간 검색 시 데이터 누락 수정

This commit is contained in:
김보곤
2026-02-19 20:35:17 +09:00
parent 4191e4637f
commit fea28d6652

View File

@@ -16,6 +16,7 @@
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Carbon\Carbon;
use Symfony\Component\HttpFoundation\StreamedResponse;
/**
@@ -344,41 +345,11 @@ public function transactions(Request $request): JsonResponse
return $this->getAllAccountsTransactions($userId, $startDate, $endDate, $page, $limit, $savedData, $overrideData, $tenantId, $manualTransactions);
}
// 단일 계좌 조회
$result = $this->callSoap('GetPeriodBankAccountTransLog', [
'ID' => $userId,
'BankAccountNum' => $bankAccountNum,
'StartDate' => $startDate,
'EndDate' => $endDate,
'TransDirection' => 1, // 1:전체
'CountPerPage' => $limit,
'CurrentPage' => $page,
'OrderDirection' => 2 // 2:내림차순
]);
// 단일 계좌 조회 - 기간을 월별로 분할하여 SOAP API 호출 (긴 기간 에러 방지)
$fetched = $this->fetchAccountTransactions($userId, $bankAccountNum, $startDate, $endDate);
if (!$result['success']) {
return response()->json([
'success' => false,
'error' => $result['error'],
'error_code' => $result['error_code'] ?? null
]);
}
$resultData = $result['data'];
// 에러 코드 체크
$errorCode = $this->checkErrorCode($resultData);
if ($errorCode && !in_array($errorCode, [-25005, -25001])) {
return response()->json([
'success' => false,
'error' => $this->getErrorMessage($errorCode),
'error_code' => $errorCode
]);
}
// 데이터가 없는 경우
if ($errorCode && in_array($errorCode, [-25005, -25001])) {
// API 데이터 없어도 수동 건은 표시
// API 데이터가 없는 경우 (수동 건만 표시)
if (empty($fetched['logs'])) {
$manualLogs = $this->convertManualToLogs($manualTransactions);
$baseBalance = $this->findBaseBalance($tenantId, $startDate, $bankAccountNum);
$recalcLogs = $this->recalcManualBalances($manualLogs['logs'], $baseBalance);
@@ -392,8 +363,12 @@ public function transactions(Request $request): JsonResponse
]);
}
// 데이터 파싱 (저장된 계정과목 + 오버라이드 병합)
$logs = $this->parseTransactionLogs($resultData, '', $savedData, $tenantId);
// 월별 청크 결과를 합쳐서 파싱
$fakeData = new \stdClass();
$fakeData->BankAccountLogList = new \stdClass();
$fakeData->BankAccountLogList->BankAccountTransLog = $fetched['logs'];
$logs = $this->parseTransactionLogs($fakeData, '', $savedData, $tenantId);
// 수동 입력 건 병합 (중복 제거: 수동 거래와 동일한 API 거래는 제외)
$manualLogs = $this->convertManualToLogs($manualTransactions);
@@ -418,15 +393,21 @@ public function transactions(Request $request): JsonResponse
'count' => count($mergedLogs),
];
// 클라이언트 사이드 페이지네이션
$totalCount = count($mergedLogs);
$maxPageNum = (int)ceil($totalCount / $limit);
$startIndex = ($page - 1) * $limit;
$paginatedLogs = array_slice($mergedLogs, $startIndex, $limit);
return response()->json([
'success' => true,
'data' => [
'logs' => $mergedLogs,
'logs' => $paginatedLogs,
'pagination' => [
'currentPage' => $resultData->CurrentPage ?? 1,
'countPerPage' => $resultData->CountPerPage ?? 50,
'maxPageNum' => $resultData->MaxPageNum ?? 1,
'maxIndex' => $resultData->MaxIndex ?? 0
'currentPage' => $page,
'countPerPage' => $limit,
'maxPageNum' => $maxPageNum,
'maxIndex' => $totalCount
],
'summary' => $mergedSummary
]
@@ -473,30 +454,21 @@ private function getAllAccountsTransactions(string $userId, string $startDate, s
$accNum = $acc->BankAccountNum ?? '';
if (empty($accNum) || (is_numeric($accNum) && $accNum < 0)) continue;
$accResult = $this->callSoap('GetPeriodBankAccountTransLog', [
'ID' => $userId,
'BankAccountNum' => $accNum,
'StartDate' => $startDate,
'EndDate' => $endDate,
'TransDirection' => 1,
'CountPerPage' => 1000,
'CurrentPage' => 1,
'OrderDirection' => 2
]);
// 기간을 월별로 분할하여 SOAP API 호출 (긴 기간 에러 방지)
$fetched = $this->fetchAccountTransactions($userId, $accNum, $startDate, $endDate);
if ($accResult['success']) {
$accData = $accResult['data'];
$errorCode = $this->checkErrorCode($accData);
if (!empty($fetched['logs'])) {
$fakeData = new \stdClass();
$fakeData->BankAccountLogList = new \stdClass();
$fakeData->BankAccountLogList->BankAccountTransLog = $fetched['logs'];
if (!$errorCode || in_array($errorCode, [-25005, -25001])) {
$parsed = $this->parseTransactionLogs($accData, $acc->BankName ?? '', $savedData, $tenantId);
foreach ($parsed['logs'] as $log) {
$log['bankName'] = $acc->BankName ?? $this->getBankName($acc->BankCode ?? '');
$allLogs[] = $log;
}
$totalDeposit += $parsed['summary']['totalDeposit'];
$totalWithdraw += $parsed['summary']['totalWithdraw'];
$parsed = $this->parseTransactionLogs($fakeData, $acc->BankName ?? '', $savedData, $tenantId);
foreach ($parsed['logs'] as $log) {
$log['bankName'] = $acc->BankName ?? $this->getBankName($acc->BankCode ?? '');
$allLogs[] = $log;
}
$totalDeposit += $parsed['summary']['totalDeposit'];
$totalWithdraw += $parsed['summary']['totalWithdraw'];
}
}
@@ -692,6 +664,98 @@ private function getErrorMessage(int $errorCode): string
return $messages[$errorCode] ?? '바로빌 API 오류: ' . $errorCode;
}
/**
* 긴 기간을 월별 청크로 분할 (바로빌 API 기간 제한 대응)
* YYYYMMDD 형식의 시작/종료일을 받아 월별 [start, end] 배열 반환
*/
private function splitDateRangeMonthly(string $startDate, string $endDate): array
{
$start = Carbon::createFromFormat('Ymd', $startDate)->startOfDay();
$end = Carbon::createFromFormat('Ymd', $endDate)->endOfDay();
$chunks = [];
$cursor = $start->copy();
while ($cursor->lte($end)) {
$chunkStart = $cursor->copy();
$chunkEnd = $cursor->copy()->endOfMonth()->startOfDay();
// 마지막 청크: 종료일이 월말보다 이전이면 종료일 사용
if ($chunkEnd->gt($end)) {
$chunkEnd = $end->copy()->startOfDay();
}
$chunks[] = [
'start' => $chunkStart->format('Ymd'),
'end' => $chunkEnd->format('Ymd'),
];
// 다음 월 1일로 이동
$cursor = $chunkEnd->copy()->addDay()->startOfMonth();
}
return $chunks;
}
/**
* 단일 계좌의 거래 내역을 기간 분할하여 조회
* 긴 기간도 월별로 나누어 SOAP API 호출 후 병합
*/
private function fetchAccountTransactions(string $userId, string $accNum, string $startDate, string $endDate): array
{
$chunks = $this->splitDateRangeMonthly($startDate, $endDate);
$allRawLogs = [];
$lastSuccessData = null;
foreach ($chunks as $chunk) {
$result = $this->callSoap('GetPeriodBankAccountTransLog', [
'ID' => $userId,
'BankAccountNum' => $accNum,
'StartDate' => $chunk['start'],
'EndDate' => $chunk['end'],
'TransDirection' => 1,
'CountPerPage' => 1000,
'CurrentPage' => 1,
'OrderDirection' => 2
]);
if (!$result['success']) {
continue;
}
$chunkData = $result['data'];
$errorCode = $this->checkErrorCode($chunkData);
// 데이터 없음(-25005, -25001)은 건너뜀, 기타 에러도 건너뜀 (다른 월은 성공할 수 있음)
if ($errorCode && !in_array($errorCode, [-25005, -25001])) {
Log::debug("바로빌 API 기간 분할 - 에러 발생 ({$chunk['start']}~{$chunk['end']}): {$errorCode}");
continue;
}
if ($errorCode && in_array($errorCode, [-25005, -25001])) {
continue; // 데이터 없음
}
// 로그 추출
$rawLogs = [];
if (isset($chunkData->BankAccountLogList) && isset($chunkData->BankAccountLogList->BankAccountTransLog)) {
$logs = $chunkData->BankAccountLogList->BankAccountTransLog;
$rawLogs = is_array($logs) ? $logs : [$logs];
}
foreach ($rawLogs as $log) {
$allRawLogs[] = $log;
}
$lastSuccessData = $chunkData;
}
return [
'logs' => $allRawLogs,
'lastData' => $lastSuccessData,
];
}
/**
* 은행 코드 -> 은행명 변환
*/