DiamondWithdrawHandler.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. namespace App\Module\OpenAPI\Handlers\Fund;
  3. use App\Module\OpenAPI\Handlers\BaseHandler;
  4. use App\Module\OpenAPI\Services\ScopeService;
  5. use App\Module\OpenAPI\Services\DeveloperAccountService;
  6. use App\Module\OpenAPI\Enums\SCOPE_TYPE;
  7. use App\Module\OpenAPI\Validations\DiamondWithdrawValidation;
  8. use App\Module\Fund\Services\FundService;
  9. use App\Module\Fund\Enums\FUND_TYPE;
  10. use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
  11. use Illuminate\Http\JsonResponse;
  12. use Illuminate\Support\Facades\DB;
  13. use Illuminate\Support\Facades\Log;
  14. /**
  15. * 钻石提取Handler
  16. *
  17. * 处理开发者从用户账户提取钻石的业务逻辑
  18. * 资金流向:用户钻石账户 -> 开发者提取账户
  19. */
  20. class DiamondWithdrawHandler extends BaseHandler
  21. {
  22. public function __construct(ScopeService $scopeService)
  23. {
  24. parent::__construct($scopeService);
  25. }
  26. /**
  27. * 获取所需的权限范围
  28. *
  29. * @return SCOPE_TYPE[]
  30. */
  31. public function getRequiredScopes(): array
  32. {
  33. return [SCOPE_TYPE::FUND_WITHDRAW];
  34. }
  35. /**
  36. * 处理钻石提取请求
  37. *
  38. * @param array $data 请求数据
  39. * @param array $context 上下文信息
  40. * @return JsonResponse
  41. */
  42. protected function process(array $data, array $context = []): JsonResponse
  43. {
  44. // 使用验证类进行数据验证
  45. $validation = new DiamondWithdrawValidation($data);
  46. $validation->validate();
  47. if ($validation->isFail()) {
  48. return $this->errorResponse('参数验证失败', $validation->getErrors(), 422);
  49. }
  50. // 获取验证后的数据
  51. $safeData = $validation->getSafeData();
  52. $sourceUserId = $safeData['user_id'];
  53. $amount = $safeData['amount'];
  54. $remark = $safeData['remark'] ?? '开发者提取钻石';
  55. $orderId = $safeData['order_id'] ?? null;
  56. // 获取应用信息
  57. $app = $this->getApp($context);
  58. if (!$app) {
  59. return $this->errorResponse('无法获取应用信息', null, 400);
  60. }
  61. try {
  62. DB::beginTransaction();
  63. // 检查开发者账户是否存在
  64. $accountCheck = DeveloperAccountService::checkDeveloperAccounts($app);
  65. if (!$accountCheck['withdraw_account_exists']) {
  66. // 自动创建开发者账户
  67. $createResult = DeveloperAccountService::createDeveloperAccounts($app);
  68. if (!$createResult['success']) {
  69. DB::rollBack();
  70. return $this->errorResponse('创建开发者账户失败', $createResult['message'], 500);
  71. }
  72. }
  73. // 获取开发者提取账户用户ID
  74. $withdrawUserId = DeveloperAccountService::getWithdrawUserId($app->id);
  75. // 检查源用户钻石账户余额
  76. $sourceFundService = new FundService($sourceUserId, FUND_TYPE::FUND2->value);
  77. $sourceAccount = $sourceFundService->getAccount();
  78. if (!$sourceAccount) {
  79. DB::rollBack();
  80. return $this->errorResponse('用户钻石账户不存在', null, 404);
  81. }
  82. $sourceBalance = $sourceFundService->balance();
  83. if ($sourceBalance < $amount) {
  84. DB::rollBack();
  85. return $this->errorResponse('用户钻石账户余额不足', [
  86. 'required' => $amount,
  87. 'available' => $sourceBalance
  88. ], 400);
  89. }
  90. // 确保开发者提取账户存在
  91. $withdrawFundService = new FundService($withdrawUserId, FUND_TYPE::FUND2->value);
  92. $withdrawAccount = $withdrawFundService->getAccount();
  93. if (!$withdrawAccount) {
  94. // 初始化开发者提取账户
  95. $initResult = $withdrawFundService->admin(FUND_TYPE::FUND2, 0, 1, '初始化开发者提取账户');
  96. if (is_string($initResult)) {
  97. DB::rollBack();
  98. return $this->errorResponse('初始化提取账户失败', $initResult, 500);
  99. }
  100. }
  101. // 执行转账:从用户钻石账户转到开发者提取账户
  102. $transferResult = $sourceFundService->transfer(
  103. $withdrawUserId,
  104. $amount,
  105. $remark . ($orderId ? " (订单号: {$orderId})" : '')
  106. );
  107. if (is_string($transferResult)) {
  108. DB::rollBack();
  109. return $this->errorResponse('提取转账失败', $transferResult, 500);
  110. }
  111. DB::commit();
  112. // 记录操作日志
  113. $this->logAction('diamond.withdraw', [
  114. 'app_id' => $app->id,
  115. 'source_user_id' => $sourceUserId,
  116. 'withdraw_user_id' => $withdrawUserId,
  117. 'amount' => $amount,
  118. 'order_id' => $orderId,
  119. 'transfer_id' => $transferResult->transferId,
  120. ], $context);
  121. // 获取提取后的账户信息
  122. $sourceAccountInfo = $sourceFundService->getAccount();
  123. $withdrawAccountInfo = $withdrawFundService->getAccount();
  124. $responseData = [
  125. 'transfer_id' => $transferResult->transferId,
  126. 'order_id' => $orderId,
  127. 'amount' => $amount,
  128. 'currency_type' => FUND_CURRENCY_TYPE::ZUANSHI->value,
  129. 'currency_name' => FUND_CURRENCY_TYPE::ZUANSHI->getCurrencyName(),
  130. 'from_account' => [
  131. 'user_id' => $sourceUserId,
  132. 'account_type' => '用户钻石账户',
  133. 'balance_after' => $sourceAccountInfo ? $sourceAccountInfo->balance : 0,
  134. ],
  135. 'to_account' => [
  136. 'user_id' => $withdrawUserId,
  137. 'account_type' => '开发者提取账户',
  138. 'balance_after' => $withdrawAccountInfo ? $withdrawAccountInfo->balance : 0,
  139. ],
  140. 'remark' => $remark,
  141. 'created_at' => $transferResult->createdAt,
  142. ];
  143. return $this->successResponse('钻石提取成功', $responseData);
  144. } catch (\Exception $e) {
  145. DB::rollBack();
  146. Log::error('钻石提取失败', [
  147. 'app_id' => $app->id,
  148. 'source_user_id' => $sourceUserId,
  149. 'amount' => $amount,
  150. 'error' => $e->getMessage(),
  151. 'trace' => $e->getTraceAsString()
  152. ]);
  153. return $this->errorResponse('提取处理失败', $e->getMessage(), 500);
  154. }
  155. }
  156. /**
  157. * 获取开发者提取账户余额信息
  158. *
  159. * @param array $data 请求数据
  160. * @param array $context 上下文信息
  161. * @return JsonResponse
  162. */
  163. public function getWithdrawAccountBalance(array $data, array $context = []): JsonResponse
  164. {
  165. // 获取应用信息
  166. $app = $this->getApp($context);
  167. if (!$app) {
  168. return $this->errorResponse('无法获取应用信息', null, 400);
  169. }
  170. try {
  171. // 获取开发者账户信息
  172. $accountInfo = DeveloperAccountService::getDeveloperAccountInfo($app);
  173. $responseData = [
  174. 'app_id' => $app->id,
  175. 'app_name' => $app->name,
  176. 'withdraw_account' => $accountInfo['withdraw_account'],
  177. 'currency_type' => FUND_CURRENCY_TYPE::ZUANSHI->value,
  178. 'currency_name' => FUND_CURRENCY_TYPE::ZUANSHI->getCurrencyName(),
  179. 'precision' => FUND_CURRENCY_TYPE::ZUANSHI->getPrecision(),
  180. ];
  181. return $this->successResponse('获取提取账户余额成功', $responseData);
  182. } catch (\Exception $e) {
  183. Log::error('获取提取账户余额失败', [
  184. 'app_id' => $app->id,
  185. 'error' => $e->getMessage(),
  186. ]);
  187. return $this->errorResponse('获取账户信息失败', $e->getMessage(), 500);
  188. }
  189. }
  190. }