dbmsv4/app/Services/Customer/Wallet/WalletService.php
2026-03-04 10:43:59 +09:00

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);
}
}