dbmsv4 init...5

This commit is contained in:
최준흠 2026-03-04 10:43:59 +09:00
parent 68a06aaac9
commit 6983a5f3de
44 changed files with 329 additions and 255 deletions

View File

@ -11,7 +11,7 @@ class ServiceCell extends CustomerCell
public function detail(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
//서비스별 미납 Count
$unPaids = service('paymentservice')->getUnPaids('serviceinfo_uid', ['clientinfo_uid' => $params['clientinfo_uid']]);
//서비스별 서버리스트

View File

@ -59,7 +59,7 @@ class ServerCell extends EquipmentCell
}
public function detail(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
if (!array_key_exists('serviceEntity', $params)) {
return static::class . '->' . __FUNCTION__ . "에서 오류발생: 서비스 정보가 정의되지 않았습니다.";
}

View File

@ -14,7 +14,7 @@ class ServerPartCell extends EquipmentCell
public function parttable(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
if (!array_key_exists('serverinfo_uid', $params)) {
return "서버정보를 정의하셔야합니다.";
}

View File

@ -15,7 +15,7 @@ class MylogCell extends CommonCell
public function dashboard(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
$this->getService()->setLimit(20);
$template = array_key_exists('template', $params) ? $params['template'] : __FUNCTION__;
return view('cells/mylog/' . $template, [

View File

@ -13,7 +13,7 @@ class DISKCell extends PartCell
public function stock(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
$template = array_key_exists('template', $params) ? $params['template'] : 'disk_stock';
return view('cells/part/' . $template, [
'partCellDatas' => [

View File

@ -14,7 +14,7 @@ class PaymentCell extends CommonCell
public function detail(array $params): string
{
$this->getService()->getActionForm()->action_init_process(__FUNCTION__);
$this->getService()->getActionForm()->form_init_process(__FUNCTION__);
$entities = $this->getService()->getEntities(['clientinfo_uid' => $params['clientinfo_uid'], 'billing' => PAYMENT['BILLING']['ONETIME'], 'status' => STATUS['UNPAID']]);
$template = array_key_exists('template', $params) ? $params['template'] : __FUNCTION__;
return view('cells/payment/' . $template, [

View File

@ -23,7 +23,7 @@ abstract class AdminController extends CommonController
$this->addViewDatas('layout', $this->layouts);
$this->addViewDatas('title', $this->getTitle());
$this->addViewDatas('helper', $this->service->getHelper());
$this->service->getActionForm()->action_init_process($action, $formDatas);
$this->service->getActionForm()->form_init_process($action, $formDatas);
$this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields());
$this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules());
$this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters());

View File

@ -25,7 +25,7 @@ class Home extends AbstractWebController
parent::action_init_process($action, $formDatas);
$this->addViewDatas('layout', $this->layouts);
$this->addViewDatas('helper', $this->service->getHelper());
$this->service->getActionForm()->action_init_process($action, $formDatas);
$this->service->getActionForm()->form_init_process($action, $formDatas);
$this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields());
$this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules());
$this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters());

View File

@ -23,7 +23,7 @@ abstract class AdminController extends AjaxController
$this->addViewDatas('layout', $this->layouts);
$this->addViewDatas('title', $this->getTitle());
$this->addViewDatas('helper', $this->service->getHelper());
$this->service->getActionForm()->action_init_process($action, $formDatas);
$this->service->getActionForm()->form_init_process($action, $formDatas);
$this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields());
$this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules());
$this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters());

View File

@ -23,7 +23,7 @@ abstract class AjaxController extends AbstractCRUDController
$this->addViewDatas('layout', $this->layouts);
$this->addViewDatas('title', $this->getTitle());
$this->addViewDatas('helper', $this->service->getHelper());
$this->service->getActionForm()->action_init_process($action, $formDatas);
$this->service->getActionForm()->form_init_process($action, $formDatas);
$this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields());
$this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules());
$this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters());

View File

@ -25,7 +25,7 @@ abstract class AuthController extends AbstractWebController
$this->addViewDatas('layout', $this->layouts);
$this->addViewDatas('helper', $this->service->getHelper());
//Fields,Rules,Filters,Options등 초기화
$this->service->getActionForm()->action_init_process($action, $formDatas);
$this->service->getActionForm()->form_init_process($action, $formDatas);
$this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields());
$this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules());
$this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters());

