Files
sam-kd/eaccount/api/transactions.php

492 lines
24 KiB
PHP

<?php
/**
* 계좌 입출금내역 조회 API (GetPeriodBankAccountLog)
*/
header('Content-Type: application/json; charset=utf-8');
require_once('barobill_account_config.php');
try {
$startDate = isset($_GET['startDate']) ? $_GET['startDate'] : date('Ymd');
$endDate = isset($_GET['endDate']) ? $_GET['endDate'] : date('Ymd');
$bankAccountNum = isset($_GET['accountNum']) ? $_GET['accountNum'] : ''; // 특정 계좌만 조회 시, 빈 값이면 전체 계좌
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 50;
// 바로빌 사용자 ID (설정 파일에서 로드)
$userId = getBarobillUserId();
// 계좌번호 하이픈 제거
$bankAccountNum = str_replace('-', '', $bankAccountNum);
// 전체 계좌 조회: 빈 값이면 모든 계좌의 거래 내역을 조회
if (empty($bankAccountNum)) {
// 먼저 등록된 계좌 목록 가져오기
$accountResult = callBarobillAccountSOAP('GetBankAccountEx', [
'AvailOnly' => 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 {
$response = [
'success' => false,
'error' => $result['error'],
'error_code' => $result['error_code'] ?? null
];
// 디버그 정보 추가
if (isset($result['debug'])) {
$response['debug'] = $result['debug'];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);
}
} catch (Throwable $e) {
echo json_encode([
'success' => false,
'error' => '서버 오류: ' . $e->getMessage()
], JSON_UNESCAPED_UNICODE);
}