WalletService.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. namespace App\Services\Client;
  3. use App\Enums\UserStatus;
  4. use App\Enums\WithdrawStatus;
  5. use App\Models\MemberUser;
  6. use App\Models\Wallet;
  7. use App\Models\WalletTransRecord;
  8. use App\Models\WalletWithdrawRecord;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. class WalletService
  12. {
  13. /**
  14. * [钱包管理]获取钱包明细
  15. *
  16. * @param int $userId 用户ID
  17. * @param int $perPage 每页记录数
  18. * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
  19. *
  20. * @throws \Exception
  21. */
  22. public function getWalletRecords($userId, $perPage = 10)
  23. {
  24. try {
  25. // 获取当前用户
  26. $user = MemberUser::find($userId);
  27. // 检查用户是否存在
  28. abort_if(! $user, 400, '用户不存在');
  29. // 检查用户状态
  30. abort_if($user->state != UserStatus::OPEN->value, 400, '用户状态异常');
  31. // 获取钱包交易记录
  32. $records = $user->wallet->transRecords()
  33. ->orderBy('created_at', 'desc')
  34. ->paginate($perPage);
  35. return $records;
  36. } catch (\Exception $e) {
  37. // 记录错误日志
  38. \Log::error('获取钱包明细失败', [
  39. 'userId' => $userId,
  40. 'error' => $e->getMessage(),
  41. 'trace' => $e->getTraceAsString(),
  42. ]);
  43. throw $e;
  44. }
  45. }
  46. /**
  47. * 获取用户钱包
  48. */
  49. public function getUserWallet($userId)
  50. {
  51. try {
  52. $user = MemberUser::find($userId);
  53. abort_if(! $user, 400, '用户不存在');
  54. abort_if($user->state != UserStatus::OPEN->value, 400, '用户状态异常');
  55. $wallet = $user->wallet;
  56. if (! $wallet) {
  57. Log::warning('用户钱包不存在', ['user_id' => $user->id]);
  58. throw new \Exception('钱包不存在');
  59. }
  60. return $wallet;
  61. } catch (\Exception $e) {
  62. Log::error('获取用户钱包失败', ['error' => $e->getMessage()]);
  63. throw $e;
  64. }
  65. }
  66. /**
  67. * 用户钱包提现
  68. *
  69. * @param int $userId 用户ID
  70. * @param array $data 提现数据
  71. * @return array
  72. *
  73. * @throws \Exception
  74. */
  75. public function withdraw(int $userId, array $data)
  76. {
  77. return DB::transaction(function () use ($userId, $data) {
  78. try {
  79. // 获取用户信息
  80. $user = MemberUser::findOrFail($userId);
  81. abort_if($user->state != UserStatus::OPEN->value, 400, '用户状态异常');
  82. abort_if(! $user->wallet, 404, '钱包信息不存在');
  83. // 锁定钱包记录
  84. $wallet = Wallet::where('id', $user->wallet->id)
  85. ->lockForUpdate()
  86. ->first();
  87. // 验证提现金额
  88. $amount = $data['amount'];
  89. abort_if($amount <= 100, 422, '提现金额必须大于100元');
  90. abort_if($amount > $wallet->available_balance, 422, '可提现余额不足');
  91. // 生成交易流水号
  92. $transNo = 'CW' . date('YmdHis') . mt_rand(1000, 9999);
  93. // 创建提现记录
  94. $withdraw = WalletWithdrawRecord::create([
  95. 'wallet_id' => $wallet->id, // 钱包ID
  96. 'trans_no' => $transNo, // 交易流水号
  97. 'amount' => $amount, // 提现金额
  98. 'withdraw_type' => $data['withdraw_type'], // 提现方式(1:微信 2:支付宝 3:银行卡)
  99. 'withdraw_account' => $data['withdraw_account'], // 提现账号
  100. 'withdraw_account_name' => $data['withdraw_account_name'], // 提现账户名称
  101. 'state' => WithdrawStatus::PROCESSING, // 提现状态
  102. ]);
  103. // 创建交易记录
  104. WalletTransRecord::create([
  105. 'wallet_id' => $wallet->id,
  106. 'trans_no' => $transNo,
  107. 'trans_type' => 2, // 支出
  108. 'amount' => -$amount,
  109. 'before_balance' => $wallet->available_balance,
  110. 'after_balance' => $wallet->available_balance - $amount,
  111. 'owner_type' => WalletWithdrawRecord::class,
  112. 'owner_id' => $withdraw->id,
  113. 'remark' => '提现申请',
  114. 'state' => 2, // 处理中
  115. ]);
  116. // 冻结提现金额
  117. $wallet->decrement('available_balance', $amount);
  118. $wallet->increment('frozen_amount', $amount);
  119. // 记录日志
  120. Log::info('用户提现申请成功', [
  121. 'user_id' => $userId,
  122. 'trans_no' => $transNo,
  123. 'amount' => $amount,
  124. 'wallet_id' => $wallet->id,
  125. ]);
  126. return [
  127. 'message' => '提现申请已提交',
  128. 'trans_no' => $transNo,
  129. 'amount' => number_format($amount, 2, '.', ''),
  130. 'state' => '处理中',
  131. ];
  132. } catch (\Exception $e) {
  133. Log::error('用户提现申请失败', [
  134. 'user_id' => $userId,
  135. 'data' => $data,
  136. 'error' => $e->getMessage(),
  137. 'file' => $e->getFile(),
  138. 'line' => $e->getLine(),
  139. ]);
  140. throw $e;
  141. }
  142. });
  143. }
  144. }