소스 검색

feat: 添加微信退款回调处理功能

- 在PaymentController中新增refundNotify方法,处理微信退款回调通知。
- 在PaymentService中实现handleRefundNotify方法,处理退款记录的更新和订单状态的变更。
- 在OrderService中优化processCancelRefund方法,确保退款记录的创建和异常处理逻辑的准确性。
- 更新api路由,添加退款回调的路由支持,提升系统对微信退款的处理能力。
刘学玺 2 달 전
부모
커밋
0e299134c2
4개의 변경된 파일129개의 추가작업 그리고 32개의 파일을 삭제
  1. 16 0
      app/Http/Controllers/Client/PaymentController.php
  2. 33 32
      app/Services/Client/OrderService.php
  3. 78 0
      app/Services/Client/PaymentService.php
  4. 2 0
      routes/api.php

+ 16 - 0
app/Http/Controllers/Client/PaymentController.php

@@ -5,6 +5,13 @@ namespace App\Http\Controllers\Client;
 use App\Http\Controllers\Controller;
 use App\Services\Client\PaymentService;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\DB;
+use Carbon\Carbon;
+use App\Models\OrderRefundRecord;
+use App\Models\MemberUser;
+use App\Enums\OrderStatus;
+use App\Enums\OrderRecordStatus;
 
 /**
  *
@@ -77,4 +84,13 @@ class PaymentController extends Controller
     {
         return $this->service->handleNotify($request);
     }
+
+    /**
+     * 处理微信退款回调通知
+     */
+    public function refundNotify(Request $request)
+    {
+        $this->service->handleRefundNotify();
+        return $this->service->getRefundSuccessResponse();
+    }
 }

+ 33 - 32
app/Services/Client/OrderService.php

@@ -38,6 +38,7 @@ use App\Services\Client\Traits\ValidatesServiceTime;
 use App\Services\Client\Traits\CalculatesOrderAmounts;
 use App\Models\CoachStatistic;
 use App\Models\FinanceRecord;
