146 lines
6.4 KiB
PHP
146 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Customer\Wallet;
|
|
|
|
use App\Entities\CommonEntity;
|
|
use App\Entities\Customer\ClientEntity;
|
|
use App\Entities\PaymentEntity;
|
|
use App\Models\CommonModel;
|
|
use App\Services\Customer\CustomerService;
|
|
use RuntimeException;
|
|
|
|
abstract class WalletService extends CustomerService
|
|
{
|
|
protected $title = "";
|
|
protected $balanceField = "";
|
|
protected function __construct(CommonModel $model)
|
|
{
|
|
parent::__construct($model);
|
|
$this->addClassPaths('Wallet');
|
|
}
|
|
abstract protected function getClientBalance(ClientEntity $clientEntity): int;
|
|
//기본기능
|
|
protected function create_process(array $formDatas): CommonEntity
|
|
{
|
|
// 고객 정보
|
|
if (empty($formDatas['clientinfo_uid'])) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 고객정보(clientinfo_uid)가 전송되지 않았습니다.");
|
|
}
|
|
|
|
$clientEntity = service('customer_clientservice')->getEntity($formDatas['clientinfo_uid']);
|
|
if (!$clientEntity instanceof ClientEntity) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$formDatas['clientinfo_uid']}에 해당하는 고객정보를 찾을수 없습니다.");
|
|
}
|
|
|
|
if (empty($formDatas['status'])) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: status가 전송되지 않았습니다.");
|
|
}
|
|
|
|
if (in_array($formDatas['status'], [STATUS['DEPOSIT'], STATUS['WITHDRAWAL']], true)) {
|
|
if (!array_key_exists('amount', $formDatas)) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: amount가 전송되지 않았습니다.");
|
|
}
|
|
$formDatas['amount'] = (int) $formDatas['amount'];
|
|
if ($formDatas['amount'] <= 0) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: amount는 1 이상이어야 합니다.");
|
|
}
|
|
}
|
|
switch ($formDatas['status']) {
|
|
case STATUS['DEPOSIT']:
|
|
$entity = $this->deposit_process($clientEntity, $formDatas);
|
|
break;
|
|
case STATUS['WITHDRAWAL']:
|
|
$entity = $this->withdrawal_process($clientEntity, $formDatas);
|
|
break;
|
|
default:
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 지원하지 않는 status={$formDatas['status']}");
|
|
}
|
|
return $entity;
|
|
}
|
|
final protected function modify_process($entity, array $formDatas): CommonEntity
|
|
{
|
|
throw new RuntimeException("{$this->title}는 수정이 불가합니다.");
|
|
}
|
|
|
|
private function getFreshClientEntity(ClientEntity $clientEntity): ClientEntity
|
|
{
|
|
$fresh = service('customer_clientservice')->getEntity($clientEntity->getPK());
|
|
|
|
if (!$fresh instanceof ClientEntity) {
|
|
throw new RuntimeException(
|
|
static::class . '->' . __FUNCTION__ . "에서 오류발생: 고객 재조회 실패"
|
|
);
|
|
}
|
|
|
|
return $fresh;
|
|
}
|
|
|
|
//입금,쿠폰 충전 처리
|
|
protected function deposit_process(ClientEntity $clientEntity, array $formDatas): CommonEntity
|
|
{
|
|
$amount = (int) ($formDatas['amount'] ?? 0);
|
|
if ($amount <= 0) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$this->title}는 1 이상이어야 합니다.");
|
|
}
|
|
|
|
// 1) DB 원자 증가
|
|
service('customer_clientservice')->increaseBalance($clientEntity->getPK(), $this->balanceField, $amount);
|
|
|
|
// 2) ✅ 최신 잔액 재조회 (stale 방지)
|
|
// balanceField를 기반으로 현재잔액 기록
|
|
$formDatas['balance'] = $this->getClientBalance($this->getFreshClientEntity($clientEntity));
|
|
|
|
// 3) wallet row 저장
|
|
$entity = parent::create_process($formDatas);
|
|
if (!$entity) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 고객의 Wallet정보 생성에 실패하였습니다.");
|
|
}
|
|
return $entity;
|
|
}
|
|
|
|
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): CommonEntity
|
|
{
|
|
$amount = (int) ($formDatas['amount'] ?? 0);
|
|
if ($amount <= 0) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$this->title}는 1 이상이어야 합니다.");
|
|
}
|
|
|
|
// 1) DB 원자 차감(충분할 때만)
|
|
$ok = service('customer_clientservice')->decreaseBalance($clientEntity->getPK(), $this->balanceField, $amount);
|
|
|
|
if (!$ok) {
|
|
throw new RuntimeException(sprintf(
|
|
"{$this->title}이 부족합니다. (요청:%s원 / 현재:%s원)",
|
|
number_format($amount),
|
|
number_format((int) $this->getClientBalance($clientEntity)) // 메시지용
|
|
));
|
|
}
|
|
|
|
// 2) ✅ 최신 잔액 재조회 (stale 방지)
|
|
// balanceField를 기반으로 현재잔액 기록
|
|
$formDatas['balance'] = $this->getClientBalance($this->getFreshClientEntity($clientEntity));
|
|
|
|
// 3) wallet row 저장
|
|
$entity = parent::create_process($formDatas);
|
|
if (!$entity) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 고객의 Wallet정보 생성에 실패하였습니다.");
|
|
}
|
|
return $entity;
|
|
}
|
|
|
|
//결제관련 출금 처리(결제를 통해서만 호출되므로 action_init_process로 fields,rules 초기화 필요)
|
|
public function withdrawalByPayment(PaymentEntity $paymentEntity, array $formDatas = []): CommonEntity
|
|
{
|
|
//고객 정보
|
|
$clientEntity = service('customer_clientservice')->getEntity($paymentEntity->getClientInfoUid());
|
|
if (!$clientEntity instanceof ClientEntity) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$paymentEntity->getClientInfoUid()}에 해당하는 고객정보를 찾을수 없습니다.");
|
|
}
|
|
$formDatas['clientinfo_uid'] = $paymentEntity->getClientInfoUid();
|
|
$formDatas['title'] = $paymentEntity->getTitle();
|
|
$formDatas['amount'] = $paymentEntity->getAmount();
|
|
$formDatas['status'] = STATUS['WITHDRAWAL'];
|
|
return $this->create_process($formDatas);
|
|
}
|
|
}
|