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