Browse Source

fixed:优化订单业务逻辑

刘学玺 4 months ago
parent
commit
e3b8a2bb7f
3 changed files with 219 additions and 121 deletions
  1. 3 5
      app/Http/Controllers/Client/OrderController.php
  2. 215 115
      app/Services/Client/OrderService.php
  3. 1 1
      routes/api.php

+ 3 - 5
app/Http/Controllers/Client/OrderController.php

@@ -295,25 +295,23 @@ class OrderController extends Controller
     }
 
     /**
-     * 指定技师
-     *
      * 指定技师
      *
      * @authenticated
      *
-     * @urlParam order_id required 订单ID. Example: 123
-     *
      * @bodyParam coach_id int required 技师ID. Example: 1
+     * @bodyParam order_id int required 订单ID. Example: 1
      *
      * @response {
      *   "status": "success",
      *   "data": {}
      * }
      */
-    public function assignCoach(Request $request, $orderId)
+    public function assignCoach(Request $request)
     {
         $userId = Auth::user()->id;
         $coachId = $request->input('coach_id');
+        $orderId = $request->input('order_id');
 
         return $this->service->assignCoach($userId, $orderId, $coachId);
     }

+ 215 - 115
app/Services/Client/OrderService.php

@@ -13,6 +13,7 @@ use App\Models\OrderRecord;
 use App\Models\Project;
 use App\Models\SysConfig;
 use App\Models\User;
+use App\Models\WalletPaymentRecord;
 use App\Models\WalletRefundRecord;
 use Exception;
 use Illuminate\Support\Facades\Auth;
