0 // 전체 계좌 ]); if ($accountResult['success']) { $accountData = $accountResult['data']; $accountList = []; // BankAccount 또는 BankAccountEx에서 계좌 목록 추출 if (isset($accountData->BankAccount)) { if (is_array($accountData->BankAccount)) { $accountList = $accountData->BankAccount; } else if (is_object($accountData->BankAccount)) { $accountList = [$accountData->BankAccount]; } } else if (isset($accountData->BankAccountEx)) { if (is_array($accountData->BankAccountEx)) { $accountList = $accountData->BankAccountEx; } else if (is_object($accountData->BankAccountEx)) { $accountList = [$accountData->BankAccountEx]; } } // 각 계좌별로 거래 내역 조회 $allLogs = []; $allSummary = ['totalDeposit' => 0, 'totalWithdraw' => 0, 'count' => 0]; $debugAllAccounts = []; foreach ($accountList as $accIndex => $acc) { if (!is_object($acc)) continue; $accNum = $acc->BankAccountNum ?? ''; if (empty($accNum) || (is_numeric($accNum) && $accNum < 0)) { continue; // 에러 코드 스킵 } // 각 계좌의 거래 내역 조회 $accResult = callBarobillAccountSOAP('GetPeriodBankAccountTransLog', [ 'ID' => $userId, 'BankAccountNum' => $accNum, 'StartDate' => $startDate, 'EndDate' => $endDate, 'TransDirection' => 1, 'CountPerPage' => 1000, // 전체 조회를 위해 큰 값 사용 'CurrentPage' => 1, 'OrderDirection' => 2 ]); if ($accResult['success']) { $accData = $accResult['data']; // 에러 코드 체크 $errorCode = null; if (isset($accData->CurrentPage) && is_numeric($accData->CurrentPage) && $accData->CurrentPage < 0) { $errorCode = $accData->CurrentPage; } elseif (isset($accData->BankAccountNum) && is_numeric($accData->BankAccountNum) && $accData->BankAccountNum < 0) { $errorCode = $accData->BankAccountNum; } // -25005, -25001은 데이터 없음 (정상) if (!$errorCode || ($errorCode == -25005 || $errorCode == -25001)) { // 거래 내역 파싱 if (isset($accData->BankAccountLogList) && isset($accData->BankAccountLogList->BankAccountTransLog)) { $rawLogs = is_array($accData->BankAccountLogList->BankAccountTransLog) ? $accData->BankAccountLogList->BankAccountTransLog : [$accData->BankAccountLogList->BankAccountTransLog]; foreach ($rawLogs as $log) { $deposit = floatval($log->Deposit ?? 0); $withdraw = floatval($log->Withdraw ?? 0); // 거래일시 파싱: TransDT 필드 사용 (YYYYMMDDHHmmss 형식) $transDT = $log->TransDT ?? ''; $transDate = ''; $transTime = ''; $dateTime = ''; if (!empty($transDT) && strlen($transDT) >= 14) { // TransDT: "20251203100719" -> "2025-12-03 10:07:19" $transDate = substr($transDT, 0, 8); // YYYYMMDD $transTime = substr($transDT, 8, 6); // HHmmss $dateTime = substr($transDT, 0, 4) . '-' . substr($transDT, 4, 2) . '-' . substr($transDT, 6, 2) . ' ' . substr($transDT, 8, 2) . ':' . substr($transDT, 10, 2) . ':' . substr($transDT, 12, 2); } else { // 기존 방식도 지원 (다양한 필드명 확인) $transDate = $log->TransDate ?? $log->TradeDate ?? $log->Date ?? ''; $transTime = $log->TransTime ?? $log->TradeTime ?? $log->Time ?? ''; if (!empty($transDate) && !empty($transTime)) { $dateStr = (string)$transDate; $timeStr = (string)$transTime; if (strlen($dateStr) == 8 && strlen($timeStr) >= 4) { $dateTime = substr($dateStr, 0, 4) . '-' . substr($dateStr, 4, 2) . '-' . substr($dateStr, 6, 2) . ' ' . substr($timeStr, 0, 2) . ':' . substr($timeStr, 2, 2); if (strlen($timeStr) >= 6) { $dateTime .= ':' . substr($timeStr, 4, 2); } } elseif (strlen($dateStr) == 10 && strpos($dateStr, '-') !== false) { $dateTime = $dateStr . ' ' . substr($timeStr, 0, 2) . ':' . substr($timeStr, 2, 2); if (strlen($timeStr) >= 6) { $dateTime .= ':' . substr($timeStr, 4, 2); } } } } // 적요 파싱: TransRemark1 필드 사용 $summary = $log->TransRemark1 ?? $log->Summary ?? $log->Content ?? $log->Description ?? $log->Remark ?? $log->Note ?? ''; // 추가 적요 정보: TransRemark2 $remark2 = $log->TransRemark2 ?? ''; // 거래 유형: TransType (예: CC) $transType = $log->TransType ?? ''; // 거래 방향: TransDirection (예: 입금, 출금) $transDirection = $log->TransDirection ?? ''; // 취급점: TransOffice $transOffice = $log->TransOffice ?? ''; // 적요 정보 결합 $fullSummary = $summary; if (!empty($remark2)) { $fullSummary = (!empty($fullSummary) ? $fullSummary . ' ' . $remark2 : $remark2); } if (!empty($transType)) { $fullSummary = (!empty($fullSummary) ? $fullSummary . ' (' . $transType . ')' : '(' . $transType . ')'); } // 보낸분/받는분 정보 (기존 필드명도 지원) $cast = $log->Cast ?? $log->Counterpart ?? $log->Opponent ?? $log->Name ?? ''; // 취급점/수단 정보 $branch = $transOffice ?: ($log->Branch ?? $log->HandlingBranch ?? $log->Method ?? ''); // 디버그: 첫 번째 계좌의 첫 번째 로그 정보 저장 if ($accIndex === 0 && empty($debugAllAccounts)) { $debugAllAccounts['first_account_first_log'] = [ 'account_num' => $accNum, 'log_raw_fields' => [], 'parsed' => [ 'transDate' => $transDate, 'transTime' => $transTime, 'transDateTime' => $dateTime, 'summary' => $summary, 'fullSummary' => $fullSummary, 'cast' => $cast, 'branch' => $branch ] ]; // 원본 로그의 모든 필드 저장 foreach ($log as $key => $value) { $debugAllAccounts['first_account_first_log']['log_raw_fields'][$key] = is_string($value) ? substr($value, 0, 100) : (is_numeric($value) ? $value : gettype($value)); } } $allLogs[] = [ 'transDate' => $transDate, 'transTime' => $transTime, 'transDateTime' => $dateTime, 'bankAccountNum' => $log->BankAccountNum ?? $accNum, 'bankName' => $log->BankName ?? ($acc->BankName ?? ''), 'deposit' => $deposit, 'withdraw' => $withdraw, 'depositFormatted' => number_format($deposit), 'withdrawFormatted' => number_format($withdraw), 'balance' => floatval($log->Balance ?? 0), 'balanceFormatted' => number_format(floatval($log->Balance ?? 0)), 'summary' => $fullSummary ?: $summary, 'cast' => $cast, 'memo' => $log->Memo ?? '', 'identity' => $log->Identity ?? '', 'branch' => $branch ]; $allSummary['totalDeposit'] += $deposit; $allSummary['totalWithdraw'] += $withdraw; $allSummary['count']++; } } } } } // 날짜/시간 기준으로 정렬 (최신순) usort($allLogs, function($a, $b) { $dateA = $a['transDate'] . $a['transTime']; $dateB = $b['transDate'] . $b['transTime']; return strcmp($dateB, $dateA); // 내림차순 }); // 페이지네이션 계산 $maxPageNum = ceil($allSummary['count'] / $limit); $startIndex = ($page - 1) * $limit; $paginatedLogs = array_slice($allLogs, $startIndex, $limit); $response = [ 'success' => true, 'data' => [ 'logs' => $paginatedLogs, 'pagination' => [ 'currentPage' => $page, 'countPerPage' => $limit, 'maxPageNum' => $maxPageNum, 'maxIndex' => $allSummary['count'] ], 'summary' => $allSummary ] ]; // 디버그 정보 추가 if (!empty($debugAllAccounts)) { $response['debug_all_accounts'] = $debugAllAccounts; } // 디버그: 전체 계좌 조회 시 첫 번째 로그 확인 if (!empty($paginatedLogs) && isset($paginatedLogs[0])) { $response['debug_first_log_parsed'] = $paginatedLogs[0]; } echo json_encode($response, JSON_UNESCAPED_UNICODE); return; } } // 단일 계좌 조회 (기존 로직) $result = callBarobillAccountSOAP('GetPeriodBankAccountTransLog', [ 'ID' => $userId, 'BankAccountNum' => $bankAccountNum, 'StartDate' => $startDate, 'EndDate' => $endDate, 'TransDirection' => 1, // 1:전체? (API 예제 값), 2:입금, 3:출금 추정 (확인 필요) - 우선 예제값 1 사용 'CountPerPage' => $limit, 'CurrentPage' => $page, 'OrderDirection' => 2 // 1:오름차순, 2:내림차순 ]); if ($result['success']) { $resultData = $result['data']; // 에러 코드 체크 (다양한 필드에서 확인) $errorCode = null; // CurrentPage가 음수인 경우 if (isset($resultData->CurrentPage) && is_numeric($resultData->CurrentPage) && $resultData->CurrentPage < 0) { $errorCode = $resultData->CurrentPage; } // BankAccountNum이 음수인 경우 (예: -10002) elseif (isset($resultData->BankAccountNum) && is_numeric($resultData->BankAccountNum) && $resultData->BankAccountNum < 0) { $errorCode = $resultData->BankAccountNum; } // -25005: 데이터 없음 (정상), -25001: 계좌 없음 (정상) if ($errorCode && ($errorCode == -25005 || $errorCode == -25001)) { echo json_encode([ 'success' => true, 'data' => [ 'logs' => [], 'summary' => ['totalDeposit' => 0, 'totalWithdraw' => 0, 'count' => 0], 'pagination' => ['currentPage' => 1, 'maxPageNum' => 1] ] ], JSON_UNESCAPED_UNICODE); return; } // 다른 오류 코드인 경우 if ($errorCode) { // 상세 에러 메시지 매핑 $errorMsg = '계좌 내역 조회 실패: ' . $errorCode; $errorMessages = [ -10002 => '인증 실패 (-10002). CERTKEY가 올바르지 않거나 만료되었습니다. 바로빌 개발자센터에서 CERTKEY를 확인하세요.', -50214 => '은행 로그인 실패 (-50214). 바로빌 사이트에서 계좌 비밀번호/인증서를 점검해주세요.', -24005 => '사용자 정보 불일치 (-24005). 사업자번호를 확인해주세요.', ]; if (isset($errorMessages[$errorCode])) { $errorMsg = $errorMessages[$errorCode]; } throw new Exception($errorMsg); } // 데이터 파싱 (BankAccountTransLog) $logs = []; $rawLogs = []; if (isset($resultData->BankAccountLogList) && isset($resultData->BankAccountLogList->BankAccountTransLog)) { if (is_array($resultData->BankAccountLogList->BankAccountTransLog)) { $rawLogs = $resultData->BankAccountLogList->BankAccountTransLog; } else { $rawLogs = [$resultData->BankAccountLogList->BankAccountTransLog]; } } // 디버그: 첫 번째 로그의 전체 구조 확인 $debugInfo = []; if (!empty($rawLogs) && is_object($rawLogs[0])) { $firstLog = $rawLogs[0]; $debugInfo['first_log_structure'] = []; $debugInfo['first_log_all_keys'] = []; foreach ($firstLog as $key => $value) { $debugInfo['first_log_all_keys'][] = $key; $debugInfo['first_log_structure'][$key] = [ 'type' => gettype($value), 'value' => is_string($value) ? $value : (is_numeric($value) ? $value : gettype($value)), 'length' => is_string($value) ? strlen($value) : null ]; } } $totalDeposit = 0; $totalWithdraw = 0; foreach ($rawLogs as $logIndex => $log) { $deposit = floatval($log->Deposit ?? 0); $withdraw = floatval($log->Withdraw ?? 0); $totalDeposit += $deposit; $totalWithdraw += $withdraw; // 거래일시 파싱: TransDT 필드 사용 (YYYYMMDDHHmmss 형식) $transDT = $log->TransDT ?? ''; $transDate = ''; $transTime = ''; $dateTime = ''; if (!empty($transDT) && strlen($transDT) >= 14) { // TransDT: "20251203100719" -> "2025-12-03 10:07:19" $transDate = substr($transDT, 0, 8); // YYYYMMDD $transTime = substr($transDT, 8, 6); // HHmmss $dateTime = substr($transDT, 0, 4) . '-' . substr($transDT, 4, 2) . '-' . substr($transDT, 6, 2) . ' ' . substr($transDT, 8, 2) . ':' . substr($transDT, 10, 2) . ':' . substr($transDT, 12, 2); } else { // 기존 방식도 지원 (다양한 필드명 확인) $transDate = $log->TransDate ?? $log->TradeDate ?? $log->Date ?? ''; $transTime = $log->TransTime ?? $log->TradeTime ?? $log->Time ?? ''; if (!empty($transDate) && !empty($transTime)) { $dateStr = (string)$transDate; $timeStr = (string)$transTime; if (strlen($dateStr) == 8 && strlen($timeStr) >= 4) { $dateTime = substr($dateStr, 0, 4) . '-' . substr($dateStr, 4, 2) . '-' . substr($dateStr, 6, 2) . ' ' . substr($timeStr, 0, 2) . ':' . substr($timeStr, 2, 2); if (strlen($timeStr) >= 6) { $dateTime .= ':' . substr($timeStr, 4, 2); } } elseif (strlen($dateStr) == 10 && strpos($dateStr, '-') !== false) { $dateTime = $dateStr . ' ' . substr($timeStr, 0, 2) . ':' . substr($timeStr, 2, 2); if (strlen($timeStr) >= 6) { $dateTime .= ':' . substr($timeStr, 4, 2); } } } } // 적요 파싱: TransRemark1 필드 사용 $summary = $log->TransRemark1 ?? $log->Summary ?? $log->Content ?? $log->Description ?? $log->Remark ?? $log->Note ?? ''; // 추가 적요 정보: TransRemark2 $remark2 = $log->TransRemark2 ?? ''; // 거래 유형: TransType (예: CC) $transType = $log->TransType ?? ''; // 거래 방향: TransDirection (예: 입금, 출금) $transDirection = $log->TransDirection ?? ''; // 취급점: TransOffice $transOffice = $log->TransOffice ?? ''; // 적요 정보 결합 $fullSummary = $summary; if (!empty($remark2)) { $fullSummary = (!empty($fullSummary) ? $fullSummary . ' ' . $remark2 : $remark2); } if (!empty($transType)) { $fullSummary = (!empty($fullSummary) ? $fullSummary . ' (' . $transType . ')' : '(' . $transType . ')'); } // 보낸분/받는분 정보 (기존 필드명도 지원) $cast = $log->Cast ?? $log->Counterpart ?? $log->Opponent ?? $log->Name ?? ''; // 취급점/수단 정보 $branch = $transOffice ?: ($log->Branch ?? $log->HandlingBranch ?? $log->Method ?? ''); $logs[] = [ 'transDate' => $transDate, 'transTime' => $transTime, 'transDateTime' => $dateTime, 'bankAccountNum' => $log->BankAccountNum ?? '', 'bankName' => $log->BankName ?? '', 'deposit' => $deposit, 'withdraw' => $withdraw, 'depositFormatted' => number_format($deposit), 'withdrawFormatted' => number_format($withdraw), 'balance' => floatval($log->Balance ?? 0), 'balanceFormatted' => number_format(floatval($log->Balance ?? 0)), 'summary' => $fullSummary ?: $summary, // 적요 (통합 정보) 'cast' => $cast, // 보낸분/받는분 'memo' => $log->Memo ?? '', 'identity' => $log->Identity ?? '', // 고유번호 'branch' => $branch, // 취급점/수단 'rawData' => json_encode($log, JSON_UNESCAPED_UNICODE) // 디버깅용 원본 데이터 ]; } $response = [ 'success' => true, 'data' => [ 'logs' => $logs, 'pagination' => [ 'currentPage' => $resultData->CurrentPage ?? 1, 'countPerPage' => $resultData->CountPerPage ?? 50, 'maxPageNum' => $resultData->MaxPageNum ?? 1, 'maxIndex' => $resultData->MaxIndex ?? 0 ], 'summary' => [ 'totalDeposit' => $totalDeposit, 'totalWithdraw' => $totalWithdraw, 'count' => count($logs) ] ] ]; // 디버그 정보 추가 if (isset($result['debug'])) { $response['debug'] = $result['debug']; } // API 응답 구조 디버그 정보 추가 if (!empty($debugInfo)) { $response['debug_api_structure'] = $debugInfo; } // 첫 번째 로그의 원본 데이터도 포함 (필드명 확인용) if (!empty($rawLogs) && is_object($rawLogs[0])) { $response['debug_first_log_raw'] = []; foreach ($rawLogs[0] as $key => $value) { $response['debug_first_log_raw'][$key] = is_string($value) ? $value : (is_numeric($value) ? $value : gettype($value)); } } echo json_encode($response, JSON_UNESCAPED_UNICODE); } else { // API Error Handling (Graceful Fallback) // If API fails (e.g., SoapClient missing), return empty list with warning // so the UI doesn't break. $response = [ 'success' => true, // Masquerade as success to render empty table 'data' => [ 'logs' => [], 'pagination' => [ 'currentPage' => 1, 'countPerPage' => $limit, 'maxPageNum' => 1, 'maxIndex' => 0 ], 'summary' => [ 'totalDeposit' => 0, 'totalWithdraw' => 0, 'count' => 0 ] ], 'warning' => 'API 연동 실패: ' . $result['error'], // Custom warning field 'api_error_code' => $result['error_code'] ?? null ]; // Add debug info if available if (isset($result['debug'])) { $response['debug'] = $result['debug']; } echo json_encode($response, JSON_UNESCAPED_UNICODE); } } catch (Throwable $e) { // Global Exception/Error Handling echo json_encode([ 'success' => true, // Return true to avoid UI breakage 'data' => [ 'logs' => [], 'pagination' => ['currentPage' => 1, 'maxPageNum' => 1], 'summary' => ['totalDeposit' => 0, 'totalWithdraw' => 0, 'count' => 0] ], 'warning' => '시스템 오류: ' . $e->getMessage() ], JSON_UNESCAPED_UNICODE); } ?>