Browse Source

Merge branch 'master' of ssh://gogs.yinbin.ink:30004/didong/owl-admin

Yin Bin 4 months ago
parent
commit
d49fd34bfe

+ 6 - 6
app/Http/Controllers/Client/OrderController.php

@@ -46,10 +46,10 @@ class OrderController extends Controller
      *
      * @bodyParam project_id int required 项目ID Example: 1
      * @bodyParam address_id int required 地址ID Example: 1
-     * @bodyParam coach_id int required 技师ID Example: 1
-     * @bodyParam use_balance int 使用余额 Example: 0
+     * @bodyParam coach_id int required 技师ID Example: 6
+     * @bodyParam use_balance boolean 使用余额 Example: false
      * @bodyParam service_time datetime required 服务时间 Example: 2024-01-01 10:00:00
-     * @bodyParam order_id int 订单ID Example:
+     * @bodyParam order_id int 订单ID Example: null
      *
      * @response {
      *   "status": "success",
@@ -68,7 +68,7 @@ class OrderController extends Controller
      *
      * @description 结束订单
      *
-     * @bodyParam order_id int required 订单ID Example: 123
+     * @bodyParam order_id int required 订单ID Example: 1
      *
      * @response {
      *   "status": "success",
@@ -143,7 +143,7 @@ class OrderController extends Controller
      */
     public function list()
     {
-        return $this->service->getOrderList();
+        return $this->service->getOrderList(Auth::user()->id);
     }
 
     /**
@@ -163,7 +163,7 @@ class OrderController extends Controller
      */
     public function detail($id)
     {
-        return $this->service->getOrderDetail($id);
+        return $this->service->getOrderDetail(Auth::user()->id, $id);
     }
 
     /**

+ 25 - 19
app/Models/CoachUser.php

@@ -10,24 +10,25 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class CoachUser extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'coach_users';
+    protected $table = 'coach_users';
 
     protected $guarded = [];
 
     protected static function booted()
-	{
-		static::created(function ($user) {
-			$user->wallet()->create([
-				'owner_type' => CoachUser::class,
-				'owner_id' => $user->id
-			]);
-		});
-	}
+    {
+        static::created(function ($user) {
+            $user->wallet()->create([
+                'owner_type' => CoachUser::class,
+                'owner_id' => $user->id,
+            ]);
+        });
+    }
 
     /**
      * @Author FelixYin
+     *
      * @description 技师所属会员
      */
     public function member()
@@ -37,6 +38,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联信息
      */
     public function info()
@@ -46,6 +48,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联资质信息
      */
     public function qual()
@@ -55,6 +58,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联评分
      */
     public function score()
@@ -64,6 +68,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联定位
      */
     public function locations()
@@ -73,15 +78,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
-     * @description 技师关联订单
-     */
-    public function orders()
-    {
-        return $this->hasMany('App\Models\OrderInfo', 'coach_id', 'id');
-    }
-
-    /**
-     * @Author FelixYin
+     *
      * @description 技师关联抢单记录
      */
     public function grabRecords()
@@ -91,6 +88,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联评论
      */
     public function comments()
@@ -100,6 +98,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联钱包
      */
     public function wallet()
@@ -109,6 +108,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师所属店铺
      */
     public function shop()
@@ -118,6 +118,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联店铺开通服务
      */
     public function shopOpenService()
@@ -127,6 +128,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联实名信息
      */
     public function real()
@@ -136,6 +138,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师开通项目
      */
     public function projects()
@@ -145,6 +148,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 基本信息认证记录
      */
     public function infoRecords()
@@ -154,6 +158,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联资质记录
      */
     public function qualRecords()
@@ -163,6 +168,7 @@ class CoachUser extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 技师关联实名认证记录
      */
     public function realAuthRecords()

+ 8 - 0
app/Models/MemberUser.php

@@ -26,4 +26,12 @@ class MemberUser extends Model
     {
         return $this->hasMany(MemberAddress::class, 'user_id', 'id');
     }
+
+    /**
+     * 获取用户的所有订单
+     */
+    public function orders(): HasMany
+    {
+        return $this->hasMany(Order::class, 'user_id', 'id');
+    }
 }

+ 7 - 3
app/Models/WalletRefundRecord.php

@@ -10,12 +10,15 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class WalletRefundRecord extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'wallet_refund_records';
+    protected $table = 'wallet_refund_records';
+
+    protected $guarded = [];
 
     /**
      * @Author FelixYin
+     *
      * @description 退款记录所属钱包
      */
     public function wallet()
@@ -25,10 +28,11 @@ class WalletRefundRecord extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 退款记录所属交易
      */
     public function trans()
     {
         return $this->belongsTo('App\Models\WalletTransRecord', 'trans_record_id');
     }
-}
+}