@@ -40,10 +41,10 @@ class OrderService
     {
         try {
             // 参数验证
-            abort_if(empty($data), 400, '订单初始化参数不能为空');
+            abort_if(empty($data['project_id']), 400, '项目ID不能为空');
+            abort_if(empty($data['coach_id']), 400, '技师ID不能为空');
 
-            DB::beginTransaction();
-            try {
+            return DB::transaction(function () use ($userId, $data) {
                 $user = MemberUser::find($userId);
                 abort_if(! $user || $user->state != 'enable', 400, '用户状态异常');
 
@@ -52,49 +53,39 @@ class OrderService
 
                 // 查询默认地址
                 $address = $user->address;
-
-                $areaCode = $address ? $address->area_code : $data['area_code'];
+                $areaCode = $address ? $address->area_code : ($data['area_code'] ?? null);
+                abort_if(empty($areaCode), 400, '区域编码不能为空');
 
                 // 查询技师数据
                 $coach = $this->validateCoach($data['coach_id']);
 
-                // 查询技师排班
-                // $schedule = CoachSchedule::where('coach_id', $coachId)
-                //     ->where('date', date('Y-m-d'))
-                //     ->first();
-
-                // // 查询用户优惠券
-                // $coupons = Coupon::where('user_id', $userId)
-                //     ->where('state', 'enable')
-                //     ->where('expire_time', '>', now())
-                //     ->get();
-
                 // 获取项目详情
                 $project = $this->projectService->getProjectDetail($data['project_id'], $areaCode);
+                abort_if(! $project, 400, '项目不存在');
 
                 // 计算订单金额
-                $amounts = $this->calculateOrderAmount($userId, $address?->id, $data['coach_id'], $data['project_id'], $project?->agent_id);
-
-                DB::commit();
+                $amounts = $this->calculateOrderAmount(
+                    $userId,
+                    $address?->id ?? 0,
+                    $data['coach_id'],
+                    $data['project_id'],
+                    $project->agent_id
+                );
 
                 return [
                     'wallet' => $wallet,
                     'coach' => $coach,
                     'project' => $project,
                     'address' => $address,
-                    // 'schedule' => $schedule,
                     'amounts' => $amounts,
-                    // 'coupons' => $coupons
                 ];
-            } catch (\Exception $e) {
-                DB::rollBack();
-                throw $e;
-            }
-        } catch (\Exception $e) {
+            });
+        } catch (Exception $e) {
             Log::error('订单初始化失败', [
                 'userId' => $userId,
                 'data' => $data,
                 'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString(),
             ]);
             throw $e;
         }
@@ -116,7 +107,7 @@ class OrderService
                     ->where('state', 'enable')
                     ->firstOrFail();
 
-                // 2. 创建订单
+                // 2. 订单类型判断
                 $orderType = isset($data['order_id']) ? 'add_time' : 'normal';
 
                 // 关键操作:验证必要参数
@@ -125,42 +116,42 @@ class OrderService
                 abort_if($orderType == 'normal' && empty($data['coach_id']), 400, '技师ID不能为空');
                 abort_if($orderType == 'normal' && empty($data['address_id']), 400, '地址ID不能为空');
 
+                // 3. 验证地址
+                $address = $user->addresses()
+                    ->where('id', $data['address_id'])
+                    ->firstOrFail();
+
+                // 4. 根据订单类型处理
                 if ($orderType == 'normal') {
-                    // 普通订单验证技师
                     $coach = $this->validateCoach($data['coach_id']);
                 } else {
-                    // 加钟订单验证
                     $originalOrder = $this->getOriginalOrder($user, $data['order_id']);
-
-                    // 关键操作:验证原订单技师状态
                     $coach = $this->validateCoach($originalOrder->coach_id);
-
-                    // 关键操作:验证原订单状态
                     abort_if(! in_array($originalOrder->state, ['service_ing', 'service_end']), 400, '原订单状态不允许加钟');
-
                     $data = $this->prepareAddTimeData($originalOrder, $data);
                 }
 
-                $address = $user->addresses()
-                    ->where('id', $data['address_id'])
-                    ->firstOrFail();
-
-                // 计算订单金额
-                $amounts = $this->calculateOrderAmount($userId, $address->id, $data['coach_id'], $data['project_id'], $project->agent_id, $data['use_balance'] ?? false);
-
-                // 关键操作:验证订单金额
+                // 5. 计算订单金额
+                $amounts = $this->calculateOrderAmount(
+                    $userId,
+                    $address->id,
+                    $data['coach_id'],
+                    $data['project_id'],
+                    $project->agent_id,
+                    $data['use_balance'] ?? false
+                );
+
+                // 6. 验证金额和余额
                 abort_if($amounts['total_amount'] <= 0, 400, '订单金额异常');
-
-                // 关键操作:验证余额支付
                 if ($amounts['payment_type'] == 'balance') {
                     $wallet = $user->wallet;
                     abort_if($wallet->available_balance < $amounts['balance_amount'], 400, '可用余额不足');
                 }
 
-                // 创建订单记录
-                $order = $this->createOrderRecord($userId, $data, $orderType, $address, $amounts);
+                // 7. 创建订单记录
+                $order = $this->createOrderRecord($userId, $data, $orderType, $address, (object) $amounts);
 
-                // 余额支付处理
+                // 8. 余额支付处理
                 if ($order->payment_type == 'balance') {
                     $this->handleBalancePayment($user, $order, $orderType);
                 }
@@ -175,6 +166,7 @@ class OrderService
                 'message' => $e->getMessage(),
                 'user_id' => $userId,
                 'data' => $data,
+                'trace' => $e->getTraceAsString(),
             ]);
             throw $e;
         }