View File

@ -10,9 +10,9 @@ class GoogleForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = ['access_code'];
$filters = [];
switch ($action) {

View File

@ -10,9 +10,9 @@ class LocalForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = ['id', 'passwd'];
$filters = [];
switch ($action) {

View File

@ -10,9 +10,9 @@ class BoardForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
'category',
'worker_uid',

View File

@ -34,7 +34,7 @@ abstract class CommonForm
$this->_validation = service('validation');
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Called...");
$this->formAction = $action;
@ -314,6 +314,8 @@ abstract class CommonForm
}
// 2) 액션별 "검증 대상 필드" 결정
$formRules = $allFormRules;
$formFields = $allFormFields;
if ($this->formAction === 'modify') {
// (1) formDatas에 실제로 넘어온 필드만
$targetFields = array_keys($formDatas);
@ -341,12 +343,8 @@ abstract class CommonForm
// 최종: modify에서는 "타겟만" 룰/라벨 세팅
$formRules = $this->getFormRules($targetFields);
$formFields = $this->getFormFields($targetFields);
} else {
// create (및 기타 액션): 전체 룰 검사
$formRules = $allFormRules;
$formFields = $allFormFields;
// throw new RuntimeException(static::class . "->targetFields" . implode(",", $targetFields) . "\nformRules:" . implode(",", array_keys($formRules)) . "\nformFields:" . implode(",", array_keys($formFields)));
}
if (empty($formRules)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 검증할 대상 RULE이 없습니다.");
}
@ -382,7 +380,14 @@ abstract class CommonForm
$this->_validation->setRules($dynamicRules);
if (!$this->_validation->run($formDatas)) {
$errors = $this->_validation->getErrors();
throw new RuntimeException(implode("\n", $errors));
throw new RuntimeException(sprintf(
"%s->%s작업 필수항목\nformDatas->%s\ndynamicRules->%s\n%s",
static::class,
$this->formAction,
var_export($formDatas, true),
implode(",", array_keys($dynamicRules)),
implode("\n", $errors)
));
}
} catch (\Throwable $e) {

View File

@ -8,9 +8,9 @@ class ClientForm extends CustomerForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
'site',
'name',

View File

@ -8,9 +8,9 @@ class ServiceForm extends CustomerForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"site",
"location",

View File

@ -8,9 +8,9 @@ class AccountForm extends WalletForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"clientinfo_uid",
"bank",

View File

@ -8,9 +8,9 @@ class CouponForm extends WalletForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"clientinfo_uid",
"title",

View File

@ -8,9 +8,9 @@ class PointForm extends WalletForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"clientinfo_uid",
"title",

View File

@ -8,9 +8,9 @@ class CHASSISForm extends EquipmentForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"title",
"price",

View File

@ -8,9 +8,9 @@ class LineForm extends EquipmentForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"type",
"protocol",

View File

@ -8,9 +8,9 @@ class ServerForm extends EquipmentForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"code",
"type",

View File

@ -10,9 +10,9 @@ class ServerPartForm extends EquipmentForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"serverinfo_uid",
"type",

View File

@ -10,9 +10,9 @@ class MylogForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = ['title', 'content', 'status'];
$filters = ['user_uid', 'status'];
$indexFilter = $filters;

View File

@ -8,9 +8,9 @@ class CPUForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"title",
"price",

View File

@ -8,9 +8,9 @@ class CSForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"type",
"ip",

View File

@ -8,9 +8,9 @@ class DISKForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"title",
"price",

View File

@ -8,9 +8,9 @@ class IPForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"lineinfo_uid",
"ip",

View File

@ -8,9 +8,9 @@ class RAMForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"title",
"price",

View File

@ -8,9 +8,9 @@ class SOFTWAREForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"title",
"price",

View File

@ -8,9 +8,9 @@ class SWITCHForm extends PartForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"code",
"price",

View File

@ -10,9 +10,9 @@ class PaymentForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
"serviceinfo_uid",
"title",

View File

@ -10,9 +10,9 @@ class UserForm extends CommonForm
{
parent::__construct();
}
public function action_init_process(string $action, array &$formDatas = []): void
public function form_init_process(string $action, array &$formDatas = []): void
{
parent::action_init_process($action, $formDatas);
parent::form_init_process($action, $formDatas);
$fields = [
'id',
'passwd',

View File

@ -6,6 +6,7 @@ use App\Entities\UserEntity;
use App\Helpers\AuthHelper;
use App\Models\CommonModel;
use App\Services\CommonService;
use CodeIgniter\Exceptions\PageNotFoundException;
abstract class AuthService extends CommonService
{
@ -24,10 +25,15 @@ abstract class AuthService extends CommonService
abstract protected function login_process(array $formDatas): UserEntity;
final public function login(array $formDatas): UserEntity
{
$entity = $this->login_process($formDatas);
//인증 세션처리
$this->getAuthContext()->setAuthSession($entity);
return $entity;
try {
$entity = $this->login_process($formDatas);
//인증 세션처리
$this->getAuthContext()->setAuthSession($entity);
return $entity;
} catch (\Exception $e) {
log_message('error', $e->getMessage());
throw new PageNotFoundException("관리자에게 문의하시기 바랍니다.\n{$e->getMessage()}");
}
}
//로그아웃
final public function logout(): void

View File

@ -24,23 +24,18 @@ class GoogleService extends AuthService
//기본기능
protected function login_process(array $formDatas): UserEntity
{
try {
//입력값 검증
$this->getActionForm()->validate($formDatas);
$this->socket->setToken($formDatas['access_code']);
$sns_entity = $this->socket->signup();
// local db 사용와의 연결 확인
$entity = $this->getEntity($sns_entity->getParent());
if (!$entity instanceof UserEntity) {
throw new PageNotFoundException("회원[{$sns_entity->getTitle()}]님은 아직 로컬사용자 연결이 이루어지지 않았습니다.");
}
return $entity;
// } catch (\Google_Service_Exception $e) {
// log_message('error', '구글 서비스 예외발생: ' . $e->getMessage());
// throw new PageNotFoundException("구글 로그인 중 오류가 발생했습니다. 다시 시도해 주세요.");
} catch (\Exception $e) {
log_message('error', $e->getMessage());
throw new PageNotFoundException("관리자에게 문의하시기 바랍니다.\n{$e->getMessage()}");
//입력값 검증
$this->getActionForm()->validate($formDatas);
$this->socket->setToken($formDatas['access_code']);
$sns_entity = $this->socket->signup();
// local db 사용와의 연결 확인
$entity = $this->getEntity($sns_entity->getParent());
if (!$entity instanceof UserEntity) {
throw new PageNotFoundException("회원[{$sns_entity->getTitle()}]님은 아직 로컬사용자 연결이 이루어지지 않았습니다.");
}
return $entity;
// } catch (\Google_Service_Exception $e) {
// log_message('error', '구글 서비스 예외발생: ' . $e->getMessage());
// throw new PageNotFoundException("구글 로그인 중 오류가 발생했습니다. 다시 시도해 주세요.");
}
}

View File

@ -23,7 +23,7 @@ class LocalService extends AuthService
}
protected function login_process(array $formDatas): UserEntity
{
$this->getActionForm()->action_init_process('login', $formDatas);
$this->getActionForm()->form_init_process('login', $formDatas);
//입력값 검증
$this->getActionForm()->validate($formDatas);
//로그인 정보확인

View File

@ -239,7 +239,7 @@ abstract class CommonService
if (!$actionForm instanceof CommonForm) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
}
$actionForm->action_init_process('create', $formDatas);
$actionForm->form_init_process('create', $formDatas);
$actionForm->validate($formDatas); // ✅ 여기서 검증
// 검증 통과 후 엔티티 반영용
foreach ($formDatas as $field => $value) {
@ -280,7 +280,7 @@ abstract class CommonService
if (!$actionForm instanceof CommonForm) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
}
$actionForm->action_init_process('modify', $formDatas);
$actionForm->form_init_process('modify', $formDatas);
$actionForm->validate($formDatas); // ✅ 여기서 검증
// 검증 통과 후 엔티티 반영
foreach ($formDatas as $field => $value) {

View File

@ -13,6 +13,15 @@ class ClientService extends CustomerService
{
protected string $formClass = ClientForm::class;
protected string $helperClass = ClientHelper::class;
/**
* 허용할 잔액 컬럼 화이트리스트 (필수!)
* - $field를 외부에서 받으면 SQL injection 포인트가 되기 쉬움
*/
protected array $balanceFields = [
'account_balance',
'coupon_balance',
'point_balance',
];
public function __construct(ClientModel $model)
{
@ -53,29 +62,7 @@ class ClientService extends CustomerService
}
return $formDatas;
}
// protected function modify_process_fieldhook(array $formDatas): array
// {
// // 1) DB 컬럼 아닌 값 제거
// unset($formDatas['confirmpassword']);
// // 2) role은 무조건 문자열로
// if (array_key_exists('role', $formDatas)) {
// $arr = is_array($formDatas['role'])
// ? $formDatas['role']
// : explode(',', (string) $formDatas['role']);
// $arr = array_values(array_filter(array_map('trim', $arr)));
// sort($arr);
// $formDatas['role'] = implode(',', $arr);
// }
// // 3) passwd는 빈 값이면 업데이트 제외 (원하면)
// if (array_key_exists('passwd', $formDatas) && $formDatas['passwd'] === '') {
// unset($formDatas['passwd']);
// }
// return $formDatas;
// }
public function history(string|int $uid, string $history): CommonEntity
{
return $this->dbTransaction(function () use ($uid, $history) {
@ -93,4 +80,77 @@ class ClientService extends CustomerService
return $this->save_process($entity);
}, __FUNCTION__);
}
/**
* 원자 증가
* - DB에서 field = field + amount 처리
* - (선택) 음수로 내려가면 안되면 아래에서 막거나 decreaseBalanceIfEnough 사용
*/
public function increaseBalance(int $pk, string $field, int $amount): void
{
//field가 예치금 , 쿠폰 , 포인트에 해당하는 것인지 확인
if (!in_array($field, $this->balanceFields, true)) {
throw new RuntimeException(static::class . "->" . __FUNCTION__ . "에서 오류발생: 허용되지 않은 field={$field}");
}
if ($amount === 0) {
return;
}
// update()는 set()에서 RawSQL/escape=false 사용 가능
$builder = $this->model->builder();
$builder->where($this->model->primaryKey, $pk);
// field = field + (amount)
$expr = "{$field} + (" . (int) $amount . ")";
$ok = $builder->set($field, $expr, false)->update();
if (!$ok) {
$errors = $this->model->errors();
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생[{$field}]: " .
(is_array($errors) ? implode(", ", $errors) : 'DB update 실패'));
}
// 영향 받은 row가 없으면 PK가 없거나 update 실패
if ($this->model->db->affectedRows() < 1) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 대상 PK({$pk}) 업데이트 실패");
}
}
/**
* 출금(감소) - 잔액이 충분할 때만 감소 (원자 처리)
* - where field >= amount 조건으로 동시에 들어와도 안전
* - 성공 true / 잔액부족 false
*/
public function decreaseBalance(int $pk, string $field, int $amount): bool
{
//field가 예치금 , 쿠폰 , 포인트에 해당하는 것인지 확인
if (!in_array($field, $this->balanceFields, true)) {
throw new RuntimeException(static::class . "->" . __FUNCTION__ . "에서 오류발생: 허용되지 않은 field={$field}");
}
if ($amount < 0) {
throw new RuntimeException(static::class . "->" . __FUNCTION__ . "에서 오류발생: balance는 0 이상이어야 합니다.");
}
if ($amount === 0) {
return true;
}
$builder = $this->model->builder();
$builder->where($this->model->primaryKey, $pk);
$builder->where("{$field} >=", (int) $amount);
// field = field - amount
$expr = "{$field} - (" . (int) $amount . ")";
$ok = $builder->set($field, $expr, false)->update();
if (!$ok) {
$errors = $this->model->errors();
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생[{$field}]: " .
(is_array($errors) ? implode(", ", $errors) : 'DB update 실패'));
}
// 조건을 만족하지 못하면 affectedRows=0 => 잔액 부족 또는 PK 없음
return ($this->model->db->affectedRows() > 0);
}
}