+ 9 - 3
app/Models/WalletTransRecord.php

@@ -10,12 +10,15 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class WalletTransRecord extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'wallet_trans_records';
+    protected $table = 'wallet_trans_records';
+
+    protected $guarded = [];
 
     /**
      * @Author FelixYin
+     *
      * @description 交易记录所属钱包
      */
     public function wallet()
@@ -25,6 +28,7 @@ class WalletTransRecord extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 钱包交易关联提现记录
      */
     public function withdraw()
@@ -34,6 +38,7 @@ class WalletTransRecord extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 交易关联支付记录
      */
     public function paymentRecords()
@@ -43,10 +48,11 @@ class WalletTransRecord extends Model
 
     /**
      * @Author FelixYin
+     *
      * @description 交易关联退款记录
      */
     public function refundRecords()
     {
         return $this->hasMany('App\Models\WalletRefundRecord', 'trans_record_id', 'id');
     }
-}
+}

+ 222 - 81
app/Services/Client/OrderService.php

@@ -15,7 +15,6 @@ use App\Models\OrderRecord;
 use App\Models\Project;
 use App\Models\SysConfig;
 use App\Models\User;
-use App\Models\Wallet;
 use App\Models\WalletRefundRecord;
 use Exception;
 use Illuminate\Support\Facades\Auth;
@@ -190,6 +189,7 @@ class OrderService
                     $order->state = 'wait_receive';
                     $order->save();
 
+                    // 创建订单支付记录
                     OrderRecord::create([
                         'order_id' => $order->id,
                         'object_id' => $userId,
@@ -198,6 +198,12 @@ class OrderService
                         'remark' => '余额支付',
                     ]);
 
+                    // 扣除用户钱包总余额
+                    $user->wallet->decrement('total_balance', $order->balance_amount);
+                    // 扣除用户钱包可用余额
+                    $user->wallet->decrement('available_balance', $order->balance_amount);
+                    $user->wallet->save();
+
                     // 创建技师排班
                     // CoachSchedule::create([
                     //     'coach_id' => $data['coach_id'],
@@ -224,108 +230,248 @@ class OrderService
     }
 
     /**
-     * 结束订单
+     * 取消订单
      */