@@ -285,13 +277,21 @@ class OrderService
             try {
                 // 1. 验证用户和订单
                 $order = $this->validateOrderForCancel($userId, $orderId);
+                abort_if($order->state == 'cancel', 400, '订单已取消');
 
                 // 2. 处理退款
-                $this->handleCancelRefund($order);
+                if (in_array($order->state, ['wait_receive', 'on_the_way'])) {
+                    $this->handleCancelRefund($order);
+                }
 
                 // 3. 完成订单取消
                 $this->completeCancel($order, $userId);
 
+                // 4. 通知技师
+                if ($order->coach_id) {
+                    // event(new OrderCancelledEvent($order));
+                }
+
                 return ['message' => '订单已取消'];
 
             } catch (Exception $e) {
@@ -472,9 +472,10 @@ class OrderService
             try {
                 // 1. 验证用户和订单
                 $order = $this->validateOrderForFinish($userId, $orderId);
+                abort_if($order->state == 'service_end', 400, '订单已完成');
 
                 // 2. 验证技师状态
-                $this->validateCoach($order->coach_id);
+                $coach = $this->validateCoach($order->coach_id);
 
                 // 3. 验证服务时长
                 $this->validateServiceDuration($order);
@@ -482,6 +483,9 @@ class OrderService
                 // 4. 完成订单
                 $this->completeOrder($order, $userId);
 
+                // 5. 通知技师
+                // event(new OrderFinishedEvent($order));
+
                 return ['message' => '订单已完成'];
 
             } catch (Exception $e) {
@@ -623,12 +627,14 @@ class OrderService
     {
         $user = MemberUser::find($userId);
 
-        return $user->orders()->with([
-            'coach.info:id,nickname,avatar,gender',
-            'records' => function ($query) {
-                $query->orderBy('created_at', 'asc');
-            },
-        ])
+        return $user->orders()
+            ->where('id', $orderId) // 需要添加订单ID条件
+            ->with([
+                'coach.info:id,nickname,avatar,gender',
+                'records' => function ($query) {
+                    $query->orderBy('created_at', 'asc');
+                },
+            ])
             ->firstOrFail();
     }
 
@@ -985,76 +991,170 @@ class OrderService
     {
         return DB::transaction(function () use ($userId, $orderId, $coachId) {
             try {
-                // 参数校验
-                $user = MemberUser::where('id', $userId)
-                    ->where('state', 'enable')
-                    ->firstOrFail();
-
-                $order = Order::where('id', $orderId)
-                    ->where('user_id', $userId)
-                    ->whereIn('state', [0, 1, 6])
-                    ->firstOrFail();
+                // 1. 验证参数
+                $order = $this->validateAssignOrder($userId, $orderId);
 
+                // 2. 验证技师
                 $coach = $this->validateCoach($coachId);
 
-                // 修改订单
-                $order->coach_id = $coachId;
-                if ($order->state == 'created') {
-                    $amounts = $this->calculateOrderAmount(
-                        $userId,
-                        $order->address_id,
-                        $coachId,
-                        $order->project_id,
-                        $order->agent_id,
-                        $order->payment_type === 'balance'
-                    );
-
-                    $order->total_amount = $amounts->total_amount;
-                    $order->balance_amount = $amounts->balance_amount;
-                    $order->pay_amount = $amounts->pay_amount;
-                    $order->coupon_amount = $amounts->coupon_amount;
-                    $order->project_amount = $amounts->project_amount;
-                    $order->delivery_fee = $amounts->delivery_fee;
-
-                    if ($order->payment_type === 'balance') {
-                        $order->state = 'paid';
-                    }
-                }
-                if ($order->state == 'paid') {
-                    $order->state = 'assigned';
-                }
-                $order->save();
+                // 3. 更新订单信息
+                $this->updateOrderForAssign($order, $coachId);
 
-                // 创建订单历史
-                OrderRecord::create([
-                    'order_id' => $order->id,
-                    'type' => 'assigned',
-                    'user_id' => $userId,
-                    'coach_id' => $coachId,
-                ]);
-
-                OrderRecord::create([
-                    'order_id' => $order->id,
-                    'type' => 'accepted',
-                    'user_id' => $userId,
-                    'coach_id' => $coachId,
-                    'remark' => '抢单成功',
-                ]);
+                // 4. 创建订单记录(指派)
+                $this->createAssignRecord($order, $userId);
 
-                // 更新抢单池
-                OrderGrabRecord::where('order_id', $orderId)
-                    ->update(['state' => 'success', 'coach_id' => $coachId]);
+                // 5. 处理支付
+                if ($order->payment_type == 'balance') {
+                    $this->handleBalancePaymentForAssign($order, $userId, $coachId);
+                }
 
                 return true;
+
             } catch (Exception $e) {
-                Log::error('分配技师失败:', [
-                    'message' => $e->getMessage(),
-                    'user_id' => $userId,
-                    'order_id' => $orderId,
-                    'coach_id' => $coachId,
-                ]);
+                $this->logAssignCoachError($e, $userId, $orderId, $coachId);
                 throw $e;
             }
         });
     }
+
+    /**
+     * 创建指派记录
+     */
+    private function createAssignRecord(Order $order, int $userId): void
+    {
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $userId,
+            'object_type' => MemberUser::class,
+            'state' => 'assigned',
+            'remark' => '指定技师',
+        ]);
+    }
+
+    /**
+     * 处理指派订单的余额支付
+     */
+    private function handleBalancePaymentForAssign(Order $order, int $userId, int $coachId): void
+    {
+        // 验证余额
+        $user = MemberUser::find($userId);
+        $wallet = $user->wallet;
+        abort_if($wallet->available_balance < $order->balance_amount, 400, '可用余额不足');
+
+        // 扣除余额
+        $wallet->decrement('total_balance', $order->balance_amount);
+        $wallet->decrement('available_balance', $order->balance_amount);
+
+        // 更新订单状态
+        $order->update(['state' => 'wait_service']);
+
+        // 创建钱包支付记录
+        WalletPaymentRecord::create([
+            'order_id' => $order->id,
+            'wallet_id' => $wallet->id,
+            'payment_no' => 'balance_'.$order->id,
+            'payment_method' => 'balance',
+            'total_amount' => $order->balance_amount,
+            'actual_amount' => 0,
+            'used_wallet_balance' => $order->balance_amount,
+            'used_recharge_balance' => 0,
+            'state' => 'success',
+        ]);
+
+        // 创建支付成功记录
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $userId,
+            'object_type' => MemberUser::class,
+            'state' => 'pay',
+            'remark' => '余额支付成功',
+        ]);
+
+        // 创建接单记录
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_type' => CoachUser::class,
+            'object_id' => $coachId,
+            'state' => 'accepted',
+            'remark' => '抢单成功',
+        ]);
+
+        // 更新抢单记录
+        $this->updateGrabRecords($order->id, $coachId);
+    }
+
+    /**
+     * 验证指定技师的订单条件
+     */
+    private function validateAssignOrder(int $userId, int $orderId): Order
+    {
+        // 验证用户状态
+        $user = MemberUser::where('id', $userId)
+            ->where('state', 'enable')
+            ->firstOrFail();
+
+        // 验证订单状态
+        $order = Order::where('user_id', $userId)
+            ->where('id', $orderId)
+            ->whereIn('state', ['wait_pay', 'wait_receive'])
+            ->lockForUpdate()
+            ->firstOrFail();
+
+        return $order;
+    }
+
+    /**
+     * 更新订单信息
+     */
+    private function updateOrderForAssign(Order $order, int $coachId): void
+    {
+        // 修改订单技师
+        $order->coach_id = $coachId;
+
+        // 待支付订单需要重新计算金额
+        if ($order->state == 'wait_pay') {
+            $amounts = $this->calculateOrderAmount(
+                $order->user_id,
+                $order->address_id,
+                $coachId,
+                $order->project_id,
+                $order->agent_id,
+                $order->payment_type === 'balance'
+            );
+
+            // 更新订单金额
+            $order->total_amount = $amounts['total_amount'];
+            $order->balance_amount = $amounts['balance_amount'];
+            $order->pay_amount = $amounts['pay_amount'];
+            $order->discount_amount = $amounts['coupon_amount'];
+            $order->project_amount = $amounts['project_amount'];
+            $order->traffic_amount = $amounts['delivery_fee'];
+        }
+        $order->save();
+    }
+
+    /**
+     * 更新抢单记录
+     */
+    private function updateGrabRecords(int $orderId, int $coachId): void
+    {
+        OrderGrabRecord::where('order_id', $orderId)
+            ->update([
+                'state' => 'success',
+                'coach_id' => $coachId,
+            ]);
+    }
+
+    /**
+     * 记录指派技师错误日志
+     */
+    private function logAssignCoachError(Exception $e, int $userId, int $orderId, int $coachId): void
+    {
+        Log::error('分配技师失败:', [
+            'message' => $e->getMessage(),
+            'user_id' => $userId,
+            'order_id' => $orderId,
+            'coach_id' => $coachId,
+        ]);
+    }
 }

+ 1 - 1
routes/api.php

@@ -102,7 +102,7 @@ Route::middleware('auth:sanctum')->group(function () {
         Route::get('/orders', [OrderController::class, 'list']);
         Route::get('/orders/{orderId}', [OrderController::class, 'detail']);
         Route::post('/orders/{orderId}/refund', [OrderController::class, 'refund']);
-        Route::post('/orders/{orderId}/assign-coach', [OrderController::class, 'assignCoach']);
+        Route::post('/orders/assign-coach', [OrderController::class, 'assignCoach']);
     });
 
 });