+use App\Models\OrderRefundRecord;
 
 readonly class OrderService
 {
@@ -928,42 +929,40 @@ readonly class OrderService
      */
     private function processCancelRefund(Order $order, array $refundAmounts): void
     {
-        // 1. 处理余额退款(不记录财务流水,因为是内部账户变动)
-        if ($refundAmounts['balance_refund'] > 0) {
-            $this->processBalanceCancelRefund($order, $refundAmounts['balance_refund']);
-        }
+        try {
+            // 1. 处理余额退款
+            if ($refundAmounts['balance_refund'] > 0) {
+                $this->processBalanceCancelRefund($order, $refundAmounts['balance_refund']);
+            }
 
-        // 2. 处理支付退款(记录财务支出)
-        if ($refundAmounts['payment_refund'] > 0) {
-            $this->processPaymentCancelRefund($order, $refundAmounts['payment_refund']);
+            // 2. 处理支付退款
+            if ($refundAmounts['payment_refund'] > 0) {
+                $refundResult = $this->processPaymentCancelRefund($order, $refundAmounts['payment_refund']);
 
-            // 记录支付退款支出
-            FinanceRecord::create([
-                'owner_type' => 'platform',
+                // 3. 创建退款记录
+                OrderRefundRecord::create([
+                    'order_id' => $order->id,
+                    'refund_no' => $refundResult['refund_no'],
+                    'total_refund_amount' => $refundAmounts['total_refund'],
+                    'balance_refund_amount' => $refundAmounts['balance_refund'],
+                    'payment_refund_amount' => $refundAmounts['payment_refund'],
+                    'penalty_amount' => $refundAmounts['penalty'],
+                    'coach_fee' => $refundAmounts['coach_fee'],
+                    'platform_traffic_fee' => $refundAmounts['platform_traffic_fee'],
+                    'platform_penalty' => $refundAmounts['platform_penalty'],
+                    'transaction_id' => $order->transaction_id,
+                    'state' => 'processing',
+                    'remark' => '订单取消退款'
+                ]);
+            }
+        } catch (\Exception $e) {
+            Log::error('处理退款失败', [
                 'order_id' => $order->id,
-                'type' => 'expense',
-                'business_type' => 'refund',
-                'amount' => $refundAmounts['payment_refund'],
-                'payment_type' => 'wechat',
-                'user_id' => $order->user_id,
-                'remark' => '订单取消微信支付退款'
+                'refund_amounts' => $refundAmounts,
+                'error' => $e->getMessage()
             ]);
+            throw $e;
         }
-
-        // 3. 创建退款记录
-        $order->refundRecords()->create([
-            'total_refund_amount' => $refundAmounts['total_refund'],
-            'balance_refund_amount' => $refundAmounts['balance_refund'],
-            'payment_refund_amount' => $refundAmounts['payment_refund'],
-            'penalty_amount' => $refundAmounts['penalty_amount'],
-            'coach_fee' => $refundAmounts['coach_fee'],
-            'platform_traffic_fee' => $refundAmounts['platform_traffic_fee'],
-            'platform_penalty' => $refundAmounts['platform_penalty'],
-            'refund_no' => $this->generateRefundNo($order),
-            'state' => 'success',
-            'remark' => '订单取消退款',
-            'refund_time' => now()
-        ]);
     }
 
     /**
@@ -1001,7 +1000,7 @@ readonly class OrderService
     /**
      * 处理支付退款
      */
-    private function processPaymentCancelRefund(Order $order, float $amount): void
+    private function processPaymentCancelRefund(Order $order, float $amount): array
     {
         try {
             // 调用支付服务处理退款
@@ -1024,6 +1023,8 @@ readonly class OrderService
                 'state' => OrderRecordStatus::REFUNDING->value,
                 'remark' => '微信支付退款'
             ]);
+
+            return $result;
         } catch (\Exception $e) {
             Log::error('订单退款失败', [
                 'order_id' => $order->id,

+ 78 - 0
app/Services/Client/PaymentService.php

@@ -13,6 +13,8 @@ use App\Enums\OrderRecordStatus;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Auth;
+use App\Models\OrderRefundRecord;
+use Carbon\Carbon;
 
 class PaymentService
 {
@@ -372,4 +374,80 @@ class PaymentService
             ];
         }
     }
+
+    /**
+     * 处理微信退款回调通知
+     * @return array 解密后的回调数据
+     */
+    public function handleRefundNotify()
+    {
+        $app = $this->getApp();
+        $server = $app->getServer();
+
+        // 处理回调
+        $server->handleRefunded(function ($message) {
+            Log::info('微信退款回调原始数据', ['message' => $message]);
+            return true;
+        });
+
+        // 获取解密后的回调数据
+        $data = $server->getRequestMessage();
+
+        try {
+            Log::info('微信退款回调数据', ['data' => $data]);
+
+            // 根据商户退款单号查找退款记录
+            $refundRecord = OrderRefundRecord::where('refund_no', $data['out_refund_no'])->first();
+            if (!$refundRecord) {
+                Log::error('未找到对应的退款记录', ['refund_no' => $data['out_refund_no']]);
+                return true;
+            }
+
+            // 更新退款记录状态
+            DB::transaction(function () use ($refundRecord, $data) {
+                // 更新退款记录
+                $refundRecord->update([
+                    'state' => $data['refund_status'],
+                    'transaction_id' => $data['transaction_id'],
+                    'refund_time' => Carbon::parse($data['success_time'])
+                ]);
+
+                // 如果退款成功,更新订单状态为已退款
+                if ($data['refund_status'] === 'SUCCESS') {
+                    $order = $refundRecord->order;
+                    $order->update([
+                        'state' => OrderStatus::REFUNDED->value,
+                        'refund_time' => Carbon::parse($data['success_time'])
+                    ]);
+
+                    // 创建订单记录
+                    $order->records()->create([
+                        'object_id' => $order->user_id,
+                        'object_type' => MemberUser::class,
+                        'state' => OrderRecordStatus::REFUNDED->value,
+                        'remark' => '订单退款成功'
+                    ]);
+                }
+            });
+
+            return true;
+        } catch (\Exception $e) {
+            Log::error('处理退款回调异常', [
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+            return true; // 即使处理失败也要返回true,避免微信重复通知
+        }
+    }
+
+    /**
+     * 获取退款成功响应
+     */
+    public function getRefundSuccessResponse()
+    {
+        return [
+            'code' => 'SUCCESS',
+            'message' => 'OK'
+        ];
+    }
 }

+ 2 - 0
routes/api.php

@@ -48,6 +48,8 @@ Route::prefix('client')->group(function () {
             ->name('wechat.pay.config');
         // 微信支付回调
         Route::any('pay/notify', [App\Http\Controllers\Client\PaymentController::class, 'notify']);
+        // 微信退款回调
+        Route::post('refund/notify', [App\Http\Controllers\Client\PaymentController::class, 'refundNotify']);
     });
 
     // 需要认证的路由组