초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
This commit is contained in:
332
eaccount/api/account_status.php
Normal file
332
eaccount/api/account_status.php
Normal file
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
/**
|
||||
* 계좌 등록 상태 조회 API
|
||||
* 로컬 DB의 company_accounts 테이블과 바로빌 API에서 계좌 정보를 가져옵니다.
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_account_config.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
|
||||
|
||||
try {
|
||||
// 1. 로컬 DB의 company_accounts 테이블에서 계좌 정보 가져오기
|
||||
$localAccounts = [];
|
||||
$selectedTenantId = $_SESSION['eaccount_tenant_id'] ?? null;
|
||||
|
||||
if ($selectedTenantId) {
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
if ($pdo) {
|
||||
$sql = "SELECT id, company_id, bank_code, account_num, account_pwd
|
||||
FROM {$DB}.company_accounts
|
||||
WHERE company_id = ?
|
||||
ORDER BY id DESC";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$selectedTenantId]);
|
||||
$localAccounts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('로컬 계좌 정보 로드 실패: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 바로빌 API에서 계좌 정보 가져오기 (시도)
|
||||
$barobillAccounts = [];
|
||||
$barobillError = null;
|
||||
$barobillErrorCode = null;
|
||||
$debugInfo = null;
|
||||
|
||||
$result = callBarobillAccountSOAP('GetBankAccountEx', [
|
||||
'AvailOnly' => 0 // 전체 계좌 조회 (0: 전체, 1: 사용가능, 2: 해지)
|
||||
]);
|
||||
|
||||
if ($result['success']) {
|
||||
$data = $result['data'];
|
||||
$accountList = [];
|
||||
|
||||
// 디버그: 응답 구조 확인
|
||||
$debugInfo = [
|
||||
'data_type' => gettype($data),
|
||||
'data_keys' => is_object($data) ? array_keys(get_object_vars($data)) : [],
|
||||
'has_BankAccountEx' => isset($data->BankAccountEx),
|
||||
'has_BankAccount' => isset($data->BankAccount),
|
||||
'BankAccountEx_type' => isset($data->BankAccountEx) ? gettype($data->BankAccountEx) : 'N/A',
|
||||
'BankAccount_type' => isset($data->BankAccount) ? gettype($data->BankAccount) : 'N/A',
|
||||
'BankAccountEx_is_array' => isset($data->BankAccountEx) ? is_array($data->BankAccountEx) : false,
|
||||
'BankAccount_is_array' => isset($data->BankAccount) ? is_array($data->BankAccount) : false
|
||||
];
|
||||
|
||||
// 실제 SOAP 응답 구조 확인:
|
||||
// GetBankAccountExResult -> BankAccount (단일 객체 또는 배열)
|
||||
// 또는 BankAccountEx (배열) - 다른 API 버전일 수 있음
|
||||
|
||||
// 우선순위 1: BankAccount 확인 (실제 응답 구조 - SOAP XML에서 확인됨)
|
||||
if (isset($data->BankAccount)) {
|
||||
if (is_array($data->BankAccount)) {
|
||||
$accountList = $data->BankAccount;
|
||||
} else if (is_object($data->BankAccount)) {
|
||||
// 단일 객체인 경우 배열로 변환
|
||||
$accountList = [$data->BankAccount];
|
||||
}
|
||||
}
|
||||
// 우선순위 2: BankAccountEx 배열 확인 (다른 API 버전)
|
||||
else if (isset($data->BankAccountEx)) {
|
||||
// 단일 객체가 에러 코드인 경우 (예: -10002, -25001)
|
||||
if (is_numeric($data->BankAccountEx) && $data->BankAccountEx < 0) {
|
||||
$errorCode = $data->BankAccountEx;
|
||||
$barobillError = '바로빌 API 오류: ' . $errorCode;
|
||||
$barobillErrorCode = $errorCode;
|
||||
|
||||
// 상세 에러 메시지 매핑
|
||||
if ($errorCode == -10002) {
|
||||
$barobillError = '인증 실패 (-10002). CERTKEY 또는 사업자번호를 확인해주세요.';
|
||||
} else if ($errorCode == -25001) {
|
||||
$barobillError = '등록된 계좌가 없습니다 (-25001). 바로빌 사이트에서 계좌를 등록해주세요.';
|
||||
} else if ($errorCode == -50214) {
|
||||
$barobillError = '은행 로그인 실패 (-50214). 바로빌 사이트에서 계좌 비밀번호/인증서를 점검해주세요.';
|
||||
}
|
||||
}
|
||||
// 배열 또는 객체인 경우
|
||||
else if (is_array($data->BankAccountEx)) {
|
||||
$accountList = $data->BankAccountEx;
|
||||
} else if (is_object($data->BankAccountEx)) {
|
||||
// 단일 객체인 경우 배열로 변환
|
||||
$accountList = [$data->BankAccountEx];
|
||||
}
|
||||
}
|
||||
// 방법 3: 직접 BankAccount 속성 확인 (다른 구조일 수 있음)
|
||||
else {
|
||||
// 객체의 모든 속성을 확인하여 BankAccount 관련 속성 찾기
|
||||
if (is_object($data)) {
|
||||
$vars = get_object_vars($data);
|
||||
foreach ($vars as $key => $value) {
|
||||
// BankAccount로 시작하는 속성 찾기
|
||||
if (stripos($key, 'BankAccount') !== false) {
|
||||
if (is_array($value)) {
|
||||
$accountList = $value;
|
||||
break;
|
||||
} else if (is_object($value)) {
|
||||
$accountList = [$value];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 계좌 정보 파싱
|
||||
foreach ($accountList as $acc) {
|
||||
// 객체가 아닌 경우 스킵
|
||||
if (!is_object($acc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 에러 코드 체크 (개별 계좌 레벨)
|
||||
if (isset($acc->BankAccountNum)) {
|
||||
// BankAccountNum이 음수인 경우 에러 코드
|
||||
if (is_numeric($acc->BankAccountNum) && $acc->BankAccountNum < 0) {
|
||||
$errorCode = $acc->BankAccountNum;
|
||||
if (!$barobillError) {
|
||||
$barobillError = '바로빌 API 오류: ' . $errorCode;
|
||||
$barobillErrorCode = $errorCode;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// BankAccountNum이 비어있는 경우도 스킵
|
||||
if (empty($acc->BankAccountNum)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// BankAccountNum이 없는 경우도 스킵
|
||||
continue;
|
||||
}
|
||||
|
||||
// BankName으로 BankCode 추론 (응답에 BankCode가 없는 경우)
|
||||
$bankCode = $acc->BankCode ?? '';
|
||||
if (empty($bankCode) && isset($acc->BankName)) {
|
||||
// BankName으로 BankCode 찾기
|
||||
$bankName = $acc->BankName;
|
||||
$bankCodeMap = [
|
||||
'기업은행' => '003',
|
||||
'IBK기업은행' => '003',
|
||||
'KB국민은행' => '004',
|
||||
'국민은행' => '004',
|
||||
'우리은행' => '020',
|
||||
'신한은행' => '088',
|
||||
'하나은행' => '081',
|
||||
'NH농협은행' => '011',
|
||||
'농협은행' => '011'
|
||||
];
|
||||
$bankCode = $bankCodeMap[$bankName] ?? '';
|
||||
}
|
||||
|
||||
// UseState 처리: 없으면 기본값 1 (사용중)으로 설정
|
||||
// UseState: 1=사용중, 0=중지, 2=해지
|
||||
$useState = isset($acc->UseState) ? intval($acc->UseState) : 1; // 기본값: 사용중
|
||||
|
||||
$barobillAccounts[] = [
|
||||
'bankAccountNum' => $acc->BankAccountNum ?? '',
|
||||
'bankCode' => $bankCode,
|
||||
'bankName' => getBankName($bankCode) ?: ($acc->BankName ?? ''),
|
||||
'accountName' => $acc->AccountName ?? '',
|
||||
'accountType' => $acc->AccountType ?? '',
|
||||
'currency' => $acc->Currency ?? 'KRW',
|
||||
'issueDate' => $acc->IssueDate ?? '',
|
||||
'balance' => $acc->Balance ?? 0,
|
||||
'status' => $useState,
|
||||
'statusText' => $useState == 1 ? '사용중' : ($useState == 0 ? '중지' : ($useState == 2 ? '해지' : '알 수 없음')),
|
||||
'source' => 'barobill_api' // 바로빌 API에서 가져온 정보
|
||||
];
|
||||
}
|
||||
|
||||
// 디버그 정보 추가
|
||||
$debugInfo['account_count'] = count($barobillAccounts);
|
||||
$debugInfo['account_list'] = array_map(function($acc) {
|
||||
return [
|
||||
'bankAccountNum' => $acc['bankAccountNum'],
|
||||
'bankCode' => $acc['bankCode'],
|
||||
'accountName' => $acc['accountName']
|
||||
];
|
||||
}, $barobillAccounts);
|
||||
|
||||
} else {
|
||||
$barobillError = $result['error'];
|
||||
$barobillErrorCode = $result['error_code'] ?? null;
|
||||
}
|
||||
|
||||
// 3. 로컬 DB 계좌 정보를 바로빌 계좌 정보와 매칭하여 통합
|
||||
$allAccounts = [];
|
||||
|
||||
// 먼저 바로빌 API 계좌 정보를 기준으로 추가 (실제 사용 가능한 계좌)
|
||||
foreach ($barobillAccounts as $barobillAcc) {
|
||||
$allAccounts[] = $barobillAcc;
|
||||
}
|
||||
|
||||
// 로컬 DB 계좌 정보를 바로빌 API 계좌와 매칭
|
||||
foreach ($localAccounts as $localAcc) {
|
||||
$matched = false;
|
||||
// 바로빌 API에 같은 계좌번호가 있는지 확인
|
||||
foreach ($allAccounts as &$existingAcc) {
|
||||
// 계좌번호 매칭 (하이픈 제거 후 비교)
|
||||
$localAccountNum = str_replace('-', '', $localAcc['account_num']);
|
||||
$barobillAccountNum = str_replace('-', '', $existingAcc['bankAccountNum']);
|
||||
|
||||
if ($localAccountNum === $barobillAccountNum) {
|
||||
// 바로빌 API 계좌 정보에 로컬 DB 정보 병합
|
||||
$existingAcc['id'] = $localAcc['id'];
|
||||
$existingAcc['hasPassword'] = !empty($localAcc['account_pwd']);
|
||||
$existingAcc['source'] = 'both'; // 양쪽 모두에 있음 (실제 사용 가능)
|
||||
$matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 바로빌 API에 없는 로컬 계좌는 경고와 함께 추가 (사용 불가능)
|
||||
if (!$matched) {
|
||||
$allAccounts[] = [
|
||||
'id' => $localAcc['id'],
|
||||
'bankAccountNum' => $localAcc['account_num'],
|
||||
'bankCode' => $localAcc['bank_code'],
|
||||
'bankName' => getBankName($localAcc['bank_code']),
|
||||
'accountName' => '', // 로컬 DB에는 별칭 정보 없음
|
||||
'accountType' => '',
|
||||
'currency' => 'KRW',
|
||||
'issueDate' => '',
|
||||
'balance' => 0,
|
||||
'status' => '',
|
||||
'statusText' => '바로빌 미등록',
|
||||
'source' => 'local_db_only', // 로컬 DB에만 있음 (바로빌 API 미등록)
|
||||
'hasPassword' => !empty($localAcc['account_pwd']),
|
||||
'warning' => true // 경고 표시용
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 사용 가능한 계좌 수 계산 (바로빌 API에서 확인된 계좌)
|
||||
$availableAccounts = array_filter($allAccounts, function($acc) {
|
||||
return $acc['source'] === 'barobill_api' || $acc['source'] === 'both';
|
||||
});
|
||||
$availableCount = count($availableAccounts);
|
||||
|
||||
// 경고가 필요한 계좌 수 (로컬에만 있는 계좌)
|
||||
$warningAccounts = array_filter($allAccounts, function($acc) {
|
||||
return isset($acc['warning']) && $acc['warning'] === true;
|
||||
});
|
||||
$warningCount = count($warningAccounts);
|
||||
|
||||
$response = [
|
||||
'success' => true,
|
||||
'accounts' => $allAccounts,
|
||||
'count' => count($allAccounts),
|
||||
'available_count' => $availableCount, // 바로빌 API에서 확인된 사용 가능한 계좌 수
|
||||
'warning_count' => $warningCount, // 로컬에만 있는 계좌 수
|
||||
'local_count' => count($localAccounts),
|
||||
'barobill_count' => count($barobillAccounts),
|
||||
'message' => $availableCount > 0
|
||||
? '사용 가능한 계좌가 ' . $availableCount . '개 있습니다.' . ($warningCount > 0 ? ' (바로빌 미등록 계좌 ' . $warningCount . '개)' : '')
|
||||
: '사용 가능한 계좌가 없습니다.' . ($warningCount > 0 ? ' (로컬에만 등록된 계좌 ' . $warningCount . '개는 바로빌 API에 등록이 필요합니다)' : '')
|
||||
];
|
||||
|
||||
// 바로빌 API 오류 정보 추가
|
||||
if ($barobillError) {
|
||||
$response['barobill_error'] = $barobillError;
|
||||
$response['barobill_error_code'] = $barobillErrorCode;
|
||||
}
|
||||
|
||||
// 디버그 정보 추가
|
||||
if (isset($result['debug'])) {
|
||||
$response['debug'] = $result['debug'];
|
||||
}
|
||||
|
||||
// API 응답 구조 디버그 정보 추가
|
||||
if (isset($debugInfo)) {
|
||||
$response['api_debug'] = $debugInfo;
|
||||
}
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '서버 오류: ' . $e->getMessage(),
|
||||
'accounts' => [],
|
||||
'count' => 0
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 은행 코드 -> 은행명 변환
|
||||
*/
|
||||
function getBankName($code) {
|
||||
$banks = [
|
||||
'002' => 'KDB산업은행',
|
||||
'003' => 'IBK기업은행',
|
||||
'004' => 'KB국민은행',
|
||||
'007' => '수협은행',
|
||||
'011' => 'NH농협은행',
|
||||
'012' => '지역농축협',
|
||||
'020' => '우리은행',
|
||||
'023' => 'SC제일은행',
|
||||
'027' => '한국씨티은행',
|
||||
'031' => '대구은행',
|
||||
'032' => '부산은행',
|
||||
'034' => '광주은행',
|
||||
'035' => '제주은행',
|
||||
'037' => '전북은행',
|
||||
'039' => '경남은행',
|
||||
'045' => '새마을금고',
|
||||
'048' => '신협',
|
||||
'050' => '저축은행',
|
||||
'064' => '산림조합',
|
||||
'071' => '우체국',
|
||||
'081' => '하나은행',
|
||||
'088' => '신한은행',
|
||||
'089' => 'K뱅크',
|
||||
'090' => '카카오뱅크',
|
||||
'092' => '토스뱅크'
|
||||
];
|
||||
return $banks[$code] ?? $code;
|
||||
}
|
||||
?>
|
||||
|
||||
187
eaccount/api/accounts.php
Normal file
187
eaccount/api/accounts.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* 등록된 계좌 목록 조회 API (GetBankAccountEx)
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_account_config.php');
|
||||
|
||||
try {
|
||||
// 0: 전체, 1: 사용가능, 2: 해지
|
||||
$availOnly = isset($_GET['availOnly']) ? intval($_GET['availOnly']) : 0;
|
||||
|
||||
// GetBankAccountEx 호출
|
||||
$result = callBarobillAccountSOAP('GetBankAccountEx', [
|
||||
'AvailOnly' => $availOnly
|
||||
]);
|
||||
|
||||
if ($result['success']) {
|
||||
$accounts = [];
|
||||
$data = $result['data'];
|
||||
|
||||
// 에러 코드 체크 (전체 응답 레벨)
|
||||
if (isset($data->BankAccountEx)) {
|
||||
// 단일 객체가 에러 코드인 경우
|
||||
if (is_numeric($data->BankAccountEx) && $data->BankAccountEx < 0) {
|
||||
$errorCode = $data->BankAccountEx;
|
||||
$errorMsg = '계좌 목록 조회 실패: ' . $errorCode;
|
||||
|
||||
// 상세 에러 메시지 매핑
|
||||
if ($errorCode == -50214) {
|
||||
$errorMsg = '은행 로그인 실패 (-50214). 바로빌 사이트에서 계좌 비밀번호/인증서를 점검해주세요.';
|
||||
} else if ($errorCode == -24005) {
|
||||
$errorMsg = '사용자 정보 불일치 (-24005). 사업자번호를 확인해주세요.';
|
||||
} else if ($errorCode == -25001) {
|
||||
$errorMsg = '등록된 계좌가 없습니다 (-25001). 바로빌 사이트에서 계좌를 등록해주세요.';
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $errorMsg,
|
||||
'error_code' => $errorCode
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 실제 SOAP 응답 구조 확인:
|
||||
// GetBankAccountExResult -> BankAccount (단일 객체 또는 배열)
|
||||
// 또는 BankAccountEx (배열) - 다른 API 버전일 수 있음
|
||||
|
||||
$accountList = [];
|
||||
|
||||
// 우선순위 1: BankAccount 확인 (실제 응답 구조)
|
||||
if (isset($data->BankAccount)) {
|
||||
if (is_array($data->BankAccount)) {
|
||||
$accountList = $data->BankAccount;
|
||||
} else if (is_object($data->BankAccount)) {
|
||||
// 단일 객체인 경우 배열로 변환
|
||||
$accountList = [$data->BankAccount];
|
||||
}
|
||||
}
|
||||
// 우선순위 2: BankAccountEx 배열 확인 (다른 API 버전)
|
||||
else if (isset($data->BankAccountEx)) {
|
||||
if (is_array($data->BankAccountEx)) {
|
||||
$accountList = $data->BankAccountEx;
|
||||
} else if (is_object($data->BankAccountEx)) {
|
||||
// 단일 객체인 경우 배열로 변환
|
||||
$accountList = [$data->BankAccountEx];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($accountList as $acc) {
|
||||
// 객체가 아닌 경우 스킵
|
||||
if (!is_object($acc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 에러 코드 체크 (개별 계좌 레벨)
|
||||
if (isset($acc->BankAccountNum)) {
|
||||
// BankAccountNum이 음수인 경우 에러 코드
|
||||
if (is_numeric($acc->BankAccountNum) && $acc->BankAccountNum < 0) {
|
||||
continue;
|
||||
}
|
||||
// BankAccountNum이 비어있는 경우도 스킵
|
||||
if (empty($acc->BankAccountNum)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// BankAccountNum이 없는 경우도 스킵
|
||||
continue;
|
||||
}
|
||||
|
||||
// BankName으로 BankCode 추론 (응답에 BankCode가 없는 경우)
|
||||
$bankCode = $acc->BankCode ?? '';
|
||||
if (empty($bankCode) && isset($acc->BankName)) {
|
||||
// BankName으로 BankCode 찾기
|
||||
$bankName = $acc->BankName;
|
||||
$bankCodeMap = [
|
||||
'기업은행' => '003',
|
||||
'IBK기업은행' => '003',
|
||||
'KB국민은행' => '004',
|
||||
'국민은행' => '004',
|
||||
'우리은행' => '020',
|
||||
'신한은행' => '088',
|
||||
'하나은행' => '081',
|
||||
'NH농협은행' => '011',
|
||||
'농협은행' => '011'
|
||||
];
|
||||
$bankCode = $bankCodeMap[$bankName] ?? '';
|
||||
}
|
||||
|
||||
// UseState 처리: 없으면 기본값 1 (사용중)으로 설정
|
||||
$useState = isset($acc->UseState) ? intval($acc->UseState) : 1;
|
||||
|
||||
$accounts[] = [
|
||||
'bankAccountNum' => $acc->BankAccountNum ?? '',
|
||||
'bankCode' => $bankCode,
|
||||
'bankName' => getBankName($bankCode) ?: ($acc->BankName ?? ''),
|
||||
'accountName' => $acc->AccountName ?? '', // 계좌 별칭/이름
|
||||
'accountType' => $acc->AccountType ?? '', // 1:입출금, 2:예적금
|
||||
'currency' => $acc->Currency ?? 'KRW',
|
||||
'issueDate' => $acc->IssueDate ?? '',
|
||||
'balance' => $acc->Balance ?? 0,
|
||||
'status' => $useState // 1:사용, 0:중지, 2:해지
|
||||
];
|
||||
}
|
||||
|
||||
$response = [
|
||||
'success' => true,
|
||||
'accounts' => $accounts,
|
||||
'count' => count($accounts)
|
||||
];
|
||||
|
||||
// 디버그 정보 추가
|
||||
if (isset($result['debug'])) {
|
||||
$response['debug'] = $result['debug'];
|
||||
}
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $result['error'],
|
||||
'error_code' => $result['error_code'] ?? null
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '서버 오류: ' . $e->getMessage()
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 은행 코드 -> 은행명 변환
|
||||
*/
|
||||
function getBankName($code) {
|
||||
$banks = [
|
||||
'002' => 'KDB산업은행',
|
||||
'003' => 'IBK기업은행',
|
||||
'004' => 'KB국민은행',
|
||||
'007' => '수협은행',
|
||||
'011' => 'NH농협은행',
|
||||
'012' => '지역농축협',
|
||||
'020' => '우리은행',
|
||||
'023' => 'SC제일은행',
|
||||
'027' => '한국씨티은행',
|
||||
'031' => '대구은행',
|
||||
'032' => '부산은행',
|
||||
'034' => '광주은행',
|
||||
'035' => '제주은행',
|
||||
'037' => '전북은행',
|
||||
'039' => '경남은행',
|
||||
'045' => '새마을금고',
|
||||
'048' => '신협',
|
||||
'050' => '저축은행',
|
||||
'064' => '산림조합',
|
||||
'071' => '우체국',
|
||||
'081' => '하나은행',
|
||||
'088' => '신한은행',
|
||||
'089' => 'K뱅크',
|
||||
'090' => '카카오뱅크',
|
||||
'092' => '토스뱅크'
|
||||
];
|
||||
return $banks[$code] ?? $code;
|
||||
}
|
||||
?>
|
||||
360
eaccount/api/barobill_account_config.php
Normal file
360
eaccount/api/barobill_account_config.php
Normal file
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
/**
|
||||
* 바로빌 계좌 API 설정 파일
|
||||
*
|
||||
* ⚠️ 중요: 바로빌은 SOAP 웹서비스를 사용합니다 (REST API가 아님)
|
||||
*
|
||||
* 계좌 입출금내역 조회를 위해서는 바로빌 웹사이트(https://www.barobill.co.kr)에서
|
||||
* 계좌를 먼저 등록해야 합니다.
|
||||
*
|
||||
* 설정 파일:
|
||||
* 1. apikey/barobill_cert_key.txt - CERTKEY (인증서 키)
|
||||
* 2. apikey/barobill_corp_num.txt - 사업자번호
|
||||
* 3. apikey/barobill_test_mode.txt - 테스트 모드 설정 (선택)
|
||||
*/
|
||||
|
||||
// 인증서 키(CERTKEY) 파일 경로
|
||||
$certKeyFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt';
|
||||
$legacyApiKeyFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_api_key.txt';
|
||||
$corpNumFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt';
|
||||
$testModeFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_test_mode.txt';
|
||||
|
||||
// CERTKEY 읽기
|
||||
$barobillCertKey = '';
|
||||
if (file_exists($certKeyFile)) {
|
||||
$content = trim(file_get_contents($certKeyFile));
|
||||
|
||||
// 설명 텍스트 필터링: 실제 CERTKEY만 추출
|
||||
// 설명 텍스트 패턴 체크
|
||||
$isPlaceholder = false;
|
||||
$placeholderPatterns = [
|
||||
'/^\[여기에/', // [여기에로 시작
|
||||
'/^=/', // =로 시작
|
||||
'/바로빌 CERTKEY/', // '바로빌 CERTKEY' 문자열 포함
|
||||
'/================================/', // 구분선 포함
|
||||
'/설정 방법:/', // '설정 방법:' 포함
|
||||
'/인증서 관리/', // '인증서 관리' 포함
|
||||
'/개발자센터/', // '개발자센터' 포함
|
||||
'/⚠️/', // 경고 이모지 포함
|
||||
'/참고:/', // '참고:' 포함
|
||||
];
|
||||
|
||||
foreach ($placeholderPatterns as $pattern) {
|
||||
if (preg_match($pattern, $content)) {
|
||||
$isPlaceholder = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 실제 CERTKEY는 보통 20자 이상의 영문/숫자 조합
|
||||
// 설명 텍스트가 아니고, 충분히 긴 경우에만 CERTKEY로 인식
|
||||
if (!empty($content) && !$isPlaceholder && strlen($content) >= 10) {
|
||||
// 추가 검증: 실제 CERTKEY는 보통 영문/숫자/하이픈 조합
|
||||
// 설명 텍스트는 한글이나 특수문자가 많음
|
||||
$koreanCharCount = preg_match_all('/[가-힣]/u', $content);
|
||||
$totalCharCount = mb_strlen($content, 'UTF-8');
|
||||
|
||||
// 한글 비율이 10% 미만이고, 길이가 적절하면 CERTKEY로 인식
|
||||
if ($koreanCharCount / max($totalCharCount, 1) < 0.1) {
|
||||
$barobillCertKey = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($barobillCertKey) && file_exists($legacyApiKeyFile)) {
|
||||
$barobillCertKey = trim(file_get_contents($legacyApiKeyFile));
|
||||
}
|
||||
|
||||
// 사업자번호 읽기
|
||||
$barobillCorpNum = '';
|
||||
if (file_exists($corpNumFile)) {
|
||||
$content = trim(file_get_contents($corpNumFile));
|
||||
if (!empty($content) && !preg_match('/^\[여기에/', $content)) {
|
||||
$barobillCorpNum = str_replace('-', '', $content);
|
||||
}
|
||||
}
|
||||
|
||||
// 테스트 모드 확인
|
||||
$isTestMode = false;
|
||||
if (file_exists($testModeFile)) {
|
||||
$testMode = trim(file_get_contents($testModeFile));
|
||||
$isTestMode = (strtolower($testMode) === 'test' || strtolower($testMode) === 'true');
|
||||
}
|
||||
|
||||
// 바로빌 사용자 ID (계좌 사용내역 조회에 필요)
|
||||
// 빈 값이면 전체 계좌 조회, 특정 사용자만 조회하려면 사용자 ID 입력
|
||||
$barobillUserIdFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt';
|
||||
$barobillUserId = '';
|
||||
if (file_exists($barobillUserIdFile)) {
|
||||
$content = trim(file_get_contents($barobillUserIdFile));
|
||||
if (!empty($content) && !preg_match('/^\[여기에/', $content)) {
|
||||
$barobillUserId = $content;
|
||||
}
|
||||
}
|
||||
|
||||
// 테넌트별 설정 (DB에서 가져오기)
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
|
||||
|
||||
$selectedTenantId = $_SESSION['eaccount_tenant_id'] ?? null;
|
||||
|
||||
// DB에서 테넌트 정보 가져오기
|
||||
if ($selectedTenantId) {
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
if ($pdo) {
|
||||
$sql = "SELECT id, company_name, corp_num, barobill_user_id
|
||||
FROM {$DB}.barobill_companies
|
||||
WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$selectedTenantId]);
|
||||
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($tenant) {
|
||||
$barobillUserId = $tenant['barobill_user_id'];
|
||||
$barobillCorpNum = $tenant['corp_num'];
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('테넌트 정보 로드 실패: ' . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
// 세션에 테넌트 ID가 없으면 '(주)주일기업'을 기본값으로 찾기
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
if ($pdo) {
|
||||
// '(주)주일기업' 또는 barobill_user_id가 'juil5130'인 회사 찾기
|
||||
$sql = "SELECT id, company_name, corp_num, barobill_user_id
|
||||
FROM {$DB}.barobill_companies
|
||||
WHERE company_name LIKE '%주일기업%'
|
||||
OR company_name LIKE '%주일%'
|
||||
OR barobill_user_id = 'juil5130'
|
||||
ORDER BY id ASC
|
||||
LIMIT 1";
|
||||
$stmt = $pdo->query($sql);
|
||||
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($tenant) {
|
||||
$barobillUserId = $tenant['barobill_user_id'];
|
||||
$barobillCorpNum = $tenant['corp_num'];
|
||||
$selectedTenantId = $tenant['id'];
|
||||
// 세션에 저장
|
||||
$_SESSION['eaccount_tenant_id'] = $selectedTenantId;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('기본 테넌트 정보 로드 실패: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 사용자 ID 반환
|
||||
*/
|
||||
function getBarobillUserId() {
|
||||
global $barobillUserId;
|
||||
return $barobillUserId;
|
||||
}
|
||||
|
||||
// 바로빌 계좌 SOAP 웹서비스 URL (BANK.asmx)
|
||||
// 바로빌 계좌 SOAP 웹서비스 URL (BANKACCOUNT.asmx)
|
||||
$barobillAccountSoapUrl = $isTestMode
|
||||
? 'https://testws.baroservice.com/BANKACCOUNT.asmx?WSDL' // 테스트 환경
|
||||
: 'https://ws.baroservice.com/BANKACCOUNT.asmx?WSDL'; // 운영 환경
|
||||
|
||||
// SOAP 클라이언트 초기화
|
||||
$barobillAccountSoapClient = null;
|
||||
$barobillInitError = '';
|
||||
|
||||
if (!empty($barobillCertKey) || $isTestMode) {
|
||||
try {
|
||||
// SSL 검증 비활성화 및 타임아웃 설정
|
||||
$context = stream_context_create([
|
||||
'ssl' => [
|
||||
'verify_peer' => false,
|
||||
'verify_peer_name' => false,
|
||||
'allow_self_signed' => true
|
||||
]
|
||||
]);
|
||||
|
||||
$barobillAccountSoapClient = new SoapClient($barobillAccountSoapUrl, [
|
||||
'trace' => true,
|
||||
'encoding' => 'UTF-8',
|
||||
'exceptions' => true,
|
||||
'connection_timeout' => 30,
|
||||
'stream_context' => $context,
|
||||
'cache_wsdl' => WSDL_CACHE_NONE // WSDL 캐시 비활성화
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$barobillInitError = $e->getMessage();
|
||||
error_log('바로빌 계좌 SOAP 클라이언트 생성 실패: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 계좌 SOAP 웹서비스 호출 함수
|
||||
*
|
||||
* @param string $method SOAP 메서드명
|
||||
* @param array $params SOAP 메서드 파라미터
|
||||
* @return array 응답 데이터
|
||||
*/
|
||||
function callBarobillAccountSOAP($method, $params = []) {
|
||||
global $barobillAccountSoapClient, $barobillCertKey, $barobillCorpNum, $isTestMode, $barobillInitError, $barobillAccountSoapUrl;
|
||||
|
||||
if (!$barobillAccountSoapClient) {
|
||||
$errorMsg = $isTestMode
|
||||
? '바로빌 계좌 SOAP 클라이언트가 초기화되지 않았습니다. (' . ($barobillInitError ?: '알 수 없는 오류') . ')'
|
||||
: '바로빌 계좌 SOAP 클라이언트가 초기화되지 않았습니다. CERTKEY를 확인하세요. (' . ($barobillInitError ?: '알 수 없는 오류') . ')';
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $errorMsg,
|
||||
'error_detail' => [
|
||||
'cert_key_file' => $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt',
|
||||
'soap_url' => $barobillAccountSoapUrl,
|
||||
'init_error' => $barobillInitError,
|
||||
'test_mode' => $isTestMode
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if (empty($barobillCertKey) && !$isTestMode) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'CERTKEY가 설정되지 않았습니다. apikey/barobill_cert_key.txt 파일을 확인하세요.'
|
||||
];
|
||||
}
|
||||
|
||||
if (empty($barobillCorpNum)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '사업자번호가 설정되지 않았습니다. apikey/barobill_corp_num.txt 파일을 확인하세요.'
|
||||
];
|
||||
}
|
||||
|
||||
// CERTKEY와 CorpNum 자동 추가
|
||||
// 테스트 모드에서도 CERTKEY가 있으면 사용 (일부 API는 테스트 모드에서도 CERTKEY 필요)
|
||||
if (!isset($params['CERTKEY'])) {
|
||||
if ($isTestMode) {
|
||||
// 테스트 모드: CERTKEY가 있으면 사용, 없으면 빈 값
|
||||
// 주의: 일부 API는 테스트 모드에서도 CERTKEY가 필요할 수 있음
|
||||
$params['CERTKEY'] = !empty($barobillCertKey) ? $barobillCertKey : '';
|
||||
} else {
|
||||
// 운영 모드: CERTKEY 필수
|
||||
$params['CERTKEY'] = $barobillCertKey;
|
||||
}
|
||||
}
|
||||
if (!isset($params['CorpNum'])) {
|
||||
$params['CorpNum'] = $barobillCorpNum;
|
||||
}
|
||||
|
||||
try {
|
||||
error_log('바로빌 계좌 API 호출 - Method: ' . $method . ', CorpNum: ' . $barobillCorpNum);
|
||||
|
||||
// SOAP 요청 로그 수집 (CERTKEY는 마스킹)
|
||||
$logParams = $params;
|
||||
if (isset($logParams['CERTKEY'])) {
|
||||
$logParams['CERTKEY'] = substr($logParams['CERTKEY'], 0, 8) . '...' . substr($logParams['CERTKEY'], -4);
|
||||
}
|
||||
|
||||
$soapRequest = [
|
||||
'method' => $method,
|
||||
'url' => $barobillAccountSoapUrl,
|
||||
'params' => $logParams,
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$result = $barobillAccountSoapClient->$method($params);
|
||||
|
||||
// SOAP 요청/응답 XML 로그 수집
|
||||
$soapRequestXml = $barobillAccountSoapClient->__getLastRequest();
|
||||
$soapResponseXml = $barobillAccountSoapClient->__getLastResponse();
|
||||
|
||||
$resultProperty = $method . 'Result';
|
||||
if (isset($result->$resultProperty)) {
|
||||
$resultData = $result->$resultProperty;
|
||||
|
||||
// 에러 코드 체크 (음수 값 또는 객체 내부의 음수 값)
|
||||
$errorCode = null;
|
||||
|
||||
// 직접 숫자로 반환된 경우
|
||||
if (is_numeric($resultData) && $resultData < 0) {
|
||||
$errorCode = $resultData;
|
||||
}
|
||||
// 객체 내부에 BankAccountNum이 음수인 경우 (예: -10002)
|
||||
elseif (is_object($resultData)) {
|
||||
if (isset($resultData->BankAccountNum) && is_numeric($resultData->BankAccountNum) && $resultData->BankAccountNum < 0) {
|
||||
$errorCode = $resultData->BankAccountNum;
|
||||
}
|
||||
// 다른 필드에서도 음수 값 체크
|
||||
foreach (get_object_vars($resultData) as $key => $value) {
|
||||
if (is_numeric($value) && $value < 0 && ($key == 'CurrentPage' || $key == 'ErrorCode' || $key == 'ResultCode')) {
|
||||
$errorCode = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($errorCode !== null) {
|
||||
$errorMsg = '바로빌 계좌 API 오류 코드: ' . $errorCode;
|
||||
|
||||
// 상세 에러 메시지 매핑
|
||||
$errorMessages = [
|
||||
-10002 => '인증 실패 (-10002). CERTKEY가 올바르지 않거나 만료되었습니다. 바로빌 개발자센터에서 CERTKEY를 확인하세요.',
|
||||
-50214 => '은행 로그인 실패 (-50214). 바로빌 사이트에서 계좌 비밀번호/인증서를 점검해주세요.',
|
||||
-24005 => '사용자 정보 불일치 (-24005). 사업자번호를 확인해주세요.',
|
||||
-25001 => '등록된 계좌가 없습니다 (-25001). 바로빌 사이트에서 계좌를 등록해주세요.',
|
||||
-25005 => '조회된 데이터가 없습니다 (-25005).',
|
||||
-25006 => '계좌번호가 잘못되었습니다 (-25006).',
|
||||
-25007 => '조회 기간이 잘못되었습니다 (-25007).',
|
||||
];
|
||||
|
||||
if (isset($errorMessages[$errorCode])) {
|
||||
$errorMsg = $errorMessages[$errorCode];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $errorMsg,
|
||||
'error_code' => $errorCode,
|
||||
'debug' => [
|
||||
'request' => $soapRequest,
|
||||
'request_xml' => $soapRequestXml,
|
||||
'response_xml' => $soapResponseXml
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $resultData,
|
||||
'debug' => [
|
||||
'request' => $soapRequest,
|
||||
'request_xml' => $soapRequestXml,
|
||||
'response_xml' => $soapResponseXml
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $result,
|
||||
'debug' => [
|
||||
'request' => $soapRequest,
|
||||
'request_xml' => $soapRequestXml,
|
||||
'response_xml' => $soapResponseXml
|
||||
]
|
||||
];
|
||||
|
||||
} catch (SoapFault $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'SOAP 오류: ' . $e->getMessage(),
|
||||
'error_code' => $e->getCode()
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'API 호출 오류: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
?>
|
||||
398
eaccount/api/barobill_card_config.php
Normal file
398
eaccount/api/barobill_card_config.php
Normal file
@@ -0,0 +1,398 @@
|
||||
<?php
|
||||
/**
|
||||
* 바로빌 카드 API 설정 파일
|
||||
*
|
||||
* ⚠️ 중요: 바로빌은 SOAP 웹서비스를 사용합니다 (REST API가 아님)
|
||||
*
|
||||
* 카드 사용내역 조회를 위해서는 바로빌 웹사이트(https://www.barobill.co.kr)에서
|
||||
* 카드를 먼저 등록해야 합니다.
|
||||
*
|
||||
* 설정 파일:
|
||||
* 1. apikey/barobill_cert_key.txt - CERTKEY (인증서 키)
|
||||
* 2. apikey/barobill_corp_num.txt - 사업자번호
|
||||
* 3. apikey/barobill_test_mode.txt - 테스트 모드 설정 (선택)
|
||||
*/
|
||||
|
||||
// 인증서 키(CERTKEY) 파일 경로
|
||||
$certKeyFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt';
|
||||
$legacyApiKeyFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_api_key.txt';
|
||||
$corpNumFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt';
|
||||
$testModeFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_test_mode.txt';
|
||||
|
||||
// CERTKEY 읽기
|
||||
$barobillCertKey = '';
|
||||
if (file_exists($certKeyFile)) {
|
||||
$content = trim(file_get_contents($certKeyFile));
|
||||
// 설명 텍스트가 아닌 실제 키만 추출 (대괄호 안의 내용 제외, =로 시작하는 경우 제외)
|
||||
if (!empty($content) && !preg_match('/^\[여기에/', $content) && !preg_match('/^=/', $content) && strpos($content, '바로빌 CERTKEY') === false) {
|
||||
$barobillCertKey = $content;
|
||||
}
|
||||
}
|
||||
if (empty($barobillCertKey) && file_exists($legacyApiKeyFile)) {
|
||||
$barobillCertKey = trim(file_get_contents($legacyApiKeyFile));
|
||||
}
|
||||
|
||||
// 사업자번호 읽기
|
||||
$barobillCorpNum = '';
|
||||
if (file_exists($corpNumFile)) {
|
||||
$content = trim(file_get_contents($corpNumFile));
|
||||
if (!empty($content) && !preg_match('/^\[여기에/', $content)) {
|
||||
$barobillCorpNum = str_replace('-', '', $content);
|
||||
}
|
||||
}
|
||||
|
||||
// 테스트 모드 확인
|
||||
$isTestMode = false;
|
||||
if (file_exists($testModeFile)) {
|
||||
$testMode = trim(file_get_contents($testModeFile));
|
||||
$isTestMode = (strtolower($testMode) === 'test' || strtolower($testMode) === 'true');
|
||||
}
|
||||
|
||||
// 바로빌 사용자 ID (카드 사용내역 조회에 필요)
|
||||
// 빈 값이면 전체 카드 조회, 특정 사용자만 조회하려면 사용자 ID 입력
|
||||
$barobillUserIdFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt';
|
||||
$barobillUserId = '';
|
||||
if (file_exists($barobillUserIdFile)) {
|
||||
$content = trim(file_get_contents($barobillUserIdFile));
|
||||
if (!empty($content) && !preg_match('/^\[여기에/', $content)) {
|
||||
$barobillUserId = $content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 사용자 ID 반환
|
||||
*/
|
||||
function getBarobillUserId() {
|
||||
global $barobillUserId;
|
||||
return $barobillUserId;
|
||||
}
|
||||
|
||||
// 바로빌 카드 SOAP 웹서비스 URL
|
||||
$barobillCardSoapUrl = $isTestMode
|
||||
? 'https://testws.baroservice.com/CARD.asmx?WSDL' // 테스트 환경
|
||||
: 'https://ws.baroservice.com/CARD.asmx?WSDL'; // 운영 환경
|
||||
|
||||
// SOAP 클라이언트 초기화
|
||||
$barobillCardSoapClient = null;
|
||||
if (!empty($barobillCertKey) || $isTestMode) {
|
||||
try {
|
||||
$barobillCardSoapClient = new SoapClient($barobillCardSoapUrl, [
|
||||
'trace' => true,
|
||||
'encoding' => 'UTF-8',
|
||||
'exceptions' => true,
|
||||
'connection_timeout' => 30
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log('바로빌 카드 SOAP 클라이언트 생성 실패: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 카드 SOAP 웹서비스 호출 함수
|
||||
*
|
||||
* @param string $method SOAP 메서드명
|
||||
* @param array $params SOAP 메서드 파라미터
|
||||
* @return array 응답 데이터
|
||||
*/
|
||||
function callBarobillCardSOAP($method, $params = []) {
|
||||
global $barobillCardSoapClient, $barobillCertKey, $barobillCorpNum, $isTestMode;
|
||||
|
||||
if (!$barobillCardSoapClient) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '바로빌 카드 SOAP 클라이언트가 초기화되지 않았습니다. CERTKEY를 확인하세요.',
|
||||
'error_detail' => [
|
||||
'cert_key_file' => $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt',
|
||||
'soap_url' => $isTestMode ? 'https://testws.baroservice.com/CARD.asmx?WSDL' : 'https://ws.baroservice.com/CARD.asmx?WSDL'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if (empty($barobillCertKey) && !$isTestMode) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'CERTKEY가 설정되지 않았습니다. apikey/barobill_cert_key.txt 파일을 확인하세요.'
|
||||
];
|
||||
}
|
||||
|
||||
if (empty($barobillCorpNum)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '사업자번호가 설정되지 않았습니다. apikey/barobill_corp_num.txt 파일을 확인하세요.'
|
||||
];
|
||||
}
|
||||
|
||||
// CERTKEY와 CorpNum 자동 추가
|
||||
if (!isset($params['CERTKEY'])) {
|
||||
$params['CERTKEY'] = $barobillCertKey;
|
||||
}
|
||||
if (!isset($params['CorpNum'])) {
|
||||
$params['CorpNum'] = $barobillCorpNum;
|
||||
}
|
||||
|
||||
try {
|
||||
error_log('바로빌 카드 API 호출 - Method: ' . $method . ', CorpNum: ' . $barobillCorpNum);
|
||||
|
||||
$result = $barobillCardSoapClient->$method($params);
|
||||
|
||||
$resultProperty = $method . 'Result';
|
||||
if (isset($result->$resultProperty)) {
|
||||
$resultData = $result->$resultProperty;
|
||||
|
||||
// 에러 코드 체크 (음수 값)
|
||||
if (is_numeric($resultData) && $resultData < 0) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '바로빌 카드 API 오류 코드: ' . $resultData,
|
||||
'error_code' => $resultData
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $resultData
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $result
|
||||
];
|
||||
|
||||
} catch (SoapFault $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'SOAP 오류: ' . $e->getMessage(),
|
||||
'error_code' => $e->getCode()
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'API 호출 오류: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 등록된 카드 목록 조회 (GetCardEx2 API 사용)
|
||||
* API 레퍼런스: https://dev.barobill.co.kr/docs/references/카드조회-API#GetCardEx2
|
||||
*
|
||||
* @param int $availOnly 0: 전체, 1: 사용가능한 카드만
|
||||
* @return array 카드 목록
|
||||
*/
|
||||
function getCardList($availOnly = 0) {
|
||||
$result = callBarobillCardSOAP('GetCardEx2', [
|
||||
'AvailOnly' => $availOnly
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$cards = [];
|
||||
$data = $result['data'];
|
||||
|
||||
// GetCardEx2는 CardEx 배열을 반환
|
||||
if (!isset($data->CardEx)) {
|
||||
return ['success' => true, 'data' => []];
|
||||
}
|
||||
|
||||
if (!is_array($data->CardEx)) {
|
||||
$cards = [$data->CardEx];
|
||||
} else {
|
||||
$cards = $data->CardEx;
|
||||
}
|
||||
|
||||
// 에러 체크: CardNum이 음수면 에러 코드
|
||||
if (count($cards) == 1 && isset($cards[0]->CardNum) && $cards[0]->CardNum < 0) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '카드 목록 조회 실패',
|
||||
'error_code' => $cards[0]->CardNum
|
||||
];
|
||||
}
|
||||
|
||||
return ['success' => true, 'data' => $cards];
|
||||
}
|
||||
|
||||
/**
|
||||
* 기간별 카드 사용내역 조회
|
||||
*
|
||||
* @param string $cardNum 카드번호 (빈값이면 전체)
|
||||
* @param string $startDate 시작일 (YYYYMMDD)
|
||||
* @param string $endDate 종료일 (YYYYMMDD)
|
||||
* @param int $countPerPage 페이지당 건수
|
||||
* @param int $currentPage 현재 페이지
|
||||
* @param int $orderDirection 정렬 (1: 오름차순, 2: 내림차순)
|
||||
* @param string $userId 바로빌 사용자 ID (빈값이면 전체)
|
||||
* @return array 사용내역
|
||||
*/
|
||||
function getPeriodCardUsage($cardNum = '', $startDate = '', $endDate = '', $countPerPage = 50, $currentPage = 1, $orderDirection = 2, $userId = '') {
|
||||
global $barobillCorpNum;
|
||||
|
||||
// 바로빌 사용자 ID 파일에서 읽기 (없으면 빈값)
|
||||
$barobillUserId = getBarobillUserId();
|
||||
if (!empty($userId)) {
|
||||
$barobillUserId = $userId;
|
||||
}
|
||||
|
||||
$result = callBarobillCardSOAP('GetPeriodCardApprovalLog', [
|
||||
'ID' => $barobillUserId,
|
||||
'CardNum' => $cardNum,
|
||||
'StartDate' => $startDate,
|
||||
'EndDate' => $endDate,
|
||||
'CountPerPage' => $countPerPage,
|
||||
'CurrentPage' => $currentPage,
|
||||
'OrderDirection' => $orderDirection
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return parseCardUsageResult($result['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 일별 카드 사용내역 조회
|
||||
*
|
||||
* @param string $cardNum 카드번호 (빈값이면 전체)
|
||||
* @param string $baseDate 기준일 (YYYYMMDD)
|
||||
* @param int $countPerPage 페이지당 건수
|
||||
* @param int $currentPage 현재 페이지
|
||||
* @param int $orderDirection 정렬 (1: 오름차순, 2: 내림차순)
|
||||
* @param string $userId 바로빌 사용자 ID (빈값이면 전체)
|
||||
* @return array 사용내역
|
||||
*/
|
||||
function getDailyCardUsage($cardNum = '', $baseDate = '', $countPerPage = 50, $currentPage = 1, $orderDirection = 2, $userId = '') {
|
||||
$barobillUserId = getBarobillUserId();
|
||||
if (!empty($userId)) {
|
||||
$barobillUserId = $userId;
|
||||
}
|
||||
|
||||
$result = callBarobillCardSOAP('GetDailyCardApprovalLog', [
|
||||
'ID' => $barobillUserId,
|
||||
'CardNum' => $cardNum,
|
||||
'BaseDate' => $baseDate,
|
||||
'CountPerPage' => $countPerPage,
|
||||
'CurrentPage' => $currentPage,
|
||||
'OrderDirection' => $orderDirection
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return parseCardUsageResult($result['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 월별 카드 사용내역 조회
|
||||
*
|
||||
* @param string $cardNum 카드번호 (빈값이면 전체)
|
||||
* @param string $baseMonth 기준월 (YYYYMM)
|
||||
* @param int $countPerPage 페이지당 건수
|
||||
* @param int $currentPage 현재 페이지
|
||||
* @param int $orderDirection 정렬 (1: 오름차순, 2: 내림차순)
|
||||
* @param string $userId 바로빌 사용자 ID (빈값이면 전체)
|
||||
* @return array 사용내역
|
||||
*/
|
||||
function getMonthlyCardUsage($cardNum = '', $baseMonth = '', $countPerPage = 50, $currentPage = 1, $orderDirection = 2, $userId = '') {
|
||||
$barobillUserId = getBarobillUserId();
|
||||
if (!empty($userId)) {
|
||||
$barobillUserId = $userId;
|
||||
}
|
||||
|
||||
$result = callBarobillCardSOAP('GetMonthlyCardApprovalLog', [
|
||||
'ID' => $barobillUserId,
|
||||
'CardNum' => $cardNum,
|
||||
'BaseMonth' => $baseMonth,
|
||||
'CountPerPage' => $countPerPage,
|
||||
'CurrentPage' => $currentPage,
|
||||
'OrderDirection' => $orderDirection
|
||||
]);
|
||||
|
||||
if (!$result['success']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return parseCardUsageResult($result['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드 사용내역 결과 파싱
|
||||
*
|
||||
* @param object $data SOAP 응답 데이터
|
||||
* @return array 파싱된 결과
|
||||
*/
|
||||
function parseCardUsageResult($data) {
|
||||
// 에러 체크
|
||||
if (isset($data->CurrentPage) && $data->CurrentPage < 0) {
|
||||
$errorCode = $data->CurrentPage;
|
||||
|
||||
// -24005: 조회 데이터 없음 (정상 케이스로 처리)
|
||||
// -24001: 등록된 카드 없음
|
||||
// -24002: 조회 기간 오류
|
||||
if ($errorCode == -24005 || $errorCode == -24001) {
|
||||
// 데이터 없음 - 빈 배열 반환 (에러가 아님)
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'currentPage' => 1,
|
||||
'countPerPage' => 50,
|
||||
'maxPageNum' => 1,
|
||||
'maxIndex' => 0,
|
||||
'logs' => []
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => '카드 사용내역 조회 실패',
|
||||
'error_code' => $errorCode
|
||||
];
|
||||
}
|
||||
|
||||
$logs = [];
|
||||
if (isset($data->CardLogList) && isset($data->CardLogList->CardApprovalLog)) {
|
||||
if (!is_array($data->CardLogList->CardApprovalLog)) {
|
||||
$logs = [$data->CardLogList->CardApprovalLog];
|
||||
} else {
|
||||
$logs = $data->CardLogList->CardApprovalLog;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'currentPage' => $data->CurrentPage ?? 1,
|
||||
'countPerPage' => $data->CountPerPage ?? 50,
|
||||
'maxPageNum' => $data->MaxPageNum ?? 1,
|
||||
'maxIndex' => $data->MaxIndex ?? 0,
|
||||
'logs' => $logs
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드 등록
|
||||
*
|
||||
* @param array $cardData 카드 데이터
|
||||
* @return array 응답 데이터
|
||||
*/
|
||||
function registerCard($cardData) {
|
||||
return callBarobillCardSOAP('RegistCardEx', [
|
||||
'CollectCycle' => $cardData['collectCycle'] ?? '1', // 수집주기 (1: 1일 1회)
|
||||
'CardCompany' => $cardData['cardCompany'] ?? '', // 카드사 코드
|
||||
'CardType' => $cardData['cardType'] ?? '1', // 카드 종류 (1: 개인, 2: 법인)
|
||||
'CardNum' => $cardData['cardNum'] ?? '', // 카드번호
|
||||
'WebId' => $cardData['webId'] ?? '', // 카드사 웹 ID
|
||||
'WebPwd' => $cardData['webPwd'] ?? '', // 카드사 웹 비밀번호
|
||||
'Alias' => $cardData['alias'] ?? '', // 카드 별칭
|
||||
'Usage' => $cardData['usage'] ?? '1' // 용도 (1: 세금계산서, 2: 기타)
|
||||
]);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
225
eaccount/api/cards.php
Normal file
225
eaccount/api/cards.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
/**
|
||||
* 등록된 카드 목록 조회 API (GetCardEx2)
|
||||
* API 레퍼런스: https://dev.barobill.co.kr/docs/references/카드조회-API#GetCardEx2
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_card_config.php');
|
||||
|
||||
try {
|
||||
$availOnly = isset($_GET['availOnly']) ? intval($_GET['availOnly']) : 0;
|
||||
|
||||
$result = getCardList($availOnly);
|
||||
|
||||
if ($result['success']) {
|
||||
$cards = [];
|
||||
foreach ($result['data'] as $card) {
|
||||
// GetCardEx2 응답 필드 매핑
|
||||
// CardCompanyCode (등록 시), CardCompanyName (조회 시)
|
||||
$cardCompanyCode = $card->CardCompanyCode ?? $card->CardCompany ?? '';
|
||||
|
||||
// 카드 브랜드 (비자, 마스터카드 등) 추측
|
||||
$cardBrand = guessCardTypeFromNumber($card->CardNum ?? '');
|
||||
|
||||
// 카드 회사명 (신한, KB 등)
|
||||
$cardCompanyName = !empty($card->CardCompanyName)
|
||||
? $card->CardCompanyName
|
||||
: getCardCompanyName($cardCompanyCode);
|
||||
|
||||
$cards[] = [
|
||||
'cardNum' => $card->CardNum ?? '',
|
||||
'cardNumMasked' => maskCardNumber($card->CardNum ?? ''),
|
||||
'cardCompany' => $cardCompanyCode,
|
||||
'cardCompanyName' => $cardCompanyName,
|
||||
'cardBrand' => $cardBrand, // 카드 브랜드 (비자, 마스터카드 등)
|
||||
'alias' => $card->Alias ?? '',
|
||||
'cardType' => $card->CardType ?? '',
|
||||
'cardTypeName' => getCardTypeName($card->CardType ?? ''),
|
||||
'status' => $card->Status ?? '',
|
||||
'statusName' => getCardStatusName($card->Status ?? ''),
|
||||
'collectCycle' => $card->CollectCycle ?? '',
|
||||
'collectCycleName' => getCollectCycleName($card->CollectCycle ?? ''),
|
||||
'lastCollectDate' => formatDate($card->LastCollectDate ?? ''),
|
||||
'lastCollectResult' => $card->LastCollectResult ?? '',
|
||||
'lastCollectResultName' => getCollectResultName($card->LastCollectResult ?? ''),
|
||||
'nextExtendDate' => formatDate($card->NextExtendDate ?? ''),
|
||||
'registDate' => formatDate($card->RegistDate ?? ''),
|
||||
'webId' => $card->WebId ?? ''
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'cards' => $cards,
|
||||
'count' => count($cards)
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $result['error'],
|
||||
'error_code' => $result['error_code'] ?? null
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '서버 오류: ' . $e->getMessage()
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드번호 마스킹
|
||||
*/
|
||||
function maskCardNumber($cardNum) {
|
||||
if (strlen($cardNum) < 8) return $cardNum;
|
||||
return substr($cardNum, 0, 4) . '-****-****-' . substr($cardNum, -4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 날짜 포맷팅
|
||||
*/
|
||||
function formatDate($date) {
|
||||
if (empty($date)) return '';
|
||||
if (strlen($date) === 8) {
|
||||
return substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드번호로 카드 종류 추측 (BIN 코드 기반)
|
||||
*/
|
||||
function guessCardTypeFromNumber($cardNum) {
|
||||
if (empty($cardNum) || strlen($cardNum) < 4) {
|
||||
return '카드';
|
||||
}
|
||||
|
||||
$bin = substr($cardNum, 0, 4);
|
||||
|
||||
// 주요 카드사 BIN 코드
|
||||
$binMappings = [
|
||||
'4518' => '비자',
|
||||
'4092' => '비자',
|
||||
'4569' => '비자',
|
||||
'4563' => '비자',
|
||||
'5' => '마스터카드', // 5로 시작
|
||||
'3528' => 'JCB',
|
||||
'3529' => 'JCB',
|
||||
'3' => '아멕스/다이너스', // 34, 37로 시작
|
||||
'9' => '국내전용카드'
|
||||
];
|
||||
|
||||
// 정확한 매칭 시도
|
||||
if (isset($binMappings[$bin])) {
|
||||
return $binMappings[$bin];
|
||||
}
|
||||
|
||||
// 첫 번째 숫자로 매칭 시도
|
||||
$firstDigit = substr($cardNum, 0, 1);
|
||||
if (isset($binMappings[$firstDigit])) {
|
||||
return $binMappings[$firstDigit];
|
||||
}
|
||||
|
||||
return '카드';
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드사 코드 -> 이름 변환
|
||||
* 바로빌 카드사 코드 참고
|
||||
*/
|
||||
function getCardCompanyName($code) {
|
||||
$companies = [
|
||||
'01' => '비씨카드',
|
||||
'02' => 'KB국민카드',
|
||||
'03' => '하나카드(외환)',
|
||||
'04' => '삼성카드',
|
||||
'06' => '신한카드',
|
||||
'07' => '현대카드',
|
||||
'08' => '롯데카드',
|
||||
'11' => 'NH농협카드',
|
||||
'12' => '수협카드',
|
||||
'13' => '씨티카드',
|
||||
'14' => '우리카드',
|
||||
'15' => '광주카드',
|
||||
'16' => '전북카드',
|
||||
'21' => '하나카드',
|
||||
'22' => '제주카드',
|
||||
'23' => 'SC제일카드',
|
||||
'25' => 'KDB산업카드',
|
||||
'26' => 'IBK기업카드',
|
||||
'27' => '새마을금고',
|
||||
'28' => '신협카드',
|
||||
'29' => '저축은행',
|
||||
'30' => '우체국카드',
|
||||
'31' => '카카오뱅크',
|
||||
'32' => 'K뱅크',
|
||||
'33' => '토스뱅크',
|
||||
'BC' => '비씨카드',
|
||||
'KB' => 'KB국민카드',
|
||||
'HANA' => '하나카드',
|
||||
'SAMSUNG' => '삼성카드',
|
||||
'SHINHAN' => '신한카드',
|
||||
'HYUNDAI' => '현대카드',
|
||||
'LOTTE' => '롯데카드',
|
||||
'NH' => 'NH농협카드',
|
||||
'SUHYUP' => '수협카드',
|
||||
'CITI' => '씨티카드',
|
||||
'WOORI' => '우리카드',
|
||||
'KJBANK' => '광주카드',
|
||||
'JBBANK' => '전북카드'
|
||||
];
|
||||
return $companies[$code] ?? $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드 종류 코드 -> 이름 변환
|
||||
*/
|
||||
function getCardTypeName($type) {
|
||||
$types = [
|
||||
'1' => '개인카드',
|
||||
'2' => '법인카드'
|
||||
];
|
||||
return $types[$type] ?? $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드 상태 코드 -> 이름 변환
|
||||
*/
|
||||
function getCardStatusName($status) {
|
||||
$statuses = [
|
||||
'0' => '대기중',
|
||||
'1' => '정상',
|
||||
'2' => '해지',
|
||||
'3' => '수집오류',
|
||||
'4' => '일시중지'
|
||||
];
|
||||
return $statuses[$status] ?? $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 수집주기 코드 -> 이름 변환
|
||||
*/
|
||||
function getCollectCycleName($cycle) {
|
||||
$cycles = [
|
||||
'1' => '1일 1회',
|
||||
'2' => '1일 2회',
|
||||
'3' => '1일 3회'
|
||||
];
|
||||
return $cycles[$cycle] ?? $cycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 수집결과 코드 -> 이름 변환
|
||||
*/
|
||||
function getCollectResultName($result) {
|
||||
$results = [
|
||||
'0' => '대기',
|
||||
'1' => '성공',
|
||||
'2' => '실패',
|
||||
'3' => '진행중'
|
||||
];
|
||||
return $results[$result] ?? $result;
|
||||
}
|
||||
?>
|
||||
|
||||
137
eaccount/api/check_api_config.php
Normal file
137
eaccount/api/check_api_config.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* 바로빌 API 설정 진단 페이지
|
||||
* 현재 API 키 설정 상태를 확인합니다.
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_account_config.php');
|
||||
|
||||
// 전역 변수 접근
|
||||
global $barobillCertKey, $barobillCorpNum, $barobillUserId, $isTestMode, $barobillAccountSoapUrl;
|
||||
|
||||
$diagnostics = [
|
||||
'cert_key' => [
|
||||
'file_exists' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt'),
|
||||
'file_path' => $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt',
|
||||
'is_set' => !empty($barobillCertKey),
|
||||
'length' => strlen($barobillCertKey),
|
||||
'preview' => !empty($barobillCertKey) ? substr($barobillCertKey, 0, 8) . '...' . substr($barobillCertKey, -4) : 'NOT SET',
|
||||
'raw_content' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt')
|
||||
? file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt')
|
||||
: 'FILE NOT FOUND',
|
||||
'is_placeholder' => !empty($barobillCertKey) ? false : (
|
||||
file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt')
|
||||
? (strpos(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt'), '[여기에') !== false
|
||||
|| strpos(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt'), '바로빌 CERTKEY') !== false
|
||||
|| strpos(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_cert_key.txt'), '================================') !== false)
|
||||
: false
|
||||
)
|
||||
],
|
||||
'corp_num' => [
|
||||
'file_exists' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt'),
|
||||
'file_path' => $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt',
|
||||
'is_set' => !empty($barobillCorpNum),
|
||||
'value' => $barobillCorpNum,
|
||||
'raw_content' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt')
|
||||
? file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_corp_num.txt')
|
||||
: 'FILE NOT FOUND'
|
||||
],
|
||||
'user_id' => [
|
||||
'file_exists' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt'),
|
||||
'file_path' => $_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt',
|
||||
'is_set' => !empty($barobillUserId),
|
||||
'value' => $barobillUserId,
|
||||
'raw_content' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt')
|
||||
? file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_user_id.txt')
|
||||
: 'FILE NOT FOUND'
|
||||
],
|
||||
'test_mode' => [
|
||||
'file_exists' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_test_mode.txt'),
|
||||
'is_active' => $isTestMode,
|
||||
'raw_content' => file_exists($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_test_mode.txt')
|
||||
? file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apikey/barobill_test_mode.txt')
|
||||
: 'FILE NOT FOUND'
|
||||
],
|
||||
'soap_client' => [
|
||||
'url' => $barobillAccountSoapUrl,
|
||||
'initialized' => isset($barobillAccountSoapClient) && $barobillAccountSoapClient !== null
|
||||
],
|
||||
'hardcoded_values' => [
|
||||
'note' => '⚠️ barobill_account_config.php에 하드코딩된 값이 있을 수 있습니다.',
|
||||
'check_file' => 'eaccount/api/barobill_account_config.php (62-68줄)'
|
||||
]
|
||||
];
|
||||
|
||||
// 실제 API 호출 테스트
|
||||
// 테스트 모드일 때는 CERTKEY가 없어도 테스트 가능
|
||||
$testResult = null;
|
||||
$canTest = false;
|
||||
if ($isTestMode) {
|
||||
// 테스트 모드: CERTKEY 불필요, 사업자번호만 확인
|
||||
$canTest = !empty($barobillCorpNum);
|
||||
} else {
|
||||
// 운영 모드: CERTKEY와 사업자번호 모두 필요
|
||||
$canTest = !empty($barobillCertKey) && !empty($barobillCorpNum);
|
||||
}
|
||||
|
||||
if ($canTest) {
|
||||
try {
|
||||
$testResult = callBarobillAccountSOAP('GetBankAccountEx', [
|
||||
'AvailOnly' => 0
|
||||
]);
|
||||
|
||||
$diagnostics['api_test'] = [
|
||||
'success' => $testResult['success'],
|
||||
'error' => $testResult['error'] ?? null,
|
||||
'error_code' => $testResult['error_code'] ?? null,
|
||||
'has_data' => isset($testResult['data']),
|
||||
'debug_available' => isset($testResult['debug'])
|
||||
];
|
||||
|
||||
if (isset($testResult['debug'])) {
|
||||
$diagnostics['api_test']['request_preview'] = $testResult['debug']['request'] ?? null;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$diagnostics['api_test'] = [
|
||||
'success' => false,
|
||||
'error' => 'Exception: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
} else {
|
||||
if ($isTestMode) {
|
||||
$diagnostics['api_test'] = [
|
||||
'skipped' => true,
|
||||
'reason' => '테스트 모드: 사업자번호가 설정되지 않았습니다. (CERTKEY는 불필요)'
|
||||
];
|
||||
} else {
|
||||
$diagnostics['api_test'] = [
|
||||
'skipped' => true,
|
||||
'reason' => '운영 모드: CERTKEY 또는 사업자번호가 설정되지 않았습니다.'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'diagnostics' => $diagnostics,
|
||||
'recommendations' => array_filter([
|
||||
!$isTestMode && !$diagnostics['cert_key']['is_set'] ? 'CERTKEY를 설정하세요: apikey/barobill_cert_key.txt 파일에 바로빌 CERTKEY를 입력하세요.' : null,
|
||||
!$isTestMode && isset($diagnostics['cert_key']['is_placeholder']) && $diagnostics['cert_key']['is_placeholder'] ? '⚠️ CERTKEY 파일에 설명 텍스트만 있습니다. 파일의 모든 설명을 삭제하고 실제 CERTKEY 값만 입력하세요. (예: "2DD6C76C-1234-5678-ABCD-EF1234561826")' : null,
|
||||
!$diagnostics['corp_num']['is_set'] ? '사업자번호를 설정하세요: apikey/barobill_corp_num.txt 파일에 사업자번호를 입력하세요.' : null,
|
||||
!$isTestMode && $diagnostics['cert_key']['file_exists'] && empty(trim($diagnostics['cert_key']['raw_content'])) ? 'CERTKEY 파일이 비어있습니다. 바로빌 사이트에서 CERTKEY를 확인하고 입력하세요.' : null,
|
||||
!$isTestMode && strpos($diagnostics['cert_key']['raw_content'], '[여기에') !== false ? 'CERTKEY 파일에 설명 텍스트가 남아있습니다. 실제 CERTKEY 값만 입력하세요.' : null,
|
||||
isset($diagnostics['api_test']['error_code']) && $diagnostics['api_test']['error_code'] == -24005 ? '사업자번호가 잘못되었습니다. 바로빌 사이트에 로그인하여 등록된 사업자번호를 확인하세요.' : null,
|
||||
isset($diagnostics['api_test']['error_code']) && $diagnostics['api_test']['error_code'] == -25001 ? '등록된 계좌가 없습니다. 바로빌 사이트에서 계좌를 먼저 등록하세요.' : null,
|
||||
$isTestMode ? '현재 테스트 모드입니다. CERTKEY는 필요하지 않습니다.' : null,
|
||||
]),
|
||||
'next_steps' => [
|
||||
'1. 바로빌 사이트(https://www.barobill.co.kr)에 로그인',
|
||||
'2. 마이페이지 > API 설정에서 CERTKEY 확인',
|
||||
'3. apikey/barobill_cert_key.txt 파일에 CERTKEY 입력 (설명 텍스트 제외)',
|
||||
'4. apikey/barobill_corp_num.txt 파일에 사업자번호 입력 (하이픈 제외 가능)',
|
||||
'5. (주)코드브릿지 산하 기업인 경우, barobill_account_config.php의 하드코딩된 값 확인 필요'
|
||||
]
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
?>
|
||||
|
||||
270
eaccount/api/debug_accounts.php
Normal file
270
eaccount/api/debug_accounts.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/**
|
||||
* 계좌 정보 디버깅 API
|
||||
* 로컬 DB와 바로빌 API에서 계좌 정보를 조회하는 과정을 상세히 로깅합니다.
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_account_config.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
|
||||
|
||||
$debug = [
|
||||
'step' => [],
|
||||
'tenant_info' => [],
|
||||
'local_db' => [],
|
||||
'barobill_api' => [],
|
||||
'final_result' => []
|
||||
];
|
||||
|
||||
try {
|
||||
// Step 1: 세션에서 테넌트 ID 확인
|
||||
$selectedTenantId = $_SESSION['eaccount_tenant_id'] ?? null;
|
||||
$debug['step'][] = '1. 세션에서 테넌트 ID 확인';
|
||||
$debug['tenant_info']['session_tenant_id'] = $selectedTenantId;
|
||||
|
||||
// Step 2: DB에서 테넌트 정보 확인
|
||||
$pdo = db_connect();
|
||||
if (!$pdo) {
|
||||
throw new Exception("Database connection failed.");
|
||||
}
|
||||
|
||||
$debug['step'][] = '2. DB 연결 성공';
|
||||
|
||||
// 테넌트 정보 조회
|
||||
if ($selectedTenantId) {
|
||||
$sql = "SELECT id, company_name, corp_num, barobill_user_id
|
||||
FROM {$DB}.barobill_companies
|
||||
WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$selectedTenantId]);
|
||||
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$debug['tenant_info']['db_query'] = $sql;
|
||||
$debug['tenant_info']['db_params'] = [$selectedTenantId];
|
||||
$debug['tenant_info']['tenant_found'] = $tenant ? true : false;
|
||||
$debug['tenant_info']['tenant_data'] = $tenant;
|
||||
|
||||
if ($tenant) {
|
||||
$debug['step'][] = '3. 테넌트 정보 조회 성공: ' . $tenant['company_name'];
|
||||
} else {
|
||||
$debug['step'][] = '3. 테넌트 정보 조회 실패: ID ' . $selectedTenantId . '를 찾을 수 없음';
|
||||
}
|
||||
} else {
|
||||
// 기본값으로 주일기업 찾기
|
||||
$sql = "SELECT id, company_name, corp_num, barobill_user_id
|
||||
FROM {$DB}.barobill_companies
|
||||
WHERE company_name LIKE '%주일기업%'
|
||||
OR company_name LIKE '%주일%'
|
||||
OR barobill_user_id = 'juil5130'
|
||||
ORDER BY id ASC
|
||||
LIMIT 1";
|
||||
$stmt = $pdo->query($sql);
|
||||
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$debug['tenant_info']['default_search_query'] = $sql;
|
||||
$debug['tenant_info']['tenant_found'] = $tenant ? true : false;
|
||||
$debug['tenant_info']['tenant_data'] = $tenant;
|
||||
|
||||
if ($tenant) {
|
||||
$selectedTenantId = $tenant['id'];
|
||||
$debug['step'][] = '3. 기본 테넌트(주일기업) 찾기 성공: ' . $tenant['company_name'];
|
||||
} else {
|
||||
$debug['step'][] = '3. 기본 테넌트(주일기업) 찾기 실패';
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: 로컬 DB에서 계좌 정보 조회
|
||||
if ($selectedTenantId) {
|
||||
$debug['step'][] = '4. 로컬 DB 계좌 정보 조회 시작';
|
||||
|
||||
$accountSql = "SELECT id, company_id, bank_code, account_num, account_pwd
|
||||
FROM {$DB}.company_accounts
|
||||
WHERE company_id = ?
|
||||
ORDER BY id DESC";
|
||||
$accountStmt = $pdo->prepare($accountSql);
|
||||
$accountStmt->execute([$selectedTenantId]);
|
||||
$localAccounts = $accountStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$debug['local_db']['query'] = $accountSql;
|
||||
$debug['local_db']['params'] = [$selectedTenantId];
|
||||
$debug['local_db']['count'] = count($localAccounts);
|
||||
$debug['local_db']['accounts'] = $localAccounts;
|
||||
$debug['step'][] = '4. 로컬 DB 계좌 정보 조회 완료: ' . count($localAccounts) . '개';
|
||||
|
||||
// 모든 회사의 계좌 정보도 확인 (디버깅용)
|
||||
$allAccountsSql = "SELECT ca.*, c.company_name, c.barobill_user_id
|
||||
FROM {$DB}.company_accounts ca
|
||||
LEFT JOIN {$DB}.barobill_companies c ON ca.company_id = c.id
|
||||
ORDER BY ca.id DESC
|
||||
LIMIT 20";
|
||||
$allAccountsStmt = $pdo->query($allAccountsSql);
|
||||
$allAccounts = $allAccountsStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$debug['local_db']['all_companies_accounts'] = $allAccounts;
|
||||
$debug['local_db']['all_companies_accounts_count'] = count($allAccounts);
|
||||
} else {
|
||||
$debug['local_db']['error'] = '테넌트 ID가 없어서 로컬 DB 조회 불가';
|
||||
}
|
||||
|
||||
// Step 4: 바로빌 API 설정 확인
|
||||
global $barobillUserId, $barobillCorpNum, $barobillCertKey, $isTestMode;
|
||||
$debug['barobill_api']['config'] = [
|
||||
'user_id' => $barobillUserId,
|
||||
'corp_num' => $barobillCorpNum,
|
||||
'cert_key_length' => strlen($barobillCertKey),
|
||||
'cert_key_preview' => !empty($barobillCertKey) ? substr($barobillCertKey, 0, 8) . '...' . substr($barobillCertKey, -4) : 'NOT SET',
|
||||
'test_mode' => $isTestMode
|
||||
];
|
||||
$debug['step'][] = '5. 바로빌 API 설정 확인 완료';
|
||||
|
||||
// Step 5: 바로빌 API 호출 시도
|
||||
$debug['step'][] = '6. 바로빌 API 호출 시작';
|
||||
$result = callBarobillAccountSOAP('GetBankAccountEx', [
|
||||
'AvailOnly' => 0
|
||||
]);
|
||||
|
||||
$debug['barobill_api']['success'] = $result['success'];
|
||||
$debug['barobill_api']['error'] = $result['error'] ?? null;
|
||||
$debug['barobill_api']['error_code'] = $result['error_code'] ?? null;
|
||||
|
||||
if ($result['success']) {
|
||||
$data = $result['data'];
|
||||
$accountList = [];
|
||||
|
||||
if (isset($data->BankAccountEx)) {
|
||||
if (is_array($data->BankAccountEx)) {
|
||||
$accountList = $data->BankAccountEx;
|
||||
} else {
|
||||
$accountList = [$data->BankAccountEx];
|
||||
}
|
||||
}
|
||||
|
||||
$barobillAccounts = [];
|
||||
foreach ($accountList as $acc) {
|
||||
if (isset($acc->BankAccountNum) && is_numeric($acc->BankAccountNum) && $acc->BankAccountNum < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$barobillAccounts[] = [
|
||||
'bankAccountNum' => $acc->BankAccountNum ?? '',
|
||||
'bankCode' => $acc->BankCode ?? '',
|
||||
'bankName' => getBankName($acc->BankCode ?? ''),
|
||||
'accountName' => $acc->AccountName ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
$debug['barobill_api']['accounts'] = $barobillAccounts;
|
||||
$debug['barobill_api']['count'] = count($barobillAccounts);
|
||||
$debug['step'][] = '6. 바로빌 API 호출 성공: ' . count($barobillAccounts) . '개 계좌';
|
||||
} else {
|
||||
$debug['barobill_api']['accounts'] = [];
|
||||
$debug['barobill_api']['count'] = 0;
|
||||
$debug['step'][] = '6. 바로빌 API 호출 실패: ' . ($result['error'] ?? '알 수 없는 오류');
|
||||
}
|
||||
|
||||
// Step 6: 최종 결과 통합
|
||||
$allAccounts = [];
|
||||
|
||||
// 로컬 DB 계좌 추가
|
||||
if (isset($localAccounts)) {
|
||||
foreach ($localAccounts as $localAcc) {
|
||||
$allAccounts[] = [
|
||||
'source' => 'local_db',
|
||||
'bankAccountNum' => $localAcc['account_num'],
|
||||
'bankCode' => $localAcc['bank_code'],
|
||||
'bankName' => getBankName($localAcc['bank_code']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 바로빌 API 계좌 추가
|
||||
if (isset($barobillAccounts)) {
|
||||
foreach ($barobillAccounts as $barobillAcc) {
|
||||
$exists = false;
|
||||
foreach ($allAccounts as &$existingAcc) {
|
||||
if ($existingAcc['bankAccountNum'] === $barobillAcc['bankAccountNum'] &&
|
||||
$existingAcc['source'] === 'local_db') {
|
||||
$existingAcc['source'] = 'both';
|
||||
$exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$exists) {
|
||||
$allAccounts[] = array_merge($barobillAcc, ['source' => 'barobill_api']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$debug['final_result']['total_count'] = count($allAccounts);
|
||||
$debug['final_result']['accounts'] = $allAccounts;
|
||||
$debug['step'][] = '7. 최종 통합 완료: ' . count($allAccounts) . '개 계좌';
|
||||
|
||||
// 모든 barobill_companies 목록도 확인
|
||||
$allCompaniesSql = "SELECT id, company_name, corp_num, barobill_user_id, parent_id
|
||||
FROM {$DB}.barobill_companies
|
||||
ORDER BY id ASC";
|
||||
$allCompaniesStmt = $pdo->query($allCompaniesSql);
|
||||
$allCompanies = $allCompaniesStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$debug['tenant_info']['all_companies'] = $allCompanies;
|
||||
$debug['tenant_info']['all_companies_count'] = count($allCompanies);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'debug' => $debug,
|
||||
'summary' => [
|
||||
'tenant_id' => $selectedTenantId,
|
||||
'tenant_name' => $tenant['company_name'] ?? '알 수 없음',
|
||||
'local_accounts_count' => count($localAccounts ?? []),
|
||||
'barobill_accounts_count' => count($barobillAccounts ?? []),
|
||||
'total_accounts_count' => count($allAccounts)
|
||||
]
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$debug['error'] = $e->getMessage();
|
||||
$debug['error_trace'] = $e->getTraceAsString();
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $e->getMessage(),
|
||||
'debug' => $debug
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 은행 코드 -> 은행명 변환
|
||||
*/
|
||||
function getBankName($code) {
|
||||
$banks = [
|
||||
'002' => 'KDB산업은행',
|
||||
'003' => 'IBK기업은행',
|
||||
'004' => 'KB국민은행',
|
||||
'007' => '수협은행',
|
||||
'011' => 'NH농협은행',
|
||||
'012' => '지역농축협',
|
||||
'020' => '우리은행',
|
||||
'023' => 'SC제일은행',
|
||||
'027' => '한국씨티은행',
|
||||
'031' => '대구은행',
|
||||
'032' => '부산은행',
|
||||
'034' => '광주은행',
|
||||
'035' => '제주은행',
|
||||
'037' => '전북은행',
|
||||
'039' => '경남은행',
|
||||
'045' => '새마을금고',
|
||||
'048' => '신협',
|
||||
'050' => '저축은행',
|
||||
'064' => '산림조합',
|
||||
'071' => '우체국',
|
||||
'081' => '하나은행',
|
||||
'088' => '신한은행',
|
||||
'089' => 'K뱅크',
|
||||
'090' => '카카오뱅크',
|
||||
'092' => '토스뱅크'
|
||||
];
|
||||
return $banks[$code] ?? $code;
|
||||
}
|
||||
?>
|
||||
|
||||
94
eaccount/api/get_tenants.php
Normal file
94
eaccount/api/get_tenants.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* 테넌트 목록 조회 API
|
||||
* barobill_companies 테이블에서 테넌트 목록을 가져옵니다.
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
|
||||
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
|
||||
if (!$pdo) {
|
||||
throw new Exception("Database connection failed.");
|
||||
}
|
||||
|
||||
// barobill_companies 테이블에서 모든 회사 가져오기
|
||||
$sql = "SELECT c.*, p.company_name as parent_name, p.barobill_user_id as parent_user_id
|
||||
FROM {$DB}.barobill_companies c
|
||||
LEFT JOIN {$DB}.barobill_companies p ON c.parent_id = p.id
|
||||
ORDER BY c.parent_id ASC, c.id ASC";
|
||||
$stmt = $pdo->query($sql);
|
||||
$companies = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 계좌 정보 확인 (company_accounts 테이블에서)
|
||||
$tenants = [];
|
||||
foreach ($companies as $company) {
|
||||
// 계좌 정보 확인
|
||||
$accountSql = "SELECT COUNT(*) as count FROM {$DB}.company_accounts WHERE company_id = ?";
|
||||
$accountStmt = $pdo->prepare($accountSql);
|
||||
$accountStmt->execute([$company['id']]);
|
||||
$accountResult = $accountStmt->fetch(PDO::FETCH_ASSOC);
|
||||
$hasAccount = ($accountResult['count'] > 0);
|
||||
|
||||
$tenants[] = [
|
||||
'id' => $company['id'],
|
||||
'name' => $company['company_name'],
|
||||
'corp_num' => $company['corp_num'],
|
||||
'user_id' => $company['barobill_user_id'],
|
||||
'parent_id' => $company['parent_id'],
|
||||
'parent_name' => $company['parent_name'] ?? null,
|
||||
'has_account' => $hasAccount,
|
||||
'memo' => $company['memo'] ?? ''
|
||||
];
|
||||
}
|
||||
|
||||
// 현재 세션의 회사 정보
|
||||
$currentCompany = $mycompany ?? '';
|
||||
|
||||
// 현재 선택된 테넌트 (세션에서 가져오거나 기본값)
|
||||
$selectedTenantId = $_SESSION['eaccount_tenant_id'] ?? null;
|
||||
|
||||
// 세션에 저장된 tenant_id가 없으면 '(주)주일기업'을 기본값으로 설정
|
||||
if ($selectedTenantId === null) {
|
||||
// '(주)주일기업' 찾기
|
||||
$defaultTenant = null;
|
||||
foreach ($tenants as $tenant) {
|
||||
if (strpos($tenant['name'], '주일기업') !== false ||
|
||||
strpos($tenant['name'], '주일') !== false ||
|
||||
$tenant['user_id'] === 'juil5130') {
|
||||
$defaultTenant = $tenant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// '(주)주일기업'을 찾지 못하면 첫 번째 테넌트 사용
|
||||
if ($defaultTenant) {
|
||||
$selectedTenantId = $defaultTenant['id'];
|
||||
} elseif (count($tenants) > 0) {
|
||||
$selectedTenantId = $tenants[0]['id'];
|
||||
}
|
||||
|
||||
if ($selectedTenantId) {
|
||||
$_SESSION['eaccount_tenant_id'] = $selectedTenantId;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'tenants' => $tenants,
|
||||
'current_tenant_id' => $selectedTenantId,
|
||||
'current_company' => $currentCompany
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '테넌트 목록 조회 실패: ' . $e->getMessage(),
|
||||
'tenants' => [],
|
||||
'current_tenant_id' => null
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
?>
|
||||
58
eaccount/api/set_tenant.php
Normal file
58
eaccount/api/set_tenant.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* 테넌트 선택 API
|
||||
* 선택된 테넌트를 세션에 저장합니다.
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/session.php');
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mydb.php');
|
||||
|
||||
$tenantId = $_POST['tenant_id'] ?? $_GET['tenant_id'] ?? '';
|
||||
|
||||
if (empty($tenantId)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '테넌트 ID가 필요합니다.'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// DB에서 테넌트 존재 여부 확인
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
if (!$pdo) {
|
||||
throw new Exception("Database connection failed.");
|
||||
}
|
||||
|
||||
$sql = "SELECT id, company_name FROM {$DB}.barobill_companies WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$tenantId]);
|
||||
$tenant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$tenant) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '유효하지 않은 테넌트 ID입니다.'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 세션에 저장
|
||||
$_SESSION['eaccount_tenant_id'] = $tenantId;
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'tenant_id' => $tenantId,
|
||||
'tenant_name' => $tenant['company_name'],
|
||||
'message' => '테넌트가 변경되었습니다.'
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '테넌트 변경 실패: ' . $e->getMessage()
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
?>
|
||||
|
||||
492
eaccount/api/transactions.php
Normal file
492
eaccount/api/transactions.php
Normal file
@@ -0,0 +1,492 @@
|
||||
<?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 (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '서버 오류: ' . $e->getMessage()
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
?>
|
||||
370
eaccount/api/usage.php
Normal file
370
eaccount/api/usage.php
Normal file
@@ -0,0 +1,370 @@
|
||||
<?php
|
||||
/**
|
||||
* 카드 사용내역 조회 API
|
||||
*
|
||||
* 파라미터:
|
||||
* - type: daily(일별), monthly(월별), period(기간별, 기본값)
|
||||
* - cardNum: 카드번호 (빈값이면 전체)
|
||||
* - startDate: 시작일 (YYYYMMDD) - period 타입
|
||||
* - endDate: 종료일 (YYYYMMDD) - period 타입
|
||||
* - baseDate: 기준일 (YYYYMMDD) - daily 타입
|
||||
* - baseMonth: 기준월 (YYYYMM) - monthly 타입
|
||||
* - page: 페이지 번호 (기본 1)
|
||||
* - limit: 페이지당 건수 (기본 50)
|
||||
* - debug: 1이면 디버그 정보 포함
|
||||
*/
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once('barobill_card_config.php');
|
||||
|
||||
// 디버그 모드
|
||||
$debugMode = isset($_GET['debug']) && $_GET['debug'] == '1';
|
||||
|
||||
try {
|
||||
$type = $_GET['type'] ?? 'period';
|
||||
$cardNum = $_GET['cardNum'] ?? '';
|
||||
$page = max(1, intval($_GET['page'] ?? 1));
|
||||
$limit = min(100, max(10, intval($_GET['limit'] ?? 50)));
|
||||
$orderDirection = intval($_GET['order'] ?? 2); // 2: 내림차순 (최신순)
|
||||
|
||||
$result = null;
|
||||
|
||||
// cardNum이 빈 값이면 전체 카드 조회 (각 카드별로 조회 후 병합)
|
||||
if (empty($cardNum)) {
|
||||
// 등록된 카드 목록 조회
|
||||
$cardsResult = getCardList(1); // 사용 가능한 카드만
|
||||
if (!$cardsResult['success'] || empty($cardsResult['data'])) {
|
||||
$result = [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'currentPage' => 1,
|
||||
'countPerPage' => $limit,
|
||||
'maxPageNum' => 1,
|
||||
'maxIndex' => 0,
|
||||
'logs' => []
|
||||
]
|
||||
];
|
||||
} else {
|
||||
// 각 카드별로 조회 후 병합
|
||||
$allLogs = [];
|
||||
foreach ($cardsResult['data'] as $card) {
|
||||
$cardNumToQuery = $card->CardNum ?? '';
|
||||
if (empty($cardNumToQuery)) continue;
|
||||
|
||||
switch ($type) {
|
||||
case 'daily':
|
||||
$baseDate = $_GET['baseDate'] ?? date('Ymd');
|
||||
$tempResult = getDailyCardUsage($cardNumToQuery, $baseDate, 100, 1, $orderDirection);
|
||||
break;
|
||||
case 'monthly':
|
||||
$baseMonth = $_GET['baseMonth'] ?? date('Ym');
|
||||
$tempResult = getMonthlyCardUsage($cardNumToQuery, $baseMonth, 100, 1, $orderDirection);
|
||||
break;
|
||||
case 'period':
|
||||
default:
|
||||
$startDate = $_GET['startDate'] ?? date('Ymd', strtotime('-30 days'));
|
||||
$endDate = $_GET['endDate'] ?? date('Ymd');
|
||||
$tempResult = getPeriodCardUsage($cardNumToQuery, $startDate, $endDate, 100, 1, $orderDirection);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($tempResult['success'] && !empty($tempResult['data']['logs'])) {
|
||||
$allLogs = array_merge($allLogs, $tempResult['data']['logs']);
|
||||
}
|
||||
}
|
||||
|
||||
// UseDT 기준으로 정렬
|
||||
usort($allLogs, function($a, $b) use ($orderDirection) {
|
||||
$aTime = $a->UseDT ?? '';
|
||||
$bTime = $b->UseDT ?? '';
|
||||
return $orderDirection == 1 ? strcmp($aTime, $bTime) : strcmp($bTime, $aTime);
|
||||
});
|
||||
|
||||
// 페이징 처리
|
||||
$totalCount = count($allLogs);
|
||||
$maxPageNum = ceil($totalCount / $limit);
|
||||
$offset = ($page - 1) * $limit;
|
||||
$pagedLogs = array_slice($allLogs, $offset, $limit);
|
||||
|
||||
$result = [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'currentPage' => $page,
|
||||
'countPerPage' => $limit,
|
||||
'maxPageNum' => $maxPageNum,
|
||||
'maxIndex' => $totalCount,
|
||||
'logs' => $pagedLogs
|
||||
]
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 특정 카드 조회
|
||||
switch ($type) {
|
||||
case 'daily':
|
||||
$baseDate = $_GET['baseDate'] ?? date('Ymd');
|
||||
$result = getDailyCardUsage($cardNum, $baseDate, $limit, $page, $orderDirection);
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$baseMonth = $_GET['baseMonth'] ?? date('Ym');
|
||||
$result = getMonthlyCardUsage($cardNum, $baseMonth, $limit, $page, $orderDirection);
|
||||
break;
|
||||
|
||||
case 'period':
|
||||
default:
|
||||
$startDate = $_GET['startDate'] ?? date('Ymd', strtotime('-30 days'));
|
||||
$endDate = $_GET['endDate'] ?? date('Ymd');
|
||||
$result = getPeriodCardUsage($cardNum, $startDate, $endDate, $limit, $page, $orderDirection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($result['success']) {
|
||||
$logs = [];
|
||||
|
||||
// 디버그: raw 로그 데이터 출력
|
||||
if ($debugMode && !empty($result['data']['logs'])) {
|
||||
$firstLog = $result['data']['logs'][0];
|
||||
error_log('CardApprovalLog raw data: ' . print_r($firstLog, true));
|
||||
// 디버그: 모든 필드명 확인
|
||||
if (is_object($firstLog)) {
|
||||
$fields = get_object_vars($firstLog);
|
||||
error_log('CardApprovalLog fields: ' . implode(', ', array_keys($fields)));
|
||||
error_log('ApprovalAmount value: ' . ($firstLog->ApprovalAmount ?? 'NOT SET'));
|
||||
error_log('Amount value: ' . ($firstLog->Amount ?? 'NOT SET'));
|
||||
error_log('TotalAmount value: ' . ($firstLog->TotalAmount ?? 'NOT SET'));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($result['data']['logs'] as $log) {
|
||||
// UseDT 형식: YYYYMMDDHHMMSS
|
||||
$useDT = $log->UseDT ?? '';
|
||||
$approvalDate = '';
|
||||
$approvalTime = '';
|
||||
if (strlen($useDT) >= 8) {
|
||||
$approvalDate = substr($useDT, 0, 4) . '-' . substr($useDT, 4, 2) . '-' . substr($useDT, 6, 2);
|
||||
}
|
||||
if (strlen($useDT) >= 14) {
|
||||
$approvalTime = substr($useDT, 8, 2) . ':' . substr($useDT, 10, 2) . ':' . substr($useDT, 12, 2);
|
||||
} elseif (strlen($useDT) >= 12) {
|
||||
$approvalTime = substr($useDT, 8, 2) . ':' . substr($useDT, 10, 2);
|
||||
}
|
||||
|
||||
$logs[] = [
|
||||
'cardNum' => maskCardNumber($log->CardNum ?? ''),
|
||||
'cardNumFull' => $log->CardNum ?? '',
|
||||
'approvalNum' => $log->ApprovalNum ?? '',
|
||||
'approvalDate' => $approvalDate,
|
||||
'approvalTime' => $approvalTime,
|
||||
'approvalDateTime' => $approvalDate . ' ' . $approvalTime,
|
||||
'merchantName' => $log->UseStoreName ?? '',
|
||||
'merchantBizNum' => $log->UseStoreCorpNum ?? '',
|
||||
// 금액 필드: 여러 가능한 필드명 시도
|
||||
// ApprovalAmount가 실제 승인금액 (화면에 표시할 금액)
|
||||
'amount' => intval($log->ApprovalAmount ?? 0),
|
||||
'amountFormatted' => number_format(intval($log->ApprovalAmount ?? 0)),
|
||||
'vat' => intval($log->Tax ?? 0),
|
||||
'vatFormatted' => number_format(intval($log->Tax ?? 0)),
|
||||
'serviceCharge' => intval($log->ServiceCharge ?? 0),
|
||||
// totalAmount는 화면에서 사용하므로 ApprovalAmount를 사용
|
||||
'totalAmount' => intval($log->ApprovalAmount ?? 0),
|
||||
'totalAmountFormatted' => number_format(intval($log->ApprovalAmount ?? 0)),
|
||||
'approvalType' => $log->ApprovalType ?? '',
|
||||
'approvalTypeName' => getApprovalTypeName($log->ApprovalType ?? ''),
|
||||
'installment' => $log->PaymentPlan ?? '',
|
||||
'installmentName' => getInstallmentName($log->PaymentPlan ?? ''),
|
||||
'currencyCode' => $log->CurrencyCode ?? 'KRW',
|
||||
'memo' => $log->Memo ?? '',
|
||||
'cardCompany' => $log->CardCompany ?? '',
|
||||
'cardCompanyName' => getCardCompanyNameFromLog($log->CardCompany ?? ''),
|
||||
// 추가 필드
|
||||
'useKey' => $log->UseKey ?? '',
|
||||
'storeAddress' => $log->UseStoreAddr ?? '',
|
||||
'storeCeo' => $log->UseStoreCeo ?? '',
|
||||
'storeBizType' => $log->UseStoreBizType ?? '',
|
||||
'storeTel' => $log->UseStoreTel ?? ''
|
||||
];
|
||||
}
|
||||
|
||||
// 통계 계산
|
||||
$totalAmount = array_sum(array_column($logs, 'totalAmount'));
|
||||
$approvalCount = count(array_filter($logs, function($l) { return $l['approvalType'] == '1'; }));
|
||||
$cancelCount = count(array_filter($logs, function($l) { return $l['approvalType'] == '2'; }));
|
||||
|
||||
$response = [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'logs' => $logs,
|
||||
'pagination' => [
|
||||
'currentPage' => $result['data']['currentPage'],
|
||||
'countPerPage' => $result['data']['countPerPage'],
|
||||
'maxPageNum' => $result['data']['maxPageNum'],
|
||||
'totalCount' => $result['data']['maxIndex']
|
||||
],
|
||||
'summary' => [
|
||||
'totalAmount' => $totalAmount,
|
||||
'totalAmountFormatted' => number_format($totalAmount),
|
||||
'count' => count($logs),
|
||||
'approvalCount' => $approvalCount,
|
||||
'cancelCount' => $cancelCount
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// 디버그 정보 추가 (성공한 경우에도 항상 첫 번째 로그의 필드 정보 출력)
|
||||
if (!empty($result['data']['logs'])) {
|
||||
$firstLog = $result['data']['logs'][0];
|
||||
if (is_object($firstLog)) {
|
||||
// 모든 필드를 배열로 변환
|
||||
$allFields = get_object_vars($firstLog);
|
||||
$fieldNames = array_keys($allFields);
|
||||
|
||||
// 금액 관련 필드 찾기 (대소문자 구분 없이)
|
||||
$amountFields = [];
|
||||
foreach ($fieldNames as $fieldName) {
|
||||
if (stripos($fieldName, 'amount') !== false ||
|
||||
stripos($fieldName, 'cost') !== false ||
|
||||
stripos($fieldName, 'price') !== false ||
|
||||
stripos($fieldName, '금액') !== false) {
|
||||
$amountFields[$fieldName] = (string)($firstLog->$fieldName ?? 'NULL');
|
||||
}
|
||||
}
|
||||
|
||||
// 디버그 모드일 때만 상세 정보 출력
|
||||
if ($debugMode) {
|
||||
$response['debug'] = [
|
||||
'userId' => getBarobillUserId(),
|
||||
'params' => $_GET,
|
||||
'firstLogFields' => $fieldNames,
|
||||
'firstLogAllValues' => array_map(function($v) {
|
||||
return is_string($v) ? $v : (is_numeric($v) ? (string)$v : gettype($v));
|
||||
}, $allFields),
|
||||
'amountFields' => $amountFields
|
||||
];
|
||||
} else {
|
||||
// 디버그 모드가 아니어도 금액 필드 정보는 항상 포함 (문제 해결용)
|
||||
$response['debug'] = [
|
||||
'amountFields' => $amountFields,
|
||||
'allFields' => $fieldNames
|
||||
];
|
||||
}
|
||||
}
|
||||
} elseif ($debugMode) {
|
||||
$response['debug'] = [
|
||||
'userId' => getBarobillUserId(),
|
||||
'params' => $_GET,
|
||||
'message' => 'No logs found'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
$response = [
|
||||
'success' => false,
|
||||
'error' => $result['error'],
|
||||
'error_code' => $result['error_code'] ?? null
|
||||
];
|
||||
|
||||
// 디버그 정보 추가
|
||||
if ($debugMode) {
|
||||
$response['debug'] = [
|
||||
'userId' => getBarobillUserId(),
|
||||
'params' => $_GET
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => '서버 오류: ' . $e->getMessage()
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드번호 마스킹
|
||||
*/
|
||||
function maskCardNumber($cardNum) {
|
||||
if (strlen($cardNum) < 8) return $cardNum;
|
||||
return substr($cardNum, 0, 4) . '-****-****-' . substr($cardNum, -4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 날짜 포맷팅
|
||||
*/
|
||||
function formatDate($date) {
|
||||
if (strlen($date) === 8) {
|
||||
return substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 시간 포맷팅
|
||||
*/
|
||||
function formatTime($time) {
|
||||
if (strlen($time) === 6) {
|
||||
return substr($time, 0, 2) . ':' . substr($time, 2, 2) . ':' . substr($time, 4, 2);
|
||||
} elseif (strlen($time) === 4) {
|
||||
return substr($time, 0, 2) . ':' . substr($time, 2, 2);
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 승인 유형 이름
|
||||
*/
|
||||
function getApprovalTypeName($type) {
|
||||
$types = [
|
||||
'1' => '승인',
|
||||
'2' => '취소'
|
||||
];
|
||||
return $types[$type] ?? $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 할부 이름
|
||||
*/
|
||||
function getInstallmentName($installment) {
|
||||
if (empty($installment) || $installment == '0' || $installment == '00') {
|
||||
return '일시불';
|
||||
}
|
||||
return $installment . '개월';
|
||||
}
|
||||
|
||||
/**
|
||||
* 카드사 이름 (로그용)
|
||||
*/
|
||||
function getCardCompanyNameFromLog($code) {
|
||||
$companies = [
|
||||
'01' => '비씨',
|
||||
'02' => 'KB국민',
|
||||
'03' => '하나(외환)',
|
||||
'04' => '삼성',
|
||||
'06' => '신한',
|
||||
'07' => '현대',
|
||||
'08' => '롯데',
|
||||
'11' => 'NH농협',
|
||||
'12' => '수협',
|
||||
'13' => '씨티',
|
||||
'14' => '우리',
|
||||
'15' => '광주',
|
||||
'16' => '전북',
|
||||
'21' => '하나',
|
||||
'22' => '제주',
|
||||
'23' => 'SC제일',
|
||||
'25' => 'KDB산업',
|
||||
'26' => 'IBK기업',
|
||||
'27' => '새마을금고',
|
||||
'28' => '신협',
|
||||
'29' => '저축은행',
|
||||
'30' => '우체국',
|
||||
'31' => '카카오뱅크',
|
||||
'32' => 'K뱅크',
|
||||
'33' => '토스뱅크'
|
||||
];
|
||||
return $companies[$code] ?? $code;
|
||||
}
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user