View File

@ -5,6 +5,7 @@ namespace App\Services\Customer\Wallet;
use App\Entities\CommonEntity;
use App\Entities\Customer\ClientEntity;
use App\Entities\Customer\Wallet\AccountEntity;
use App\Entities\PaymentEntity;
use App\Forms\Customer\Wallet\AccountForm;
use App\Helpers\Customer\Wallet\AccountHelper;
use App\Models\Customer\Wallet\AccountModel;
@ -12,7 +13,6 @@ use RuntimeException;
class AccountService extends WalletService
{
const CLIENTINFO_BALANCE_FIELD = 'account_balance';
protected string $formClass = AccountForm::class;
protected string $helperClass = AccountHelper::class;
@ -20,6 +20,8 @@ class AccountService extends WalletService
{
parent::__construct($model);
$this->addClassPaths('Account');
$this->title = "예치금";
$this->balanceField = 'account_balance';
}
public function getEntityClass(): string
{
@ -30,10 +32,7 @@ class AccountService extends WalletService
{
return $entity;
}
protected function modify_process($entity, array $formDatas): CommonEntity
{
throw new RuntimeException("예치금정보는 수정이 불가합니다.");
}
//List 검색용
//FormFilter 조건절 처리
//검색어조건절처리
@ -42,49 +41,39 @@ class AccountService extends WalletService
$this->model->orLike($this->model->getTable() . '.alias', $word, 'both');
parent::setSearchWord($word);
}
//입금,쿠폰 충전 처리
protected function deposit_process(ClientEntity $clientEntity, array $formDatas): array
//고객 예치금
protected function getClientBalance(ClientEntity $clientEntity): int
{
if (!array_key_exists('amount', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 출금액이 정의되지 않았습니다.");
return $clientEntity->getAccountBalance();
}
//예치금 입금 처리
protected function deposit_process(ClientEntity $clientEntity, array $formDatas): CommonEntity
{
if (!array_key_exists('bank', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 은행이 정의되지 않았습니다.");
}
//최종처리
$formDatas['balance'] = $clientEntity->getAccountBalance() + $formDatas['amount'];
if ($formDatas['balance'] < 0) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 잔액이 0보다 값이 정의 되었습니다.");
}
//고객 잔액 갱신
service('customer_clientservice')->modify($clientEntity->getPK(), [self::CLIENTINFO_BALANCE_FIELD => $formDatas['balance']]);
// 기본값 세팅
$formDatas['alias'] = $formDatas['alias'] ?? $clientEntity->getTitle();
$formDatas['issue_at'] = array_key_exists('issue_at', $formDatas) ? $formDatas['issue_at'] : date('Y-m-d');
return parent::deposit_process($clientEntity, $formDatas);
}
//결제 관련 출금 처리
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): array
//예치금 출금 처리
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): CommonEntity
{
try {
if (!array_key_exists('amount', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 출금액이 정의되지 않았습니다.");
}
if ($clientEntity->getAccountBalance() < $formDatas['amount']) {
throw new RuntimeException(sprintf(
"%s 에서 오류발생: 출금액(%s원) , %s 고객의 예치금액(%s원)이 부족합니다.",
static::class . '->' . __FUNCTION__,
number_format($formDatas['amount']),
$clientEntity->getTitle(),
number_format($clientEntity->getAccountBalance())
));
}
//최종처리
$formDatas['bank'] = array_key_exists('bank', $formDatas) ? $formDatas['bank'] : BANKS['결제차감'];
$formDatas['alias'] = array_key_exists('alias', $formDatas) ? $formDatas['alias'] : $clientEntity->getTitle();
$formDatas['balance'] = $clientEntity->getAccountBalance() - $formDatas['amount'];
if ($formDatas['balance'] < 0) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 잔액({$formDatas['balance']})이 0보다 작은 값이 정의되었습니다.");
}
//고객의 Account Balance수정
service('customer_clientservice')->modify($clientEntity->getPK(), [self::CLIENTINFO_BALANCE_FIELD => $formDatas['balance']]);
return parent::withdrawal_process($clientEntity, $formDatas);
} catch (\Throwable $e) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:" . $e->getMessage());
if (!array_key_exists('bank', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 은행이 정의되지 않았습니다.");
}
// 기본값 세팅
$formDatas['alias'] = $formDatas['alias'] ?? $clientEntity->getTitle();
$formDatas['issue_at'] = array_key_exists('issue_at', $formDatas) ? $formDatas['issue_at'] : date('Y-m-d');
return parent::withdrawal_process($clientEntity, $formDatas);
}
public function withdrawalByPayment(PaymentEntity $paymentEntity, array $formDatas = []): CommonEntity
{
$formDatas['bank'] = BANKS['결제차감'];
return parent::withdrawalByPayment($paymentEntity, $formDatas);
}
}

View File

@ -2,17 +2,14 @@
namespace App\Services\Customer\Wallet;
use App\Entities\CommonEntity;
use App\Entities\Customer\ClientEntity;
use App\Entities\Customer\Wallet\CouponEntity;
use App\Forms\Customer\Wallet\CouponForm;
use App\Helpers\Customer\Wallet\CouponHelper;
use App\Models\Customer\Wallet\CouponModel;
use RuntimeException;
class CouponService extends WalletService
{
const CLIENTINFO_BALANCE_FIELD = 'coupon_balance';
protected string $formClass = CouponForm::class;
protected string $helperClass = CouponHelper::class;
@ -20,6 +17,8 @@ class CouponService extends WalletService
{
parent::__construct($model);
$this->addClassPaths('Coupon');
$this->title = "쿠폰";
$this->balanceField = 'coupon_balance';
}
public function getEntityClass(): string
{
@ -30,51 +29,12 @@ class CouponService extends WalletService
{
return $entity;
}
protected function modify_process($entity, array $formDatas): CommonEntity
//고객 쿠폰
protected function getClientBalance(ClientEntity $clientEntity): int
{
throw new RuntimeException("쿠폰정보는 수정이 불가합니다.");
return $clientEntity->getCouponBalance();
}
//List 검색용
//FormFilter 조건절 처리
//검색어조건절처리
//입금,쿠폰 충전 처리
protected function deposit_process(ClientEntity $clientEntity, array $formDatas): array
{
if (!array_key_exists('amount', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 쿠폰수가 정의되지 않았습니다.");
}
//최종처리
$formDatas['balance'] = $clientEntity->getCouponBalance() + $formDatas['amount'];
if ($formDatas['balance'] < 0) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 쿠폰수가 0보다 작은 값이 정의 되었습니다.");
}
//고객 잔액 갱신
service('customer_clientservice')->modify_process($clientEntity, [self::CLIENTINFO_BALANCE_FIELD => $formDatas['balance']]);
return parent::deposit_process($clientEntity, $formDatas);
}
//결제 관련 쿠폰 사용 처리
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): array
{
if (!array_key_exists('amount', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 출금액이 정의되지 않았습니다.");
}
if ($clientEntity->getCouponBalance() < $formDatas['amount']) {
throw new RuntimeException(sprintf(
"%s 에서 오류발생: 사용쿠폰 수량(%s) , %s 잔여쿠폰 수량(%s)이 부족합니다.",
static::class . '->' . __FUNCTION__,
number_format($formDatas['amount']),
$clientEntity->getTitle(),
number_format($clientEntity->getCouponBalance())
));
}
//최종처리
$formDatas['balance'] = $clientEntity->getCouponBalance() - $formDatas['amount'];
if ($formDatas['balance'] < 0) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 잔여쿠폰수량({$formDatas['balance']})이 0보다 작은 값이 정의되었습니다.");
}
//고객 잔여쿠폰 갱신
service('customer_clientservice')->modify_process($clientEntity, [self::CLIENTINFO_BALANCE_FIELD => $formDatas['balance']]);
return parent::withdrawal_process($clientEntity, $formDatas);
}
}

View File

@ -2,17 +2,14 @@
namespace App\Services\Customer\Wallet;
use App\Entities\CommonEntity;
use App\Entities\Customer\ClientEntity;
use App\Entities\Customer\Wallet\PointEntity;
use App\Forms\Customer\Wallet\PointForm;
use App\Helpers\Customer\Wallet\PointHelper;
use App\Models\Customer\Wallet\PointModel;
use RuntimeException;
class PointService extends WalletService
{
const CLIENTINFO_BALANCE_FIELD = 'point_balance';
protected string $formClass = PointForm::class;
protected string $helperClass = PointHelper::class;
@ -20,6 +17,8 @@ class PointService extends WalletService
{
parent::__construct($model);
$this->addClassPaths('Point');
$this->title = "포인트";
$this->balanceField = 'point_balance';
}
public function getEntityClass(): string
{
@ -30,36 +29,12 @@ class PointService extends WalletService
{
return $entity;
}
protected function modify_process($entity, array $formDatas): CommonEntity
//고객 예치금
protected function getClientBalance(ClientEntity $clientEntity): int
{
throw new RuntimeException("포인트정보는 수정이 불가합니다.");
return $clientEntity->getPointBalance();
}
//List 검색용
//FormFilter 조건절 처리
//검색어조건절처리
//결제 관련 포인트 사용 처리
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): array
{
if (!array_key_exists('amount', $formDatas)) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 사용포인트가 정의되지 않았습니다.");
}
if ($clientEntity->getPointBalance() < $formDatas['amount']) {
throw new RuntimeException(sprintf(
"%s 에서 오류발생: 사용포인트(%s) , %s 잔여포인트(%s)가 부족합니다.",
static::class . '->' . __FUNCTION__,
number_format($formDatas['amount']),
$clientEntity->getTitle(),
number_format($clientEntity->getPointBalance())
));
}
//최종처리
$formDatas['balance'] = $clientEntity->getPointBalance() - $formDatas['amount'];
if ($formDatas['balance'] < 0) {
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 잔여포인트({$formDatas['balance']})가 0보다 작은 값이 정의되었습니다.");
}
//고객 잔여포인트 갱신
service('customer_clientservice')->modify_process($clientEntity, [self::CLIENTINFO_BALANCE_FIELD => $formDatas['balance']]);
return parent::withdrawal_process($clientEntity, $formDatas);
}
}

