WalletService.php 5.9 KB

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