feat: [barobill] SOAP 동기화 서비스 신규 구축
- BarobillSoapService: PHP SoapClient 기반 SOAP 래퍼 (회원/계좌/카드/인증서) - BarobillBankSyncService: 은행 거래내역 SOAP 조회 → DB 캐시 동기화 - BarobillCardSyncService: 카드 거래내역 SOAP 조회 → DB 캐시 동기화 - HometaxSyncService: 홈택스 세금계산서 upsert 동기화 - BarobillSyncController: 동기화/회원/인증서/잔액 API 11개 엔드포인트 - SyncBarobillDataJob: 매일 06:00/06:30 자동 동기화 스케줄러 - BarobillController.status() 보강: 실제 계좌/카드 수 표시
This commit is contained in:
306
app/Http/Controllers/Api/V1/BarobillSyncController.php
Normal file
306
app/Http/Controllers/Api/V1/BarobillSyncController.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Helpers\ApiResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\BarobillMember;
|
||||
use App\Services\Barobill\BarobillBankSyncService;
|
||||
use App\Services\Barobill\BarobillCardSyncService;
|
||||
use App\Services\Barobill\BarobillSoapService;
|
||||
use App\Services\Barobill\HometaxSyncService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BarobillSyncController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private BarobillSoapService $soapService,
|
||||
private BarobillBankSyncService $bankSyncService,
|
||||
private BarobillCardSyncService $cardSyncService,
|
||||
private HometaxSyncService $hometaxSyncService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 수동 은행 동기화
|
||||
*/
|
||||
public function syncBank(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'start_date' => 'nullable|date_format:Ymd',
|
||||
'end_date' => 'nullable|date_format:Ymd',
|
||||
]);
|
||||
|
||||
return ApiResponse::handle(function () use ($data) {
|
||||
$tenantId = app('tenant_id');
|
||||
$startDate = $data['start_date'] ?? Carbon::now()->subMonth()->format('Ymd');
|
||||
$endDate = $data['end_date'] ?? Carbon::now()->format('Ymd');
|
||||
|
||||
return $this->bankSyncService->syncIfNeeded($tenantId, $startDate, $endDate);
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 수동 카드 동기화
|
||||
*/
|
||||
public function syncCard(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'start_date' => 'nullable|date_format:Ymd',
|
||||
'end_date' => 'nullable|date_format:Ymd',
|
||||
]);
|
||||
|
||||
return ApiResponse::handle(function () use ($data) {
|
||||
$tenantId = app('tenant_id');
|
||||
$startDate = $data['start_date'] ?? Carbon::now()->subMonth()->format('Ymd');
|
||||
$endDate = $data['end_date'] ?? Carbon::now()->format('Ymd');
|
||||
|
||||
return $this->cardSyncService->syncCardTransactions($tenantId, $startDate, $endDate);
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 수동 홈택스 동기화
|
||||
*/
|
||||
public function syncHometax(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'invoices' => 'required|array',
|
||||
'invoices.*.ntsConfirmNum' => 'required|string',
|
||||
'invoice_type' => 'required|in:sales,purchase',
|
||||
]);
|
||||
|
||||
return ApiResponse::handle(function () use ($data) {
|
||||
$tenantId = app('tenant_id');
|
||||
|
||||
return $this->hometaxSyncService->syncInvoices(
|
||||
$data['invoices'],
|
||||
$tenantId,
|
||||
$data['invoice_type']
|
||||
);
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 등록계좌 목록 (SOAP 실시간)
|
||||
*/
|
||||
public function accounts()
|
||||
{
|
||||
return ApiResponse::handle(function () {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['accounts' => [], 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
|
||||
return [
|
||||
'accounts' => $this->bankSyncService->getRegisteredAccounts($member),
|
||||
];
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 등록카드 목록 (SOAP 실시간)
|
||||
*/
|
||||
public function cards()
|
||||
{
|
||||
return ApiResponse::handle(function () {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['cards' => [], 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
|
||||
return [
|
||||
'cards' => $this->cardSyncService->getRegisteredCards($member),
|
||||
];
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증서 상태 조회 (만료일, 유효성)
|
||||
*/
|
||||
public function certificate()
|
||||
{
|
||||
return ApiResponse::handle(function () {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['certificate' => null, 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
$corpNum = $member->biz_no;
|
||||
|
||||
$valid = $this->soapService->checkCertificateValid($corpNum);
|
||||
$expireDate = $this->soapService->getCertificateExpireDate($corpNum);
|
||||
$registDate = $this->soapService->getCertificateRegistDate($corpNum);
|
||||
|
||||
return [
|
||||
'certificate' => [
|
||||
'is_valid' => $valid['success'] && ($valid['data'] ?? 0) >= 0,
|
||||
'expire_date' => $expireDate['success'] ? ($expireDate['data'] ?? null) : null,
|
||||
'regist_date' => $registDate['success'] ? ($registDate['data'] ?? null) : null,
|
||||
],
|
||||
];
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 충전잔액 조회
|
||||
*/
|
||||
public function balance()
|
||||
{
|
||||
return ApiResponse::handle(function () {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['balance' => null, 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
$result = $this->soapService->getBalanceCostAmount($member->biz_no);
|
||||
|
||||
return [
|
||||
'balance' => $result['success'] ? ($result['data'] ?? 0) : null,
|
||||
'success' => $result['success'],
|
||||
'error' => $result['error'] ?? null,
|
||||
];
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 회원 등록 (SOAP RegistCorp)
|
||||
*/
|
||||
public function registerMember(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'biz_no' => 'required|string|size:10',
|
||||
'corp_name' => 'required|string',
|
||||
'ceo_name' => 'required|string',
|
||||
'biz_type' => 'nullable|string',
|
||||
'biz_class' => 'nullable|string',
|
||||
'addr' => 'nullable|string',
|
||||
'barobill_id' => 'required|string',
|
||||
'barobill_pwd' => 'required|string',
|
||||
'manager_name' => 'nullable|string',
|
||||
'manager_hp' => 'nullable|string',
|
||||
'manager_email' => 'nullable|email',
|
||||
]);
|
||||
|
||||
return ApiResponse::handle(function () use ($data) {
|
||||
$tenantId = app('tenant_id');
|
||||
$this->soapService->initForMember(
|
||||
BarobillMember::withoutGlobalScopes()->where('tenant_id', $tenantId)->first()
|
||||
?? new BarobillMember(['server_mode' => 'test'])
|
||||
);
|
||||
|
||||
$result = $this->soapService->registCorp($data);
|
||||
|
||||
if ($result['success']) {
|
||||
BarobillMember::withoutGlobalScopes()->updateOrCreate(
|
||||
['tenant_id' => $tenantId],
|
||||
[
|
||||
'biz_no' => $data['biz_no'],
|
||||
'corp_name' => $data['corp_name'],
|
||||
'ceo_name' => $data['ceo_name'],
|
||||
'biz_type' => $data['biz_type'] ?? null,
|
||||
'biz_class' => $data['biz_class'] ?? null,
|
||||
'addr' => $data['addr'] ?? null,
|
||||
'barobill_id' => $data['barobill_id'],
|
||||
'barobill_pwd' => $data['barobill_pwd'],
|
||||
'manager_name' => $data['manager_name'] ?? null,
|
||||
'manager_hp' => $data['manager_hp'] ?? null,
|
||||
'manager_email' => $data['manager_email'] ?? null,
|
||||
'status' => 'active',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}, __('message.created'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 회원 수정 (SOAP UpdateCorpInfo)
|
||||
*/
|
||||
public function updateMember(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'corp_name' => 'required|string',
|
||||
'ceo_name' => 'required|string',
|
||||
'biz_type' => 'nullable|string',
|
||||
'biz_class' => 'nullable|string',
|
||||
'addr' => 'nullable|string',
|
||||
'manager_name' => 'nullable|string',
|
||||
'manager_hp' => 'nullable|string',
|
||||
'manager_email' => 'nullable|email',
|
||||
]);
|
||||
|
||||
return ApiResponse::handle(function () use ($data) {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['error' => 'NO_MEMBER', 'code' => 404, 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
|
||||
$data['biz_no'] = $member->biz_no;
|
||||
$result = $this->soapService->updateCorpInfo($data);
|
||||
|
||||
if ($result['success']) {
|
||||
$member->update([
|
||||
'corp_name' => $data['corp_name'],
|
||||
'ceo_name' => $data['ceo_name'],
|
||||
'biz_type' => $data['biz_type'] ?? $member->biz_type,
|
||||
'biz_class' => $data['biz_class'] ?? $member->biz_class,
|
||||
'addr' => $data['addr'] ?? $member->addr,
|
||||
'manager_name' => $data['manager_name'] ?? $member->manager_name,
|
||||
'manager_hp' => $data['manager_hp'] ?? $member->manager_hp,
|
||||
'manager_email' => $data['manager_email'] ?? $member->manager_email,
|
||||
]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}, __('message.updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 바로빌 회원 상태 (SOAP GetCorpState)
|
||||
*/
|
||||
public function memberStatus()
|
||||
{
|
||||
return ApiResponse::handle(function () {
|
||||
$member = $this->getMember();
|
||||
if (! $member) {
|
||||
return ['status' => null, 'message' => '바로빌 회원 정보 없음'];
|
||||
}
|
||||
|
||||
$this->soapService->initForMember($member);
|
||||
$result = $this->soapService->getCorpState($member->biz_no);
|
||||
|
||||
return [
|
||||
'member' => [
|
||||
'biz_no' => $member->formatted_biz_no,
|
||||
'corp_name' => $member->corp_name,
|
||||
'status' => $member->status,
|
||||
'server_mode' => $member->server_mode,
|
||||
],
|
||||
'barobill_state' => $result['success'] ? $result['data'] : null,
|
||||
'error' => $result['error'] ?? null,
|
||||
];
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 테넌트의 바로빌 회원 조회
|
||||
*/
|
||||
private function getMember(): ?BarobillMember
|
||||
{
|
||||
$tenantId = app('tenant_id');
|
||||
|
||||
return BarobillMember::withoutGlobalScopes()
|
||||
->where('tenant_id', $tenantId)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user