|
@@ -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,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
}
|