Browse Source

feat: 移除交易状态中的取消状态并更新相关逻辑

在TransactionStatus枚举中移除了取消状态,并相应更新了状态标签和相关方法,确保系统在处理交易状态时更加简洁和一致。同时,在路由文件中新增了提现记录管理的相关路由,增强了钱包功能的管理能力。此更改提升了代码的可读性和系统的功能性。
刘学玺 2 months ago
parent
commit
354e5b669a

+ 1 - 9
app/Enums/TransactionStatus.php

@@ -22,11 +22,6 @@ enum TransactionStatus: int
      */
     case FAILED = 3;
 
-    /**
-     * 交易状态:取消
-     */
-    case CANCELLED = 4;
-
     /**
      * 获取状态的显示文本
      *
@@ -35,10 +30,9 @@ enum TransactionStatus: int
     public function label(): string
     {
         return match ($this) {
-            self::PROCESSING => '进行中',
+            self::PROCESSING => '处理中',
             self::SUCCESS => '成功',
             self::FAILED => '失败',
-            self::CANCELLED => '取消',
         };
     }
 
@@ -75,7 +69,6 @@ enum TransactionStatus: int
             self::PROCESSING->value => self::PROCESSING,
             self::SUCCESS->value => self::SUCCESS,
             self::FAILED->value => self::FAILED,
-            self::CANCELLED->value => self::CANCELLED,
             default => null
         };
     }
@@ -101,7 +94,6 @@ enum TransactionStatus: int
             self::PROCESSING->value => self::PROCESSING->label(),
             self::SUCCESS->value => self::SUCCESS->label(),
             self::FAILED->value => self::FAILED->label(),
-            self::CANCELLED->value => self::CANCELLED->label(),
         ];
     }
 }

+ 62 - 0
app/Http/Controllers/Admin/WalletWithdrawRecordController.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Http\Controllers\Controller;
+use App\Services\Admin\WalletWithdrawRecordService;
+use App\Http\Requests\Admin\Wallet\WithdrawAuditRequest;
+use App\Models\WalletWithdrawRecord;
+use App\Enums\WithdrawAuditStatus;
+
+/**
+ * @group 后台
+ *
+ * 钱包提现记录
+ */
+class WalletWithdrawRecordController extends Controller
+{
+    protected WalletWithdrawRecordService $service;
+
+    public function __construct(WalletWithdrawRecordService $service)
+    {
+        $this->service = $service;
+    }
+
+    /**
+     * [钱包]审核提现申请
+     *
+     * @description 审核用户的提现申请,可以通过或拒绝
+     *
+     * @urlParam id required 提现记录ID Example: 1
+     * @bodyParam status int required 审核状态(2:通过 3:拒绝) Example: 2
+     * @bodyParam remark string optional 审核备注 Example: 审核通过
+     *
+     * @response 200 {
+     *   "code": 200,
+     *   "message": "审核操作成功",
+     *   "data": null
+     * }
+     * @response 400 {
+     *   "code": 400,
+     *   "message": "提现申请状态异常",
+     *   "data": null
+     * }
+     * @response 404 {
+     *   "code": 404,
+     *   "message": "提现记录不存在",
+     *   "data": null
+     * }
+     */
+    public function audit(WithdrawAuditRequest $request, int $id)
+    {
+        $validated = $request->validated();
+
+        $this->service->audit(
+            $id,
+            $validated['status'],
+            $validated['remark'] ?? null
+        );
+
+        return $this->success(null, '审核操作成功');
+    }
+}

+ 41 - 0
app/Http/Requests/Admin/Wallet/WithdrawAuditRequest.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Http\Requests\Admin\Wallet;
+
+use Illuminate\Foundation\Http\FormRequest;
+use App\Enums\WithdrawAuditStatus;
+
+class WithdrawAuditRequest extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules(): array
+    {
+        return [
+            'status' => ['required', 'integer', 'in:' . implode(',', [
+                WithdrawAuditStatus::APPROVED->value,
+                WithdrawAuditStatus::REJECTED->value,
+            ])],
+            'remark' => ['nullable', 'string', 'max:255'],
+        ];
+    }
+
+    /**
+     * Get custom messages for validator errors.
+     *
+     * @return array
+     */
+    public function messages(): array
+    {
+        return [
+            'status.required' => '请选择审核状态',
+            'status.integer' => '审核状态格式错误',
+            'status.in' => '审核状态无效',
+            'remark.string' => '审核备注必须是字符串',
+            'remark.max' => '审核备注不能超过255个字符',
+        ];
+    }
+}

+ 226 - 0
app/Services/Admin/WalletWithdrawRecordService.php

@@ -0,0 +1,226 @@
+<?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' => '打款成功'
+        ];
+    }
+}

+ 14 - 0
routes/web.php

@@ -163,6 +163,13 @@ Route::group(
 
         // 修改技师资质认证信息
         Route::post('/technician/certification/update', [TechnicianController::class, 'updateCertification']);
+
+        // 提现记录管理
+        Route::group(['prefix' => 'wallet'], function () {
+            Route::group(['prefix' => 'withdraw'], function () {
+                Route::post('/{id}/audit', [\App\Http\Controllers\Admin\WalletWithdrawRecordController::class, 'audit'])->name('admin.wallet.withdraw.audit');
+            });
+        });
     }
 );
 
@@ -282,5 +289,12 @@ Route::group([
 
         // 修改技师资质认证信息
         Route::post('technician/certification/update', [TechnicianController::class, 'updateCertification']);
+
+        // 提现记录管理
+        Route::group(['prefix' => 'wallet'], function () {
+            Route::group(['prefix' => 'withdraw'], function () {
+                Route::post('/{id}/audit', [\App\Http\Controllers\Admin\WalletWithdrawRecordController::class, 'audit'])->name('admin.wallet.withdraw.audit');
+            });
+        });
     });
 });