123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- <?php
- namespace App\Services\Admin;
- use App\Models\WalletWithdrawRecord;
- use App\Models\WalletTransRecord;
- use App\Enums\WithdrawStatus;
- use App\Enums\WithdrawAuditStatus;
- use App\Enums\TransactionType;
- use App\Enums\TransactionStatus;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- class WalletWithdrawRecordService
- {
- /**
- * 审核提现申请
- *
- * @param int $id 提现记录ID
- * @param int $status 审核状态(2:通过 3:拒绝)
- * @param string|null $remark 审核备注
- */
- public function audit(int $id, int $status, ?string $remark = null): void
- {
- DB::transaction(function () use ($id, $status, $remark) {
- // 获取提现记录
- $record = WalletWithdrawRecord::lockForUpdate()->findOrFail($id);
- // 验证记录状态
- abort_if($record->audit_state !== WithdrawAuditStatus::PENDING->value, 400, '提现申请状态异常');
- // 获取用户钱包
- $wallet = $record->wallet;
- abort_if(!$wallet, 404, '钱包信息不存在');
- // 验证冻结金额
- abort_if($wallet->frozen_amount < $record->amount, 400, '钱包冻结金额异常');
- if ($status === WithdrawAuditStatus::APPROVED->value) {
- // 审核通过,发起自动打款
- $this->processApproved($record, $remark);
- } else {
- // 审核拒绝,解冻余额
- $this->processRejected($record, $remark);
- }
- // 记录审核信息
- $record->auditor = auth()->user()->name;
- $record->audit_time = now();
- $record->audit_remark = $remark;
- $record->audit_state = $status;
- $record->save();
- // 记录日志
- Log::info('提现申请审核完成', [
- 'withdraw_id' => $record->id,
- 'external_no' => $record->external_no,
- 'status' => $status,
- 'remark' => $remark,
- 'auditor' => $record->auditor
- ]);
- });
- }
- /**
- * 处理审核通过
- */
- private function processApproved(WalletWithdrawRecord $record, ?string $remark): void
- {
- try {
- // 1. 更新提现记录状态为处理中
- $record->state = WithdrawStatus::PROCESSING->value;
- $record->save();
- // 获取钱包当前余额
- $wallet = $record->wallet;
- $currentBalance = $wallet->available_amount;
- $currentRechargeBalance = $wallet->recharge_amount;
- // 2. 创建转账记录
- $transRecord = WalletTransRecord::create([
- 'trans_no' => $this->generateTransNo(),
- 'wallet_id' => $record->wallet_id,
- 'owner_id' => $record->id,
- 'owner_type' => 'withdraw', // 业务类型:提现
- 'trans_type' => 2, // 交易类型:支出
- 'amount' => $record->amount,
- 'before_balance' => $currentBalance,
- 'after_balance' => $currentBalance - $record->amount,
- 'before_recharge_balance' => $currentRechargeBalance,
- 'after_recharge_balance' => $currentRechargeBalance,
- 'trans_time' => now(),
- 'remark' => '提现打款',
- 'state' => TransactionStatus::PROCESSING->value,
- 'province' => $record->area_code ? substr($record->area_code, 0, 2) . '0000' : null,
- 'city' => $record->area_code ? substr($record->area_code, 0, 4) . '00' : null,
- 'district' => $record->area_code
- ]);
- // 3. 调用支付服务发起转账
- // TODO: 对接实际的支付服务
- $paymentResult = $this->processPayment($record);
- if ($paymentResult['success']) {
- // 4. 打款成功
- // 4.1 更新提现记录状态
- $record->state = WithdrawStatus::SUCCESS->value;
- $record->withdraw_time = now();
- $record->trans_no = $paymentResult['trade_no'];
- $record->remark = '打款成功';
- $record->save();
- // 4.2 更新转账记录状态
- $transRecord->state = TransactionStatus::SUCCESS->value;
- $transRecord->trans_no = $paymentResult['trade_no'];
- $transRecord->save();
- // 4.3 扣除钱包冻结金额
- $record->wallet->decrement('frozen_amount', $record->amount);
- } else {
- // 5. 打款失败
- throw new \Exception($paymentResult['message'] ?? '打款失败');
- }
- } catch (\Exception $e) {
- // 6. 处理异常
- Log::error('提现打款失败', [
- 'withdraw_id' => $record->id,
- 'error' => $e->getMessage()
- ]);
- // 6.1 更新提现记录状态
- $record->state = WithdrawStatus::FAILED->value;
- $record->remark = $e->getMessage();
- $record->save();
- // 6.2 更新转账记录状态
- if (isset($transRecord)) {
- $transRecord->state = TransactionStatus::FAILED->value;
- $transRecord->save();
- }
- // 6.3 解冻余额
- $this->unfreezeBalance($record);
- throw $e;
- }
- }
- /**
- * 处理审核拒绝
- */
- private function processRejected(WalletWithdrawRecord $record, ?string $remark): void
- {
- // 1. 更新提现记录状态
- $record->state = WithdrawStatus::FAILED->value;
- $record->save();
- // 2. 解冻余额
- $this->unfreezeBalance($record);
- // 3. 记录日志
- Log::info('提现申请已拒绝', [
- 'withdraw_id' => $record->id,
- 'external_no' => $record->external_no,
- 'amount' => $record->amount,
- 'remark' => $remark
- ]);
- }
- /**
- * 解冻余额
- */
- private function unfreezeBalance(WalletWithdrawRecord $record): void
- {
- $wallet = $record->wallet;
- // 获取当前余额
- $currentBalance = $wallet->available_amount;
- $currentRechargeBalance = $wallet->recharge_amount;
- // 从冻结金额中减少
- $wallet->decrement('frozen_amount', $record->amount);
- // 增加可用余额
- $wallet->increment('available_amount', $record->amount);
- // 记录解冻操作
- WalletTransRecord::create([
- 'trans_no' => $this->generateTransNo(),
- 'wallet_id' => $wallet->id,
- 'owner_id' => $record->id,
- 'owner_type' => 'withdraw',
- 'trans_type' => 1, // 交易类型:收入
- 'amount' => $record->amount,
- 'before_balance' => $currentBalance,
- 'after_balance' => $currentBalance + $record->amount,
- 'before_recharge_balance' => $currentRechargeBalance,
- 'after_recharge_balance' => $currentRechargeBalance,
- 'trans_time' => now(),
- 'remark' => '提现拒绝解冻',
- 'state' => TransactionStatus::SUCCESS->value
- ]);
- }
- /**
- * 生成交易流水号
- */
- private function generateTransNo(): string
- {
- return 'T' . date('YmdHis') . str_pad(random_int(1, 9999), 4, '0', STR_PAD_LEFT);
- }
- /**
- * 处理实际打款
- * TODO: 对接实际支付服务
- */
- private function processPayment(WalletWithdrawRecord $record): array
- {
- // 模拟打款成功
- return [
- 'success' => true,
- 'trade_no' => 'PAY' . time() . random_int(1000, 9999),
- 'message' => '打款成功'
- ];
- }
- }
|