Files
sam-manage/app/Services/Barobill/BarobillService.php
김보곤 d69f4ef5d3 feat:바로빌 카카오톡(알림톡/친구톡) 서비스 구현
- BarobillService에 KAKAOTALK SOAP 클라이언트 추가
  - 채널/템플릿 관리, 알림톡/친구톡 발송, 전송조회/예약취소 API
- BarobillKakaotalkController (API) 생성: 15개 엔드포인트
- KakaotalkController (페이지) 생성: 5개 페이지
- 라우트 등록 (web.php, api.php)
- Blade 뷰 5개 생성: 대시보드, 채널관리, 템플릿관리, 발송, 전송내역

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 14:11:15 +09:00

1607 lines
51 KiB
PHP

<?php
namespace App\Services\Barobill;
use App\Models\Barobill\BarobillConfig;
use Illuminate\Support\Facades\Log;
use SoapClient;
use SoapFault;
use Throwable;
/**
* 바로빌 API 서비스
*
* 바로빌 SOAP 웹서비스를 Laravel에서 사용하기 위한 서비스 클래스
*
* @see https://dev.barobill.co.kr/
* @see https://ws.baroservice.com/CORPSTATE.asmx (회원관리)
* @see https://ws.baroservice.com/TI.asmx (세금계산서)
* @see https://ws.baroservice.com/BANKACCOUNT.asmx (계좌조회)
* @see https://ws.baroservice.com/CARD.asmx (카드조회)
* @see https://ws.baroservice.com/KAKAOTALK.asmx (카카오톡)
*/
class BarobillService
{
/**
* SOAP 클라이언트 (회원관리용 - CORPSTATE)
*/
protected ?SoapClient $corpStateClient = null;
/**
* SOAP 클라이언트 (세금계산서용 - TI)
*/
protected ?SoapClient $tiClient = null;
/**
* SOAP 클라이언트 (계좌조회용 - BANKACCOUNT)
*/
protected ?SoapClient $bankAccountClient = null;
/**
* SOAP 클라이언트 (카드조회용 - CARD)
*/
protected ?SoapClient $cardClient = null;
/**
* SOAP 클라이언트 (카카오톡용 - KAKAOTALK)
*/
protected ?SoapClient $kakaotalkClient = null;
/**
* CERTKEY (인증키)
*/
protected string $certKey;
/**
* 파트너 사업자번호
*/
protected string $corpNum;
/**
* 테스트 모드 여부
*/
protected bool $isTestMode;
/**
* SOAP URL
*/
protected array $soapUrls;
/**
* 에러 코드 매핑
*/
protected array $errorMessages = [
// 공통 오류
-11101 => '사업자번호가 설정되지 않았거나 유효하지 않습니다.',
-11102 => 'CERTKEY가 유효하지 않습니다.',
-11103 => '인증서가 만료되었거나 유효하지 않습니다.',
-11104 => '해당 사업자가 등록되어 있지 않습니다.',
-11105 => '이미 등록된 사업자입니다.',
-11106 => '아이디가 이미 존재합니다.',
-11201 => '필수 파라미터가 누락되었습니다.',
// 인증서 관련
-26001 => '공동인증서가 등록되어 있지 않습니다.',
// 회원 관련 오류 (RegistCorp)
-32000 => '알 수 없는 오류가 발생했습니다.',
-32001 => '사업자번호가 유효하지 않습니다.',
-32002 => '아이디가 유효하지 않습니다.',
-32003 => '비밀번호가 유효하지 않습니다.',
-32004 => '상호명이 유효하지 않습니다.',
-32005 => '대표자명이 유효하지 않습니다.',
-32006 => '이메일 형식이 유효하지 않습니다.',
-32010 => '이미 등록된 사업자번호입니다.',
-32011 => '이미 등록된 아이디입니다.',
-32012 => '이미 등록된 아이디입니다. 다른 아이디를 사용해주세요.',
-32013 => '비밀번호 형식이 유효하지 않습니다. (영문/숫자/특수문자 조합 8자리 이상)',
-32014 => '연락처 형식이 유효하지 않습니다.',
-32020 => '파트너 사업자번호가 유효하지 않습니다.',
-32021 => '파트너 인증키(CERTKEY)가 유효하지 않습니다.',
// 기타
-99999 => '서버 내부 오류가 발생했습니다.',
];
public function __construct()
{
// 기본값: .env 설정 사용
$this->isTestMode = config('services.barobill.test_mode', true);
$this->initializeConfig();
}
/**
* 서버 모드 전환 (회원사별 설정 적용)
*
* @param bool $isTestMode true: 테스트서버, false: 운영서버
*/
public function switchServerMode(bool $isTestMode): self
{
if ($this->isTestMode !== $isTestMode) {
$this->isTestMode = $isTestMode;
// SOAP 클라이언트 초기화 (새 서버로 재연결)
$this->corpStateClient = null;
$this->tiClient = null;
$this->bankAccountClient = null;
$this->cardClient = null;
$this->kakaotalkClient = null;
// 설정 재로드
$this->initializeConfig();
}
return $this;
}
/**
* 서버 모드 문자열로 전환
*
* @param string $mode 'test' 또는 'production'
*/
public function setServerMode(string $mode): self
{
return $this->switchServerMode($mode === 'test');
}
/**
* 현재 서버 모드 조회
*/
public function getServerMode(): string
{
return $this->isTestMode ? 'test' : 'production';
}
/**
* 설정 초기화 (서버 모드에 따른 설정 로드)
*/
protected function initializeConfig(): void
{
// DB에서 활성화된 설정 가져오기 (우선순위)
$dbConfig = $this->loadConfigFromDatabase();
if ($dbConfig) {
$this->certKey = $dbConfig->cert_key;
$this->corpNum = $dbConfig->corp_num ?? '';
$this->soapUrls = $this->buildSoapUrls($dbConfig->base_url);
} else {
// DB 설정이 없으면 .env에서 가져오기 (fallback)
// 테스트 모드에 따라 적절한 CERT_KEY 선택
$this->certKey = $this->isTestMode
? config('services.barobill.cert_key_test', '')
: config('services.barobill.cert_key_prod', '');
$this->corpNum = config('services.barobill.corp_num', '');
$baseUrl = $this->isTestMode
? 'https://testws.baroservice.com'
: 'https://ws.baroservice.com';
$this->soapUrls = [
'corpstate' => $baseUrl . '/CORPSTATE.asmx?WSDL',
'ti' => $baseUrl . '/TI.asmx?WSDL',
'bankaccount' => $baseUrl . '/BANKACCOUNT.asmx?WSDL',
'card' => $baseUrl . '/CARD.asmx?WSDL',
'kakaotalk' => $baseUrl . '/KAKAOTALK.asmx?WSDL',
];
}
}
/**
* DB에서 활성화된 설정 가져오기
*/
protected function loadConfigFromDatabase(): ?BarobillConfig
{
try {
return BarobillConfig::getActive($this->isTestMode);
} catch (\Exception $e) {
Log::warning('바로빌 DB 설정 로드 실패', ['error' => $e->getMessage()]);
return null;
}
}
/**
* SOAP URL 빌드
*/
protected function buildSoapUrls(string $baseUrl): array
{
// URL에서 후행 슬래시 제거
$baseUrl = rtrim($baseUrl, '/');
return [
'corpstate' => $baseUrl . '/CORPSTATE.asmx?WSDL',
'ti' => $baseUrl . '/TI.asmx?WSDL',
'bankaccount' => $baseUrl . '/BANKACCOUNT.asmx?WSDL',
'card' => $baseUrl . '/CARD.asmx?WSDL',
'kakaotalk' => $baseUrl . '/KAKAOTALK.asmx?WSDL',
];
}
/**
* CORPSTATE SOAP 클라이언트 가져오기 (회원관리용)
*/
protected function getCorpStateClient(): ?SoapClient
{
if ($this->corpStateClient === null) {
try {
$this->corpStateClient = new SoapClient($this->soapUrls['corpstate'], [
'trace' => true,
'encoding' => 'UTF-8',
'exceptions' => true,
'connection_timeout' => 30,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (Throwable $e) {
Log::error('바로빌 CORPSTATE SOAP 클라이언트 생성 실패', [
'error' => $e->getMessage(),
'url' => $this->soapUrls['corpstate'],
]);
return null;
}
}
return $this->corpStateClient;
}
/**
* BANKACCOUNT SOAP 클라이언트 가져오기 (계좌조회용)
*/
protected function getBankAccountClient(): ?SoapClient
{
if ($this->bankAccountClient === null) {
try {
$this->bankAccountClient = new SoapClient($this->soapUrls['bankaccount'], [
'trace' => true,
'encoding' => 'UTF-8',
'exceptions' => true,
'connection_timeout' => 30,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (Throwable $e) {
Log::error('바로빌 BANKACCOUNT SOAP 클라이언트 생성 실패', [
'error' => $e->getMessage(),
'url' => $this->soapUrls['bankaccount'],
]);
return null;
}
}
return $this->bankAccountClient;
}
/**
* CARD SOAP 클라이언트 가져오기 (카드조회용)
*/
protected function getCardClient(): ?SoapClient
{
if ($this->cardClient === null) {
try {
$this->cardClient = new SoapClient($this->soapUrls['card'], [
'trace' => true,
'encoding' => 'UTF-8',
'exceptions' => true,
'connection_timeout' => 30,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (Throwable $e) {
Log::error('바로빌 CARD SOAP 클라이언트 생성 실패', [
'error' => $e->getMessage(),
'url' => $this->soapUrls['card'],
]);
return null;
}
}
return $this->cardClient;
}
/**
* TI SOAP 클라이언트 가져오기 (전자세금계산서용)
*/
protected function getTiClient(): ?SoapClient
{
if ($this->tiClient === null) {
try {
$this->tiClient = new SoapClient($this->soapUrls['ti'], [
'trace' => true,
'encoding' => 'UTF-8',
'exceptions' => true,
'connection_timeout' => 30,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (Throwable $e) {
Log::error('바로빌 TI SOAP 클라이언트 생성 실패', [
'error' => $e->getMessage(),
'url' => $this->soapUrls['ti'],
]);
return null;
}
}
return $this->tiClient;
}
/**
* SOAP 메서드 호출
*/
protected function call(string $service, string $method, array $params = []): array
{
$client = match ($service) {
'corpstate' => $this->getCorpStateClient(),
'ti' => $this->getTiClient(),
'bankaccount' => $this->getBankAccountClient(),
'card' => $this->getCardClient(),
'kakaotalk' => $this->getKakaotalkClient(),
default => null,
};
if (!$client) {
return [
'success' => false,
'error' => "SOAP 클라이언트가 초기화되지 않았습니다. ({$service})",
'error_code' => -1,
];
}
if (empty($this->certKey)) {
return [
'success' => false,
'error' => 'CERTKEY가 설정되지 않았습니다. .env 파일의 BAROBILL_CERT_KEY를 확인하세요.',
'error_code' => -2,
];
}
// CERTKEY 자동 추가
if (!isset($params['CERTKEY'])) {
$params['CERTKEY'] = $this->certKey;
}
try {
Log::info('바로빌 API 호출', [
'service' => $service,
'method' => $method,
'test_mode' => $this->isTestMode,
]);
$result = $client->$method($params);
$resultProperty = $method . 'Result';
if (isset($result->$resultProperty)) {
$resultData = $result->$resultProperty;
// 음수는 에러 코드
if (is_numeric($resultData) && $resultData < 0) {
$errorMessage = $this->errorMessages[$resultData] ?? "바로빌 API 오류 코드: {$resultData}";
Log::error('바로빌 API 오류', [
'method' => $method,
'error_code' => $resultData,
'error_message' => $errorMessage,
]);
return [
'success' => false,
'error' => $errorMessage,
'error_code' => $resultData,
];
}
// 양수(또는 0)는 성공
return [
'success' => true,
'data' => $resultData,
];
}
return [
'success' => true,
'data' => $result,
];
} catch (SoapFault $e) {
Log::error('바로빌 SOAP 오류', [
'method' => $method,
'fault_code' => $e->faultcode ?? null,
'fault_string' => $e->faultstring ?? null,
]);
return [
'success' => false,
'error' => 'SOAP 오류: ' . $e->getMessage(),
'error_code' => $e->getCode(),
];
} catch (Throwable $e) {
Log::error('바로빌 API 호출 오류', [
'method' => $method,
'error' => $e->getMessage(),
]);
return [
'success' => false,
'error' => 'API 호출 오류: ' . $e->getMessage(),
'error_code' => -999,
];
}
}
/**
* 회원사 등록 (RegistCorp)
*
* @see https://ws.baroservice.com/CORPSTATE.asmx?op=RegistCorp
*/
public function registCorp(array $data): array
{
$params = [
'CorpNum' => $this->formatBizNo($data['biz_no']),
'CorpName' => $data['corp_name'],
'CEOName' => $data['ceo_name'],
'BizType' => $data['biz_type'] ?? '',
'BizClass' => $data['biz_class'] ?? '',
'PostNum' => $data['post_num'] ?? '',
'Addr1' => $data['addr'] ?? '',
'Addr2' => '',
'MemberName' => $data['manager_name'] ?? '',
'JuminNum' => '', // 주민번호 (필요시)
'ID' => $data['barobill_id'],
'PWD' => $data['barobill_pwd'],
'Grade' => '2', // 1: 파트너, 2: 회원사
'TEL' => $data['tel'] ?? '',
'HP' => $data['manager_hp'] ?? '',
'Email' => $data['manager_email'] ?? '',
];
return $this->call('corpstate', 'RegistCorp', $params);
}
/**
* 회원사 정보 수정 (UpdateCorpInfo)
*/
public function updateCorpInfo(array $data): array
{
$params = [
'CorpNum' => $this->formatBizNo($data['biz_no']),
'CorpName' => $data['corp_name'],
'CEOName' => $data['ceo_name'],
'BizType' => $data['biz_type'] ?? '',
'BizClass' => $data['biz_class'] ?? '',
'PostNum' => $data['post_num'] ?? '',
'Addr1' => $data['addr'] ?? '',
'Addr2' => '',
'MemberName' => $data['manager_name'] ?? '',
'TEL' => $data['tel'] ?? '',
'HP' => $data['manager_hp'] ?? '',
'Email' => $data['manager_email'] ?? '',
];
return $this->call('corpstate', 'UpdateCorpInfo', $params);
}
/**
* 회원사 상태 조회 (GetCorpState)
*/
public function getCorpState(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('corpstate', 'GetCorpState', $params);
}
/**
* 사업자번호 포맷팅 (하이픈 제거)
*/
protected function formatBizNo(string $bizNo): string
{
return preg_replace('/[^0-9]/', '', $bizNo);
}
// ========================================
// 계좌조회 서비스 (BANKACCOUNT)
// ========================================
/**
* 계좌조회 신청 URL 조회
*
* 회원사가 계좌를 등록할 수 있는 바로빌 페이지 URL을 반환합니다.
* 이 URL로 리다이렉트하면 사용자가 직접 계좌를 등록할 수 있습니다.
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getBankAccountScrapRequestUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('bankaccount', 'GetBankAccountScrapRequestURL', $params);
}
/**
* 계좌번호 관리 URL 조회
*
* 회원사가 등록된 계좌를 관리할 수 있는 바로빌 페이지 URL을 반환합니다.
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getBankAccountManagementUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('bankaccount', 'GetBankAccountManagementURL', $params);
}
/**
* 입출금내역 URL 조회
*
* 회원사가 입출금내역을 조회할 수 있는 바로빌 페이지 URL을 반환합니다.
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getBankAccountLogUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('bankaccount', 'GetBankAccountLogURL', $params);
}
/**
* 인증서 등록 URL 조회
*
* 회원사가 공동인증서를 등록할 수 있는 바로빌 페이지 URL을 반환합니다.
* 세금계산서 발행 시 필요합니다.
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getCertificateRegistUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('bankaccount', 'GetCertificateRegistURL', $params);
}
/**
* 인증서 등록일 조회
*
* @param string $corpNum 회원사 사업자번호
*/
public function getCertificateRegistDate(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('bankaccount', 'GetCertificateRegistDate', $params);
}
/**
* 인증서 만료일 조회
*
* @param string $corpNum 회원사 사업자번호
*/
public function getCertificateExpireDate(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('bankaccount', 'GetCertificateExpireDate', $params);
}
/**
* 인증서 유효성 확인
*
* @param string $corpNum 회원사 사업자번호
*/
public function checkCertificateValid(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('bankaccount', 'CheckCERTIsValid', $params);
}
/**
* 등록계좌 목록 조회
*
* @param string $corpNum 회원사 사업자번호
* @param bool $availOnly 사용 가능한 계좌만 조회 여부
*/
public function getBankAccounts(string $corpNum, bool $availOnly = true): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'AvailOnly' => $availOnly,
];
return $this->call('bankaccount', 'GetBankAccountEx', $params);
}
/**
* 바로빌 URL 조회 (범용)
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
* @param string $togo 이동할 페이지 코드
*/
public function getBarobillUrl(string $corpNum, string $userId, string $userPwd, string $togo = ''): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
'TOGO' => $togo,
];
return $this->call('bankaccount', 'GetBaroBillURL', $params);
}
/**
* 현금충전 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getCashChargeUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('bankaccount', 'GetCashChargeURL', $params);
}
/**
* 회원사 충전잔액 확인
*
* @param string $corpNum 회원사 사업자번호
*/
public function getBalanceCostAmount(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('bankaccount', 'GetBalanceCostAmountEx', $params);
}
/**
* 설정 상태 확인
*/
public function checkConfiguration(): array
{
$dbConfig = $this->loadConfigFromDatabase();
return [
'cert_key_set' => !empty($this->certKey),
'cert_key_test_set' => !empty(config('services.barobill.cert_key_test')),
'cert_key_prod_set' => !empty(config('services.barobill.cert_key_prod')),
'corp_num_set' => !empty($this->corpNum),
'test_mode' => $this->isTestMode,
'mode_label' => $this->isTestMode ? '테스트' : '운영',
'soap_url' => $this->soapUrls['corpstate'],
'config_source' => $dbConfig ? 'database' : 'env',
'db_config_name' => $dbConfig?->name,
];
}
// ========================================
// 카드조회 서비스 (CARD)
// ========================================
/**
* 카드사 코드 목록
*/
public static array $cardCompanyCodes = [
'01' => '비씨카드',
'02' => '국민카드',
'03' => '외환카드',
'04' => '삼성카드',
'05' => '현대카드',
'06' => '롯데카드',
'07' => '신한카드',
'08' => '하나카드',
'09' => '우리카드',
'10' => 'NH농협카드',
'11' => '씨티카드',
'12' => '광주카드',
'13' => '전북카드',
'14' => '수협카드',
'15' => '제주카드',
'16' => '산업카드',
];
/**
* 카드 등록 (RegistCardEx)
*
* @param string $corpNum 회원사 사업자번호
* @param array $cardData 카드 정보
*/
public function registCard(string $corpNum, array $cardData): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'CardCompany' => $cardData['card_company'] ?? '',
'CardType' => $cardData['card_type'] ?? '1', // 1: 법인, 2: 개인
'CardNum' => preg_replace('/[^0-9]/', '', $cardData['card_num'] ?? ''),
'WebId' => $cardData['web_id'] ?? '',
'WebPwd' => $cardData['web_pwd'] ?? '',
'Alias' => $cardData['alias'] ?? '',
'Usage' => $cardData['usage'] ?? '',
'CollectCycle' => $cardData['collect_cycle'] ?? '1', // 1: 1시간, 2: 3시간, 3: 6시간, 4: 12시간, 5: 24시간
];
return $this->call('card', 'RegistCardEx', $params);
}
/**
* 카드 목록 조회 (GetCardEx2)
*
* @param string $corpNum 회원사 사업자번호
* @param bool $availOnly 사용 가능한 카드만 조회
*/
public function getCards(string $corpNum, bool $availOnly = true): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'AvailOnly' => $availOnly ? 1 : 0,
];
return $this->call('card', 'GetCardEx2', $params);
}
/**
* 카드 정보 수정 (UpdateCard)
*
* @param string $corpNum 회원사 사업자번호
* @param array $cardData 카드 정보
*/
public function updateCard(string $corpNum, array $cardData): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'CardNum' => preg_replace('/[^0-9]/', '', $cardData['card_num'] ?? ''),
'WebId' => $cardData['web_id'] ?? '',
'WebPwd' => $cardData['web_pwd'] ?? '',
'Alias' => $cardData['alias'] ?? '',
'Usage' => $cardData['usage'] ?? '',
];
return $this->call('card', 'UpdateCard', $params);
}
/**
* 카드 해지 (StopCard)
*
* @param string $corpNum 회원사 사업자번호
* @param string $cardNum 카드번호
*/
public function stopCard(string $corpNum, string $cardNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'CardNum' => preg_replace('/[^0-9]/', '', $cardNum),
];
return $this->call('card', 'StopCard', $params);
}
/**
* 카드 해지 취소 (CancelStopCard)
*
* @param string $corpNum 회원사 사업자번호
* @param string $cardNum 카드번호
*/
public function cancelStopCard(string $corpNum, string $cardNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'CardNum' => preg_replace('/[^0-9]/', '', $cardNum),
];
return $this->call('card', 'CancelStopCard', $params);
}
/**
* 카드 일별 사용내역 조회 (GetDailyCardLog)
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 ID
* @param string $cardNum 카드번호 (빈 값이면 전체)
* @param string $baseDate 기준일자 (YYYYMMDD)
* @param int $countPerPage 페이지당 건수
* @param int $currentPage 현재 페이지
*/
public function getDailyCardLog(
string $corpNum,
string $id,
string $cardNum,
string $baseDate,
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'CardNum' => preg_replace('/[^0-9]/', '', $cardNum),
'BaseDate' => $baseDate,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D', // D: 내림차순, A: 오름차순
];
return $this->call('card', 'GetDailyCardLog', $params);
}
/**
* 카드 월별 사용내역 조회 (GetMonthlyCardLog)
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 ID
* @param string $cardNum 카드번호 (빈 값이면 전체)
* @param string $baseMonth 기준월 (YYYYMM)
* @param int $countPerPage 페이지당 건수
* @param int $currentPage 현재 페이지
*/
public function getMonthlyCardLog(
string $corpNum,
string $id,
string $cardNum,
string $baseMonth,
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'CardNum' => preg_replace('/[^0-9]/', '', $cardNum),
'BaseMonth' => $baseMonth,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D',
];
return $this->call('card', 'GetMonthlyCardLog', $params);
}
/**
* 카드 기간별 사용내역 조회 (GetPeriodCardLog)
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 ID
* @param string $cardNum 카드번호 (빈 값이면 전체)
* @param string $startDate 시작일 (YYYYMMDD)
* @param string $endDate 종료일 (YYYYMMDD)
* @param int $countPerPage 페이지당 건수
* @param int $currentPage 현재 페이지
*/
public function getPeriodCardLog(
string $corpNum,
string $id,
string $cardNum,
string $startDate,
string $endDate,
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'CardNum' => preg_replace('/[^0-9]/', '', $cardNum),
'StartDate' => $startDate,
'EndDate' => $endDate,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D',
];
return $this->call('card', 'GetPeriodCardLog', $params);
}
/**
* 카드 등록 신청 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getCardScrapRequestUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('card', 'GetCardScrapRequestURL', $params);
}
/**
* 카드 관리 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getCardManagementUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('card', 'GetCardManagementURL', $params);
}
/**
* 카드 사용내역 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getCardLogUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('card', 'GetCardLogURL', $params);
}
// ========================================
// 계좌조회 확장 (BANKACCOUNT)
// ========================================
/**
* 은행 코드 목록
*/
public static array $bankCodes = [
'02' => '산업은행',
'03' => '기업은행',
'04' => '국민은행',
'05' => '외환은행',
'06' => '국민은행(구주택)',
'07' => '수협은행',
'08' => '수출입은행',
'11' => 'NH농협은행',
'12' => '지역농축협',
'20' => '우리은행',
'21' => '신한은행(구조흥)',
'22' => '상업은행(구)',
'23' => '제일은행(SC)',
'25' => '하나은행(구 서울)',
'26' => '신한은행',
'27' => '한국씨티은행',
'31' => '대구은행',
'32' => '부산은행',
'34' => '광주은행',
'35' => '제주은행',
'37' => '전북은행',
'38' => '강원은행(구)',
'39' => '경남은행',
'41' => '비씨카드',
'45' => '새마을금고연합',
'48' => '신협',
'50' => '상호저축은행',
'53' => '한국씨티은행(구)',
'54' => 'HSBC은행',
'55' => '도이치은행',
'56' => 'ABN-AMRO',
'57' => 'JP모간',
'59' => '미쓰비시도쿄은행',
'60' => 'BOA',
'64' => '산림조합중앙회',
'71' => '우체국',
'81' => 'KEB하나은행',
'88' => '신한은행(통합)',
'89' => '케이뱅크',
'90' => '카카오뱅크',
'92' => '토스뱅크',
];
/**
* 계좌 일별 입출금내역 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 ID
* @param string $bankAccountNum 계좌번호 (빈 값이면 전체)
* @param string $baseDate 기준일자 (YYYYMMDD)
* @param string $transDirection I: 입금, O: 출금, '' 전체
* @param int $countPerPage 페이지당 건수
* @param int $currentPage 현재 페이지
*/
public function getDailyBankAccountTransLog(
string $corpNum,
string $id,
string $bankAccountNum,
string $baseDate,
string $transDirection = '',
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'BankAccountNum' => $bankAccountNum,
'BaseDate' => $baseDate,
'TransDirection' => $transDirection,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D',
];
return $this->call('bankaccount', 'GetDailyBankAccountTransLog', $params);
}
/**
* 계좌 월별 입출금내역 조회
*/
public function getMonthlyBankAccountTransLog(
string $corpNum,
string $id,
string $bankAccountNum,
string $baseMonth,
string $transDirection = '',
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'BankAccountNum' => $bankAccountNum,
'BaseMonth' => $baseMonth,
'TransDirection' => $transDirection,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D',
];
return $this->call('bankaccount', 'GetMonthlyBankAccountTransLog', $params);
}
/**
* 계좌 기간별 입출금내역 조회
*/
public function getPeriodBankAccountTransLog(
string $corpNum,
string $id,
string $bankAccountNum,
string $startDate,
string $endDate,
string $transDirection = '',
int $countPerPage = 20,
int $currentPage = 1
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
'BankAccountNum' => $bankAccountNum,
'StartDate' => $startDate,
'EndDate' => $endDate,
'TransDirection' => $transDirection,
'CountPerPage' => $countPerPage,
'CurrentPage' => $currentPage,
'OrderDirection' => 'D',
];
return $this->call('bankaccount', 'GetPeriodBankAccountTransLog', $params);
}
// ========================================
// 전자세금계산서 서비스 (TI)
// ========================================
/**
* 세금계산서 발행 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getTaxInvoiceIssueUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('ti', 'GetTaxInvoiceIssueURL', $params);
}
/**
* 세금계산서 목록 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getTaxInvoiceListUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('ti', 'GetTaxInvoiceListURL', $params);
}
/**
* 매입/매출 관리 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $userId 회원사 사용자 ID
* @param string $userPwd 회원사 사용자 비밀번호
*/
public function getHomeTaxUrl(string $corpNum, string $userId, string $userPwd): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $userId,
'PWD' => $userPwd,
];
return $this->call('ti', 'GetHomeTaxURL', $params);
}
// ========================================
// 카카오톡 서비스 (KAKAOTALK)
// ========================================
/**
* KAKAOTALK SOAP 클라이언트 가져오기
*/
protected function getKakaotalkClient(): ?SoapClient
{
if ($this->kakaotalkClient === null) {
try {
$this->kakaotalkClient = new SoapClient($this->soapUrls['kakaotalk'], [
'trace' => true,
'encoding' => 'UTF-8',
'exceptions' => true,
'connection_timeout' => 30,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (Throwable $e) {
Log::error('바로빌 KAKAOTALK SOAP 클라이언트 생성 실패', [
'error' => $e->getMessage(),
'url' => $this->soapUrls['kakaotalk'],
]);
return null;
}
}
return $this->kakaotalkClient;
}
// --- 채널 관리 ---
/**
* 카카오톡 채널 목록 조회
*
* @param string $corpNum 회원사 사업자번호
*/
public function getKakaotalkChannels(string $corpNum): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
];
return $this->call('kakaotalk', 'GetKakaotalkChannels', $params);
}
/**
* 카카오톡 채널 관리 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 사용자 ID
*/
public function getKakaotalkChannelManagementUrl(string $corpNum, string $id): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
];
return $this->call('kakaotalk', 'GetKakaotalkChannelManagementURL', $params);
}
// --- 템플릿 관리 ---
/**
* 카카오톡 템플릿 목록 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $channelId 카카오톡 채널 ID
*/
public function getKakaotalkTemplates(string $corpNum, string $channelId): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ChannelId' => $channelId,
];
return $this->call('kakaotalk', 'GetKakaotalkTemplates', $params);
}
/**
* 카카오톡 템플릿 관리 URL 조회
*
* @param string $corpNum 회원사 사업자번호
* @param string $id 회원사 사용자 ID
*/
public function getKakaotalkTemplateManagementUrl(string $corpNum, string $id): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'ID' => $id,
];
return $this->call('kakaotalk', 'GetKakaotalkTemplateManagementURL', $params);
}
// --- 알림톡 발송 ---
/**
* 알림톡 단건 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키 (채널 ID)
* @param string $templateName 템플릿 이름
* @param string $receiverName 수신자 이름
* @param string $receiverNum 수신자 전화번호
* @param string $title 알림톡 제목
* @param string $message 알림톡 본문
* @param string $smsMessage SMS 대체발송 메시지 (빈 값이면 대체발송 안 함)
* @param string $smsSubject SMS 대체발송 제목
* @param string $reserveDT 예약일시 (YYYYMMDDHHmmss, 빈 값이면 즉시발송)
*/
public function sendATKakaotalk(
string $corpNum,
string $senderId,
string $templateName,
string $receiverName,
string $receiverNum,
string $title,
string $message,
string $smsMessage = '',
string $smsSubject = '',
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'TemplateName' => $templateName,
'ReceiverName' => $receiverName,
'ReceiverNum' => $receiverNum,
'Title' => $title,
'Message' => $message,
'SmsMessage' => $smsMessage,
'SmsSubject' => $smsSubject,
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendATKakaotalk', $params);
}
/**
* 알림톡 단건 발송 (버튼 포함)
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $templateName 템플릿 이름
* @param string $receiverName 수신자 이름
* @param string $receiverNum 수신자 전화번호
* @param string $title 알림톡 제목
* @param string $message 알림톡 본문
* @param array $buttons 버튼 배열 [{Name, ButtonType, Url1, Url2}]
* @param string $smsMessage SMS 대체발송 메시지
* @param string $smsSubject SMS 대체발송 제목
* @param string $reserveDT 예약일시
*/
public function sendATKakaotalkEx(
string $corpNum,
string $senderId,
string $templateName,
string $receiverName,
string $receiverNum,
string $title,
string $message,
array $buttons = [],
string $smsMessage = '',
string $smsSubject = '',
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'TemplateName' => $templateName,
'ReceiverName' => $receiverName,
'ReceiverNum' => $receiverNum,
'Title' => $title,
'Message' => $message,
'Buttons' => $buttons,
'SmsMessage' => $smsMessage,
'SmsSubject' => $smsSubject,
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendATKakaotalkEx', $params);
}
/**
* 알림톡 대량 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $templateName 템플릿 이름
* @param array $messages 메시지 배열 [{ReceiverName, ReceiverNum, Title, Message, SmsMessage, SmsSubject}]
* @param string $reserveDT 예약일시
*/
public function sendATKakaotalks(
string $corpNum,
string $senderId,
string $templateName,
array $messages,
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'TemplateName' => $templateName,
'Messages' => $messages,
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendATKakaotalks', $params);
}
// --- 친구톡 발송 ---
/**
* 친구톡 텍스트 단건 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $channelId 채널 ID
* @param string $receiverName 수신자 이름
* @param string $receiverNum 수신자 전화번호
* @param string $message 메시지 내용
* @param array $buttons 버튼 배열
* @param string $smsMessage SMS 대체발송 메시지
* @param string $smsSubject SMS 대체발송 제목
* @param bool $adYn 광고 여부
* @param string $reserveDT 예약일시
*/
public function sendFTKakaotalk(
string $corpNum,
string $senderId,
string $channelId,
string $receiverName,
string $receiverNum,
string $message,
array $buttons = [],
string $smsMessage = '',
string $smsSubject = '',
bool $adYn = false,
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'ChannelId' => $channelId,
'ReceiverName' => $receiverName,
'ReceiverNum' => $receiverNum,
'Message' => $message,
'Buttons' => $buttons,
'SmsMessage' => $smsMessage,
'SmsSubject' => $smsSubject,
'AdYn' => $adYn ? 'Y' : 'N',
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendFTKakaotalk', $params);
}
/**
* 친구톡 대량 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $channelId 채널 ID
* @param array $messages 메시지 배열
* @param bool $adYn 광고 여부
* @param string $reserveDT 예약일시
*/
public function sendFTKakaotalks(
string $corpNum,
string $senderId,
string $channelId,
array $messages,
bool $adYn = false,
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'ChannelId' => $channelId,
'Messages' => $messages,
'AdYn' => $adYn ? 'Y' : 'N',
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendFTKakaotalks', $params);
}
/**
* 친구톡 이미지 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $channelId 채널 ID
* @param string $receiverName 수신자 이름
* @param string $receiverNum 수신자 전화번호
* @param string $message 메시지 내용
* @param string $imageUrl 이미지 URL
* @param array $buttons 버튼 배열
* @param string $smsMessage SMS 대체발송 메시지
* @param string $smsSubject SMS 대체발송 제목
* @param bool $adYn 광고 여부
* @param string $reserveDT 예약일시
*/
public function sendFIKakaotalk(
string $corpNum,
string $senderId,
string $channelId,
string $receiverName,
string $receiverNum,
string $message,
string $imageUrl,
array $buttons = [],
string $smsMessage = '',
string $smsSubject = '',
bool $adYn = false,
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'ChannelId' => $channelId,
'ReceiverName' => $receiverName,
'ReceiverNum' => $receiverNum,
'Message' => $message,
'ImageURL' => $imageUrl,
'Buttons' => $buttons,
'SmsMessage' => $smsMessage,
'SmsSubject' => $smsSubject,
'AdYn' => $adYn ? 'Y' : 'N',
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendFIKakaotalk', $params);
}
/**
* 친구톡 와이드 이미지 발송
*
* @param string $corpNum 회원사 사업자번호
* @param string $senderId 발신프로필 키
* @param string $channelId 채널 ID
* @param string $receiverName 수신자 이름
* @param string $receiverNum 수신자 전화번호
* @param string $message 메시지 내용
* @param string $imageUrl 와이드 이미지 URL
* @param array $buttons 버튼 배열
* @param string $smsMessage SMS 대체발송 메시지
* @param string $smsSubject SMS 대체발송 제목
* @param bool $adYn 광고 여부
* @param string $reserveDT 예약일시
*/
public function sendFWKakaotalk(
string $corpNum,
string $senderId,
string $channelId,
string $receiverName,
string $receiverNum,
string $message,
string $imageUrl,
array $buttons = [],
string $smsMessage = '',
string $smsSubject = '',
bool $adYn = false,
string $reserveDT = ''
): array {
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SenderID' => $senderId,
'ChannelId' => $channelId,
'ReceiverName' => $receiverName,
'ReceiverNum' => $receiverNum,
'Message' => $message,
'ImageURL' => $imageUrl,
'Buttons' => $buttons,
'SmsMessage' => $smsMessage,
'SmsSubject' => $smsSubject,
'AdYn' => $adYn ? 'Y' : 'N',
'ReserveDT' => $reserveDT,
];
return $this->call('kakaotalk', 'SendFWKakaotalk', $params);
}
// --- 전송 조회/관리 ---
/**
* 전송 결과 조회 (단건)
*
* @param string $corpNum 회원사 사업자번호
* @param string $sendKey 전송키
*/
public function getSendKakaotalk(string $corpNum, string $sendKey): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SendKey' => $sendKey,
];
return $this->call('kakaotalk', 'GetSendKakaotalk', $params);
}
/**
* 전송 결과 조회 (다건)
*
* @param string $corpNum 회원사 사업자번호
* @param array $sendKeyList 전송키 배열
*/
public function getSendKakaotalks(string $corpNum, array $sendKeyList): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SendKeyList' => $sendKeyList,
];
return $this->call('kakaotalk', 'GetSendKakaotalks', $params);
}
/**
* 예약 전송 취소
*
* @param string $corpNum 회원사 사업자번호
* @param string $sendKey 전송키
*/
public function cancelReservedKakaotalk(string $corpNum, string $sendKey): array
{
$params = [
'CorpNum' => $this->formatBizNo($corpNum),
'SendKey' => $sendKey,
];
return $this->call('kakaotalk', 'CancelReservedKakaotalk', $params);
}
}