-    public function finishOrder($userId, $orderId)
+    public function cancelOrder($userId, $orderId)
     {
         return DB::transaction(function () use ($userId, $orderId) {
-            $order = Order::where('user_id', $userId)
-                ->where('id', $orderId)
-                ->first();
+            try {
+                $user = MemberUser::where('id', $userId)->firstOrFail();
+                $order = $user->orders()->find($orderId);
 
-            if (! $order) {
-                throw new Exception('订单不存在');
+                if (! $order) {
+                    throw new Exception('订单不存在');
+                }
+
+                // 判断订单状态
+                if ($order->state == 'wait_receive') { // 已接单
+                    // 扣除20%费用
+                    $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.2;
+                    $this->handleRefund($user, $order, $deductAmount, false);
+                } elseif ($order->state == 'on_the_way') { // 已出发
+                    // 扣除50%费用并扣除路费
+                    $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.5;
+                    $this->handleRefund($user, $order, $deductAmount, true);
+                } elseif ($order->state == 'wait_pay') {
+                    // 待支付状态直接取消,无需退款
+                } else {
+                    throw new Exception('当前订单状态不允许取消');
+                }
+
+                // 添加订单取消记录
+                OrderRecord::create([
+                    'order_id' => $orderId,
+                    'object_id' => $userId,
+                    'object_type' => MemberUser::class,
+                    'state' => 'cancel',
+                    'remark' => '用户取消订单',
+                ]);
+
+                // 修改订单状态
+                $order->state = 'cancel';
+                $order->save();
+
+                return ['message' => '订单已取消'];
+            } catch (Exception $e) {
+                Log::error('取消订单失败:', [
+                    'message' => $e->getMessage(),
+                    'user_id' => $userId,
+                    'order_id' => $orderId,
+                ]);
+                throw $e;
             }
+        });
+    }
 
-            // 添加订单结束记录
-            OrderRecord::create([
-                'order_id' => $orderId,
-                'user_id' => $userId,
-                'state' => 'finish',
-                'remark' => '服务完成',
+    /**
+     * 处理退款
+     */
+    private function handleRefund($user, $order, $deductAmount, $deductTrafficFee)
+    {
+        // 计算实际退款金额
+        $refundAmount = $order->payment_amount + $order->balance_amount;
+        if ($deductTrafficFee) {
+            $refundAmount -= $order->traffic_amount;
+            // 记录技师路费收入
+            // ...
+        }
+        $refundAmount -= $deductAmount;
+
+        // 优先从余额支付金额中扣除
+        $balanceRefund = min($order->balance_amount, $refundAmount);
+        if ($balanceRefund > 0) {
+
+            // 添加钱包退款记录
+            $refundRecord = $user->wallet->refundRecords()->create([
+                'refund_method' => 'balance',
+                'total_refund_amount' => $order->payment_amount + $order->balance_amount,
+                'actual_refund_amount' => '0.00',
+                'wallet_balance_refund_amount' => $balanceRefund,
+                'recharge_balance_refund_amount' => '0.00',
+                'remark' => '订单取消退还余额',
+                'order_id' => $order->id,
             ]);
 
-            // 修改订单状态
-            $order->state = 'finished';
-            $order->save();
+            // 添加钱包交易记录
+            $user->wallet->transRecords()->create([
+                'amount' => $balanceRefund,
+                'owner_type' => $refundRecord::class,
+                'owner_id' => $refundRecord->id,
+                'remark' => '订单取消退还余额',
+                'trans_type' => 'income',
+                'storage_type' => 'balance',
+                'amount' => $balanceRefund,
+                'before_balance' => $user->wallet->total_balance,
+                'after_balance' => $user->wallet->total_balance + $balanceRefund,
+                'before_recharge_balance' => '0.00',
+                'after_recharge_balance' => '0.00',
+                'trans_time' => now(),
+                'state' => 'success',
+            ]);
 
-            return ['message' => '订单已完成'];
-        });
+            $user->wallet->increment('total_balance', $balanceRefund);
+            $user->wallet->increment('available_balance', $balanceRefund);
+            $user->wallet->save();
+        }
+
+        // 剩余退款金额从支付金额中退还
+        $paymentRefund = $refundAmount - $balanceRefund;
+        if ($paymentRefund > 0) {
+
+            // 添加钱包退款记录
+            $refundRecord = $user->wallet->refundRecords()->create([
+                'refund_method' => 'balance',
+                'total_refund_amount' => $order->payment_amount + $order->balance_amount,
+                'actual_refund_amount' => '0.00',
+                'wallet_balance_refund_amount' => $balanceRefund,
+                'recharge_balance_refund_amount' => '0.00',
+                'remark' => '订单取消退还余额',
+                'order_id' => $order->id,
+            ]);
+
+            // 添加钱包交易记录
+            $user->wallet->transRecords()->create([
+                'amount' => $balanceRefund,
+                'owner_type' => $refundRecord::class,
+                'owner_id' => $refundRecord->id,
+                'remark' => '订单取消退还余额',
+                'trans_type' => 'income',
+                'storage_type' => 'balance',
+                'amount' => $balanceRefund,
+                'before_balance' => $user->wallet->total_balance,
+                'after_balance' => $user->wallet->total_balance + $balanceRefund,
+                'before_recharge_balance' => '0.00',
+                'after_recharge_balance' => '0.00',
+                'trans_time' => now(),
+                'state' => 'success',
+            ]);
+
+            $user->wallet->increment('total_balance', $paymentRefund);
+            $user->wallet->increment('available_balance', $paymentRefund);
+            $user->wallet->save();
+        }
+
+        // 记录平台收入
+        if ($deductAmount > 0) {
+            // TODO: 添加平台收入记录
+            // PlatformIncome::create([...]);
+        }
     }
 
     /**
-     * 确认技师离开
+     * 结束订单
      */
-    public function confirmLeave($userId, $orderId)
+    public function finishOrder($userId, $orderId)
     {
         return DB::transaction(function () use ($userId, $orderId) {
-            $order = Order::where('user_id', $userId)
-                ->where('id', $orderId)
-                ->first();
+            try {
+                // 1. 参数校验
+                $order = Order::where('user_id', $userId)
+                    ->where('id', $orderId)
+                    ->where('state', 'service_ing') // 订单状态必须是服务中
+                    ->firstOrFail();
 
-            if (! $order) {
-                throw new Exception('订单不存在');
-            }
+                if (! $order) {
+                    throw new Exception('订单不能结束');
+                }
 
-            // 添加订单撤离记录
-            OrderRecord::create([
-                'order_id' => $orderId,
-                'user_id' => $userId,
-                'state' => 'leave',
-                'remark' => '技师已离开',
-            ]);
+                // 2. 创建订单历史记录
+                OrderRecord::create([
+                    'order_id' => $orderId,
+                    'object_id' => $userId,
+                    'object_type' => MemberUser::class,
+                    'state' => 'finish',
+                    'remark' => '服务完成',
+                ]);
 
-            // 修改订单状态
-            $order->state = 'allow_leave';
-            $order->save();
+                // 3. 修改订单状态为服务结束
+                $order->state = 'service_end';
+                $order->save();
 
-            return ['message' => '已确认技师离开'];
+                return ['message' => '订单已完成'];
+            } catch (Exception $e) {
+                Log::error('结束订单失败:', [
+                    'message' => $e->getMessage(),
+                    'user_id' => $userId,
+                    'order_id' => $orderId,
+                ]);
+                throw $e;
+            }
         });
     }
 
     /**
-     * 取消订单
+     * 确认技师离开
      */
-    public function cancelOrder($userId, $orderId)
+    public function confirmLeave($userId, $orderId)
     {
         return DB::transaction(function () use ($userId, $orderId) {
-            $order = Order::where('user_id', $userId)
-                ->where('id', $orderId)
-                ->first();
+            try {
+                // 1. 参数校验
+                $order = Order::where('user_id', $userId)
+                    ->where('id', $orderId)
+                    ->where('state', 'service_end') // 订单状态必须是服务结束
+                    ->firstOrFail();
 
-            if (! $order) {
-                throw new Exception('订单不存在');
-            }
+                if (! $order) {
+                    throw new Exception('订单不能撤离');
+                }
 
-            // 添加订单取消记录
-            OrderRecord::create([
-                'order_id' => $orderId,
-                'user_id' => $userId,
-                'state' => 'cancel',
-                'remark' => '用户取消订单',
-            ]);
+                // 2. 添加订单撤离记录
+                OrderRecord::create([
+                    'order_id' => $orderId,
+                    'object_id' => $userId,
+                    'object_type' => MemberUser::class,
+                    'state' => 'leave',
+                    'remark' => '技师已离开',
+                ]);
 
-            // 修改订单状态
-            $order->state = 'cancelled';
-            $order->save();
+                // 3. 修改订单状态为撤离
+                $order->state = 'leave';
+                $order->save();
 
-            return ['message' => '订单已取消'];
+                return ['message' => '已确认技师离开'];
+            } catch (Exception $e) {
+                Log::error('确认技师离开失败:', [
+                    'message' => $e->getMessage(),
+                    'user_id' => $userId,
+                    'order_id' => $orderId,
+                ]);
+                throw $e;
+            }
         });
     }
 
     /**
      * 获取订单列表
      */
-    public function getOrderList()
+    public function getOrderList($user_id)
     {
-        $userId = Auth::id();
+        $user = MemberUser::find($user_id);
 
-        return Order::where('user_id', $userId)
+        return $user->orders()
             ->with([
-                'project:id,title,cover,price',
-                'coach:id,name,avatar',
-                'agent:id,company_name',
-                'address:id,address',
+                'coach.info:id,nickname,avatar,gender',
             ])
             ->orderBy('created_at', 'desc')
             ->paginate(10);
@@ -334,21 +480,16 @@ class OrderService
     /**
      * 获取订单详情
      */
-    public function getOrderDetail($orderId)
+    public function getOrderDetail($userId, $orderId)
     {
-        $userId = Auth::id();
+        $user = MemberUser::find($userId);
 
-        return Order::where('id', $orderId)
-            ->where('user_id', $userId)
-            ->with([
-                'project:id,title,cover,price,duration',
-                'coach:id,name,avatar,mobile',
-                'agent:id,company_name',
-                'address:id,address,latitude,longitude',
-                'records' => function ($query) {
-                    $query->orderBy('created_at', 'asc');
-                },
-            ])
+        return $user->orders()->with([
+            'coach.info:id,nickname,avatar,gender',
+            'records' => function ($query) {
+                $query->orderBy('created_at', 'asc');
+            },
+        ])
             ->firstOrFail();
     }
 
@@ -560,7 +701,7 @@ class OrderService
                 ->first();
 
             if (! $agentProject) {
-                throw new Exception('代理商项目不在');
+                throw new Exception('代理商项目不在');
             }
 
             $project->price = $agentProject->price;
@@ -587,12 +728,12 @@ class OrderService
         $payAmount = $totalAmount;
 
         if ($useBalance) {
-            $wallet = Wallet::where('user_id', $userId)->first();
-            if ($wallet && $wallet->balance >= $totalAmount) {
+            $wallet = $user->wallet;
+            if ($wallet && $wallet->available_balance >= $totalAmount) {
                 $balanceAmount = $totalAmount;
                 $payAmount = 0;
             } elseif ($wallet) {
-                $balanceAmount = $wallet->balance;
+                $balanceAmount = $wallet->available_balance;
                 $payAmount = $totalAmount - $balanceAmount;
             }
         }

+ 8 - 7
routes/api.php

@@ -77,20 +77,21 @@ Route::middleware('auth:sanctum')->group(function () {
         Route::put('/{id}/default', [UserAddressController::class, 'setDefault']);
     });
 
+    // 订单相关
     Route::prefix('orders')->group(function () {
         Route::post('initialize', [OrderController::class, 'initialize']);
         Route::post('create', [OrderController::class, 'create']);
+        Route::post('cancel', [OrderController::class, 'cancel']);
         Route::post('finish', [OrderController::class, 'finish']);
         Route::post('confirm-leave', [OrderController::class, 'confirmLeave']);
-        Route::post('cancel', [OrderController::class, 'cancel']);
         Route::get('list', [OrderController::class, 'list']);
         Route::get('detail/{id}', [OrderController::class, 'detail']);
-        Route::post('refund/{id}', [OrderController::class, 'refund']);
-        Route::post('get-agent-config', [OrderController::class, 'getAgentConfig']);
-        Route::post('get-coach-config', [OrderController::class, 'getCoachConfig']);
-        Route::post('calculate-delivery-fee', [OrderController::class, 'calculateDeliveryFee']);
-        Route::post('calculate-order-amount', [OrderController::class, 'calculateOrderAmount']);
-        Route::post('add-time/{orderId}', [OrderController::class, 'addTime']);
+        // Route::post('refund/{id}', [OrderController::class, 'refund']);
+        // Route::post('get-agent-config', [OrderController::class, 'getAgentConfig']);
+        // Route::post('get-coach-config', [OrderController::class, 'getCoachConfig']);
+        // Route::post('calculate-delivery-fee', [OrderController::class, 'calculateDeliveryFee']);
+        // Route::post('calculate-order-amount', [OrderController::class, 'calculateOrderAmount']);
+        // Route::post('add-time/{orderId}', [OrderController::class, 'addTime']);
     });
 
 });