View File

@ -11,64 +11,135 @@ 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']:
$formDatas = $this->deposit_process($clientEntity, $formDatas);
$entity = $this->deposit_process($clientEntity, $formDatas);
break;
case STATUS['WITHDRAWAL']:
$formDatas = $this->withdrawal_process($clientEntity, $formDatas);
$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 deposit_process(ClientEntity $clientEntity, array $formDatas): array
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): CommonEntity
{
$formDatas['issue_at'] = array_key_exists('issue_at', $formDatas) ? $formDatas['issue_at'] : date('Y-m-d');
return $formDatas;
}
//출금,쿠폰 사용 처리
protected function withdrawal_process(ClientEntity $clientEntity, array $formDatas): array
{
$formDatas['issue_at'] = array_key_exists('issue_at', $formDatas) ? $formDatas['issue_at'] : date('Y-m-d');
return $formDatas;
$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 초기화 필요)
final public function withdrawalByPayment(PaymentEntity $paymentEntity): void
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(),
'title' => $paymentEntity->getTitle(),
'amount' => $paymentEntity->getAmount(),
'status' => STATUS['WITHDRAWAL'],
];
$this->create_process($formDatas);
$formDatas['clientinfo_uid'] = $paymentEntity->getClientInfoUid();
$formDatas['title'] = $paymentEntity->getTitle();
$formDatas['amount'] = $paymentEntity->getAmount();
$formDatas['status'] = STATUS['WITHDRAWAL'];
return $this->create_process($formDatas);
}
}

