Files
sam-sales/ecard/api/usage.php
aweso 50308dd340 피플라이프 기업분석 추가
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 09:33:23 +09:00

403 lines
16 KiB
PHP

<?php
/**
* 카드 사용내역 조회 API
*
* ============================================================================
* 데이터 흐름
* ============================================================================
*
* [호출 경로]
* 화면(ecard/index.php) → 이 API(usage.php) → barobill_card_config.php::getPeriodCardUsage()
* → 바로빌 SOAP API(GetPeriodCardApprovalLog) → 바로빌 서버
*
* [사용내역 정보 출처]
* - 바로빌이 카드사에서 자동으로 수집한 사용내역
* - 카드 등록 시 설정한 수집주기(CollectCycle)에 따라 1일 1회~3회 자동 수집
* - 수집된 데이터는 바로빌 서버에 저장됨
*
* [수집 과정]
* 1. 카드 등록 시 Web ID/비밀번호로 카드사 홈페이지에 로그인
* 2. 바로빌이 설정된 수집주기에 따라 카드사에서 사용내역 자동 수집
* 3. 수집된 데이터를 바로빌 서버에 저장
* 4. 이 API를 통해 저장된 사용내역 조회
*
* 파라미터:
* - type: daily(일별), monthly(월별), period(기간별, 기본값)
* - cardNum: 카드번호 (빈값이면 전체)
* - startDate: 시작일 (YYYYMMDD) - period 타입
* - endDate: 종료일 (YYYYMMDD) - period 타입
* - baseDate: 기준일 (YYYYMMDD) - daily 타입
* - baseMonth: 기준월 (YYYYMM) - monthly 타입
* - page: 페이지 번호 (기본 1)
* - limit: 페이지당 건수 (기본 50)
* - debug: 1이면 디버그 정보 포함
*
* [반환 데이터]
* - approvalDateTime: 승인일시
* - cardNum: 카드번호 (마스킹)
* - cardNumFull: 카드번호 (전체)
* - merchantName: 가맹점명
* - merchantBizNum: 가맹점 사업자번호
* - amount: 승인금액
* - vat: 부가세
* - serviceCharge: 봉사료
* - approvalType: 승인유형 (1=승인, 2=취소)
* - installment: 할부개월 (0=일시불)
* - approvalNum: 승인번호
*/
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;
}
?>