agentService = $agentService; $this->projectService = $projectService; } /** * 订单初始化 */ public function initialize($userId, $data) { $user = MemberUser::find($userId); if (! $user) { throw new Exception('用户不存在'); } if ($user->state != 'enable') { throw new Exception('用户状态异常'); } // 查询用户钱包 $wallet = $user->wallet; // 查询默认地址 $address = $user->address; $areaCode = $address ? $address->area_code : $data['area_code']; // 查询技师数据 $coach = CoachUser::where('state', 'enable') ->whereHas('info', function ($query) { $query->where('state', 'approved'); }) ->whereHas('real', function ($query) { $query->where('state', 'approved'); }) ->whereHas('qual', function ($query) { $query->where('state', 'approved'); }) ->with(['info:id,nickname,avatar,gender']) ->find($data['coach_id']); if (! $coach) { throw new Exception('技师不存在'); } // 查询技师排班 // $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); // 计算订单金额 $amounts = $this->calculateOrderAmount($userId, $address?->id, $data['coach_id'], $data['project_id'], $project?->agent_id); return [ 'wallet' => $wallet, 'coach' => $coach, 'project' => $project, 'address' => $address, // 'schedule' => $schedule, 'amounts' => $amounts, // 'coupons' => $coupons ]; } /** * 创建订单 */ public function createOrder($userId, array $data) { try { return DB::transaction(function () use ($userId, $data) { // 1. 参数校验 $user = MemberUser::where('id', $userId) ->where('state', 'enable') ->firstOrFail(); $project = Project::where('id', $data['project_id']) ->where('state', 'enable') ->firstOrFail(); // 2. 创建订单 $orderType = isset($data['order_id']) ? 'add_time' : 'normal'; if ($orderType == 'normal') { // 查询技师及其认证状态 $coach = CoachUser::where('id', $data['coach_id']) ->where('state', 'enable') ->whereHas('info', function ($query) { $query->where('state', 'approved'); }) ->whereHas('qual', function ($query) { $query->where('state', 'approved'); }) ->whereHas('real', function ($query) { $query->where('state', 'approved'); }) ->firstOrFail(); } else { // 1. 检查原订单 $originalOrder = $user->orders->where('id', $data['order_id']) ->whereIn('state', ['service_ing', 'service_end']) // 只有服务中和服务结束的订单可以加钟 ->firstOrFail(); // 2. 设置加钟订单的服务时间 if ($originalOrder->state == 'service_ing') { // 服务中订单,加钟开始时间为原订单结束时间 $startTime = now(); // Carbon::parse($originalOrder->service_time)->addMinutes($originalOrder->project->duration); } else { // 服务结束订单,加钟开始时间为当前时间 $startTime = now(); } // 3. 构建加钟订单数据 $data['order_id'] = $data['order_id']; // 关联原订单ID $data['address_id'] = $originalOrder->address_id; $data['service_time'] = $startTime; $data['coach_id'] = $originalOrder->coach_id; } $address = $user->addresses() ->where('id', $data['address_id']) ->firstOrFail(); // 计算订单金额 $amounts = $this->calculateOrderAmount( $userId, $data['address_id'], $data['coach_id'], $data['project_id'], $project->agent_id, $data['use_balance'] ?? false ); $order = new Order; $order->user_id = $userId; $order->project_id = $data['project_id']; $order->coach_id = $data['coach_id']; $order->type = $orderType; $order->state = 'wait_pay'; $order->source = 'platform'; $order->total_amount = $amounts['total_amount']; $order->balance_amount = $amounts['balance_amount']; $order->pay_amount = $amounts['pay_amount']; $order->project_amount = $amounts['project_amount']; $order->traffic_amount = $orderType == 'add_time' ? 0 : $amounts['delivery_fee']; $order->payment_type = ($data['use_balance'] && $amounts['pay_amount'] == 0) ? 'balance' : null; $order->service_time = $data['service_time']; // 从用户地址获取位置信息 $order->address_id = $data['address_id']; $order->longitude = $address->longitude; // 经度 $order->latitude = $address->latitude; // 纬度 $order->location = $address->location; // 定位地址 $order->address = $address->address; // 详细地址 $order->area_code = $address->area_code; // 行政区划代码 $order->save(); // 3. 创建订单记录 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => $userId, 'object_type' => MemberUser::class, 'state' => $orderType == 'add_time' ? 'add_time' : 'create', 'remark' => $orderType == 'add_time' ? '加钟订单' : '创建订单', ]); // 4. 余额支付处理 if ($order->payment_type == 'balance') { $order->state = $orderType == 'normal' ? 'wait_receive' : 'service_ing'; $order->save(); // 创建订单支付记录 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => $userId, 'object_type' => MemberUser::class, 'state' => 'pay', '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'], // 'date' => date('Y-m-d'), // 'state' => 'busy', // ]); // TODO: 发送抢单通知 } return [ 'order_id' => $order->id, 'payment_type' => $order->payment_type, ]; }); } catch (Exception $e) { Log::error('创建订单失败:', [ 'message' => $e->getMessage(), 'user_id' => $userId, 'data' => $data, ]); throw $e; } } /** * 取消订单 */ public function cancelOrder($userId, $orderId) { return DB::transaction(function () use ($userId, $orderId) { try { $user = MemberUser::where('id', $userId)->firstOrFail(); $order = $user->orders()->find($orderId); 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; } }); } /** * 处理退款 */ 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, ]); // 添加钱包交易记录 $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', $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 finishOrder($userId, $orderId) { return DB::transaction(function () use ($userId, $orderId) { try { // 1. 参数校验 $order = Order::where('user_id', $userId) ->where('id', $orderId) ->where('state', 'service_ing') // 订单状态必须是服务中 ->firstOrFail(); if (! $order) { throw new Exception('订单不能结束'); } // 2. 创建订单历史记录 OrderRecord::create([ 'order_id' => $orderId, 'object_id' => $userId, 'object_type' => MemberUser::class, 'state' => 'finish', 'remark' => '服务完成', ]); // 3. 修改订单状态为服务结束 $order->state = 'service_end'; $order->save(); return ['message' => '订单已完成']; } catch (Exception $e) { Log::error('结束订单失败:', [ 'message' => $e->getMessage(), 'user_id' => $userId, 'order_id' => $orderId, ]); throw $e; } }); } /** * 确认技师离开 */ public function confirmLeave($userId, $orderId) { return DB::transaction(function () use ($userId, $orderId) { try { // 1. 参数校验 $order = Order::where('user_id', $userId) ->where('id', $orderId) ->where('state', 'service_end') // 订单状态必须是服务结束 ->firstOrFail(); if (! $order) { throw new Exception('订单不能撤离'); } // 2. 添加订单撤离记录 OrderRecord::create([ 'order_id' => $orderId, 'object_id' => $userId, 'object_type' => MemberUser::class, 'state' => 'leave', 'remark' => '技师已离开', ]); // 3. 修��订单状态为撤离 $order->state = 'leave'; $order->save(); return ['message' => '已确认技师离开']; } catch (Exception $e) { Log::error('确认技师离开失败:', [ 'message' => $e->getMessage(), 'user_id' => $userId, 'order_id' => $orderId, ]); throw $e; } }); } /** * 获取订单列表 */ public function getOrderList($user_id) { $user = MemberUser::find($user_id); return $user->orders() ->with([ 'coach.info:id,nickname,avatar,gender', ]) ->orderBy('created_at', 'desc') ->paginate(10); } /** * 获取订单详情 */ public function getOrderDetail($userId, $orderId) { $user = MemberUser::find($userId); return $user->orders()->with([ 'coach.info:id,nickname,avatar,gender', 'records' => function ($query) { $query->orderBy('created_at', 'asc'); }, ]) ->firstOrFail(); } /** * 订单退款 */ public function refundOrder($orderId) { $userId = Auth::id(); return DB::transaction(function () use ($orderId, $userId) { // 查询并锁定订单 $order = Order::where('id', $orderId) ->where('user_id', $userId) ->where('state', 'pending') ->lockForUpdate() ->firstOrFail(); // 更新订单状态 $order->state = 'refunded'; $order->save(); // 添加订单记录 OrderRecord::create([ 'order_id' => $orderId, 'object_id' => $userId, 'object_type' => 'user', 'state' => 'refund', 'remark' => '订单退款', ]); // 创建退款记录 WalletRefundRecord::create([ 'order_id' => $orderId, 'user_id' => $userId, 'amount' => $order->total_amount, 'state' => 'success', ]); return ['message' => '退款成功']; }); } /** * 获取代理商配置 */ public function getAgentConfig($agentId) { $agent = AgentInfo::where('id', $agentId) ->where('state', 'enable') ->firstOrFail(); // $config = AgentConfig::where('agent_id', $agentId)->firstOrFail(); return [ // 'min_distance' => $config->min_distance, // 'min_fee' => $config->min_fee, // 'per_km_fee' => $config->per_km_fee ]; } /** * 获取技师配置 */ public function getCoachConfig($coachId) { $coach = CoachUser::where('id', $coachId) ->where('state', 'enable') ->where('auth_state', 'passed') ->firstOrFail(); // $config = CoachConfig::where('coach_id', $coachId)->firstOrFail(); return [ // 'delivery_fee_type' => $config->delivery_fee_type, // 'charge_delivery_fee' => $config->charge_delivery_fee ]; } /** * 计算路费金额 */ public function calculateDeliveryFee($coachId, $projectId, $agentId, $distance) { // 查询技师数据 $coach = CoachUser::where('state', 'enable') ->whereHas('info', function ($query) { $query->where('state', 'approved'); }) ->whereHas('real', function ($query) { $query->where('state', 'approved'); }) ->whereHas('qual', function ($query) { $query->where('state', 'approved'); }) ->find($coachId); if (! $coach) { throw new Exception('技师不存在'); } // 查询技师项目 $coachProject = $coach->projects() ->where('state', 'enable') ->where('project_id', $projectId) ->first(); if (! $coachProject) { throw new Exception('项目不存在'); } // 技师免收路费 if ($coachProject->traffic_fee_type == 'free') { return 0; } // 查询代理商 $agent = AgentInfo::where('state', 'enable')->find($agentId); if ($agent) { $agentProject = $agent->projects() ->where('state', 'enable') ->where('project_id', $projectId) ->first(); if (! $agentProject) { throw new Exception('代理商项目不存在'); } $config = $agent->projectConfig; } else { // 系统配置 $config = SysConfig::where('key', 'delivery_fee')->firstOrFail(); dd('暂停处理'); } $fee = 0; if ($distance <= $config->min_distance) { $fee = $config->min_fee; } else { $extraDistance = $distance - $config->min_distance; $fee = $config->min_fee + ($extraDistance * $config->per_km_fee); } return $coachProject->delivery_fee_type == 'round_trip' ? $fee * 2 : $fee; } /** * 计算订单金额 */ public function calculateOrderAmount($userId, $addressId, $coachId, $projectId, $agentId, $useBalance = false) { // 参数校验 $user = MemberUser::find($userId); if (! $user) { throw new Exception('用户不存在'); } if ($user->state != 'enable') { throw new Exception('用户状态异常'); } // 查询地址 $address = $user->address()->find($addressId); // 查询技师数据 $coach = CoachUser::where('state', 'enable') ->whereHas('info', function ($query) { $query->where('state', 'approved'); }) ->whereHas('real', function ($query) { $query->where('state', 'approved'); }) ->whereHas('qual', function ($query) { $query->where('state', 'approved'); }) ->with(['info:id,nickname,avatar,gender']) ->find($coachId); if (! $coach) { throw new Exception('技师不存在'); } // 查询技师项目 $coachProject = $coach->projects() ->where('state', 'enable') ->where('project_id', $projectId) ->first(); if (! $coachProject) { throw new Exception('项目不存在'); } // 查询项目 $project = $coachProject->basicInfo; if (! $project) { throw new Exception('项目不存在'); } if ($project->state != 'enable') { throw new Exception('项目状态异常'); } // 查询代理商 $agent = AgentInfo::where('state', 'enable')->find($agentId); if ($agent) { $agentProject = $agent->projects() ->where('state', 'enable') ->where('project_id', $projectId) ->first(); if (! $agentProject) { throw new Exception('代理商项目不在'); } $project->price = $agentProject->price; $project->duration = $agentProject->duration; $project->distance = $address->distance; } // 计算金额 $projectAmount = $project->price; $deliveryFee = $this->calculateDeliveryFee($coachId, $projectId, $agentId, $address?->distance); // $tipAmount = request()->has('order_id') ? Order::find(request()->input('order_id'))->tip_amount : 0; $couponAmount = 0; if (request()->has('coupon_id')) { // $coupon = Coupon::where('id', request()->input('coupon_id')) // ->where('state', 'enable') // ->firstOrFail(); // $couponAmount = $coupon->amount; } $totalAmount = $projectAmount + $deliveryFee - $couponAmount; $balanceAmount = 0; $payAmount = $totalAmount; if ($useBalance) { $wallet = $user->wallet; if ($wallet && $wallet->available_balance >= $totalAmount) { $balanceAmount = $totalAmount; $payAmount = 0; } elseif ($wallet) { $balanceAmount = $wallet->available_balance; $payAmount = $totalAmount - $balanceAmount; } } return [ 'total_amount' => $totalAmount, 'balance_amount' => $balanceAmount, 'pay_amount' => $payAmount, 'coupon_amount' => $couponAmount, // 'tip_amount' => $tipAmount, 'project_amount' => $projectAmount, 'delivery_fee' => $deliveryFee, ]; } /** * 指定技师 */ public function assignCoach($userId, $orderId, $coachId) { return DB::transaction(function () use ($userId, $orderId, $coachId) { // 参数校验 $user = MemberUser::where('id', $userId) ->where('state', 'enable') ->firstOrFail(); $order = Order::where('id', $orderId) ->where('user_id', $userId) ->whereIn('state', [0, 1, 6]) ->firstOrFail(); $coach = CoachUser::where('id', $coachId) ->where('state', 'enable') ->where('auth_state', 'passed') ->firstOrFail(); // $schedule = CoachSchedule::where('coach_id', $coachId) // ->where('date', date('Y-m-d')) // ->where('state', 'free') // ->firstOrFail(); // 修改订单 $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->tip_amount = $amounts['tip_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(); // 创建订单历史 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' => '抢单成功', ]); // 更新抢单池 OrderGrabRecord::where('order_id', $orderId) ->update(['state' => 'success', 'coach_id' => $coachId]); // 更新排班 // $schedule->state = 'busy'; // $schedule->save(); return true; }); } }