View File

@ -121,9 +121,14 @@ class ServerService extends EquipmentService
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServerEntity만 가능");
}
if ($entity->getIP()) {
service('part_ipservice')->attachToServer($entity);
try {
if ($entity->getIP()) {
service('part_ipservice')->attachToServer($entity);
}
} catch (\Throwable $e) {
log_message('debug', static::class . '->' . __FUNCTION__ . '에서:' . $e->getMessage());
}
if ($entity->getSwitchInfoUid()) {
service('part_switchservice')->attachToServer($entity);
}
@ -147,11 +152,19 @@ class ServerService extends EquipmentService
}
if ($oldEntity->getIP() !== $entity->getIP()) {
if ($oldEntity->getIP() !== null) { //null이거나 공백인경우
service('part_ipservice')->detachFromServer($oldEntity);
try {
if ($oldEntity->getIP()) {
service('part_ipservice')->detachFromServer($oldEntity);
}
} catch (\Throwable $e) {
log_message('debug', static::class . '->' . __FUNCTION__ . '에서:' . $e->getMessage());
}
if ($entity->getIP() !== null) {
service('part_ipservice')->attachToServer($entity);
try {
if ($entity->getIP()) {
service('part_ipservice')->attachToServer($entity);
}
} catch (\Throwable $e) {
log_message('debug', static::class . '->' . __FUNCTION__ . '에서:' . $e->getMessage());
}
}