|
@@ -2,7 +2,14 @@
|
|
|
|
|
|
namespace App\Services\Client;
|
|
|
|
|
|
+use App\Enums\OrderSource;
|
|
|
+use App\Enums\OrderStatus;
|
|
|
+use App\Enums\OrderType;
|
|
|
+use App\Enums\PaymentMethod;
|
|
|
use App\Enums\ProjectStatus;
|
|
|
+use App\Enums\TechnicianAuthStatus;
|
|
|
+use App\Enums\TechnicianStatus;
|
|
|
+use App\Enums\UserStatus;
|
|
|
use App\Models\AgentConfig;
|
|
|
use App\Models\AgentInfo;
|
|
|
use App\Models\CoachConfig;
|
|
@@ -20,6 +27,7 @@ use Exception;
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
+use Illuminate\Support\Facades\Redis;
|
|
|
|
|
|
class OrderService
|
|
|
{
|
|
@@ -107,10 +115,11 @@ class OrderService
|
|
|
*/
|
|
|
public function createOrder(int $userId, array $data): array
|
|
|
{
|
|
|
+
|
|
|
return DB::transaction(function () use ($userId, $data) {
|
|
|
// 1. 参数校验
|
|
|
$user = MemberUser::where('id', $userId)
|
|
|
- ->where('state', 'enable')
|
|
|
+ ->where('state', UserStatus::OPEN->value())
|
|
|
->firstOrFail();
|
|
|
|
|
|
$project = Project::where('id', $data['project_id'])
|
|
@@ -118,18 +127,30 @@ class OrderService
|
|
|
->firstOrFail();
|
|
|
|
|
|
// 2. 订单类型判断
|
|
|
- $orderType = isset($data['order_id']) ? 'add_time' : 'normal';
|
|
|
+ $orderType = $data['order_type'];
|
|
|
|
|
|
// 关键操作:验证必要参数
|
|
|
abort_if(empty($data['project_id']), 400, '项目ID不能为空');
|
|
|
- abort_if($orderType == 'normal' && empty($data['coach_id']), 400, '技师ID不能为空');
|
|
|
- abort_if($orderType == 'normal' && empty($data['address_id']), 400, '地址ID不能为空');
|
|
|
+ // 上门订单必须指定技师和地址
|
|
|
+ abort_if($orderType == OrderType::VISIT->value && empty($data['coach_id']), 400, '技师ID不能为空');
|
|
|
+ abort_if($orderType == OrderType::VISIT->value && empty($data['address_id']), 400, '地址ID不能为空');
|
|
|
+ // 抢单订单必须指定地址
|
|
|
+ abort_if($orderType == OrderType::GRAB->value && empty($data['address_id']), 400, '地址ID不能为空');
|
|
|
+ // 加钟订单必须指定原订单
|
|
|
+ abort_if($orderType == OrderType::OVERTIME->value && empty($data['order_id']), 400, '原订单ID不能为空');
|
|
|
+ // 到店订单必须指定店铺
|
|
|
+ abort_if($orderType == OrderType::SHOP->value && empty($data['shop_id']), 400, '店铺ID不能为空');
|
|
|
+ // 应急订单必须指定地址
|
|
|
+ abort_if($orderType == OrderType::EMERGENCY->value && empty($data['address_id']), 400, '地址ID不能为空');
|
|
|
|
|
|
// 3. 验证技师
|
|
|
// 4. 根据订单类型处理
|
|
|
- if ($orderType == 'normal') {
|
|
|
+ // 上门订单
|
|
|
+ if ($orderType == OrderType::VISIT->value) {
|
|
|
$this->validateCoach($data['coach_id']);
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ // 加钟订单
|
|
|
+ if ($orderType == OrderType::OVERTIME->value) {
|
|
|
$originalOrder = $this->getOriginalOrder($user, $data['order_id']);
|
|
|
|
|
|
$data['address_id'] = $originalOrder->address_id;
|
|
@@ -144,19 +165,20 @@ class OrderService
|
|
|
->firstOrFail();
|
|
|
|
|
|
// 5. 计算订单金额
|
|
|
+ $data['use_balance'] = $data['use_balance'] ?? false;
|
|
|
$amounts = $this->calculateOrderAmount(
|
|
|
$userId,
|
|
|
$address->id,
|
|
|
$data['coach_id'],
|
|
|
$data['project_id'],
|
|
|
- $project->agent_id,
|
|
|
- $data['use_balance'] ?? false
|
|
|
+ $project?->agent_id,
|
|
|
+ $data['use_balance']
|
|
|
);
|
|
|
|
|
|
// 6. 验证金额和余额
|
|
|
abort_if($amounts['total_amount'] <= 0, 400, '订单金额异常');
|
|
|
|
|
|
- if ($data['payment_type'] == 'balance') {
|
|
|
+ if ($data['payment_type'] == PaymentMethod::BALANCE->value) {
|
|
|
$wallet = $user->wallet;
|
|
|
abort_if($wallet->available_balance < $amounts['balance_amount'], 400, '可用余额不足');
|
|
|
}
|
|
@@ -164,7 +186,7 @@ class OrderService
|
|
|
$order = $this->createOrderRecord($userId, $data, $orderType, $address, $data['payment_type'], (object) $amounts);
|
|
|
|
|
|
// 8. 余额支付处理
|
|
|
- if ($order->payment_type == 'balance') {
|
|
|
+ if ($order->payment_type == PaymentMethod::BALANCE->value && $orderType != OrderType::GRAB->value) {
|
|
|
$this->handleBalancePayment($user, $order, $orderType);
|
|
|
}
|
|
|
|
|
@@ -178,11 +200,13 @@ class OrderService
|
|
|
// 提取方法:验证技师
|
|
|
public function validateCoach(int $coachId): CoachUser
|
|
|
{
|
|
|
+ $coach = CoachUser::where('id', $coachId)->first();
|
|
|
+
|
|
|
$coach = CoachUser::where('id', $coachId)
|
|
|
- ->where('state', 'enable')
|
|
|
- ->whereHas('info', fn ($q) => $q->where('state', 'approved'))
|
|
|
- ->whereHas('qual', fn ($q) => $q->where('state', 'approved'))
|
|
|
- ->whereHas('real', fn ($q) => $q->where('state', 'approved'))
|
|
|
+ ->where('state', TechnicianStatus::ACTIVE->value)
|
|
|
+ ->whereHas('info', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
+ ->whereHas('qual', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
+ ->whereHas('real', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
->firstOrFail();
|
|
|
|
|
|
return $coach;
|
|
@@ -224,14 +248,14 @@ class OrderService
|
|
|
$order->project_id = $data['project_id'];
|
|
|
$order->coach_id = $data['coach_id'];
|
|
|
$order->type = $orderType;
|
|
|
- $order->state = 'wait_pay';
|
|
|
- $order->source = 'platform';
|
|
|
+ $order->state = OrderStatus::CREATED->value;
|
|
|
+ $order->source = OrderSource::PLATFORM->value;
|
|
|
$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' : $payment_type;
|
|
|
+ $order->traffic_amount = $orderType == OrderType::OVERTIME->value ? 0 : $amounts->delivery_fee;
|
|
|
+ $order->payment_type = ($data['use_balance'] && $amounts->pay_amount == 0) ? PaymentMethod::BALANCE->value : $payment_type;
|
|
|
$order->service_time = $data['service_time'];
|
|
|
$order->address_id = $data['address_id'];
|
|
|
$order->longitude = $address->longitude;
|
|
@@ -241,14 +265,26 @@ class OrderService
|
|
|
$order->area_code = $address->area_code;
|
|
|
$order->save();
|
|
|
|
|
|
+ // 创建订单记录
|
|
|
OrderRecord::create([
|
|
|
'order_id' => $order->id,
|
|
|
'object_id' => $userId,
|
|
|
'object_type' => MemberUser::class,
|
|
|
- 'state' => $orderType == 'add_time' ? 'add_time' : 'create',
|
|
|
- 'remark' => $orderType == 'add_time' ? '加钟订单' : '创建订单',
|
|
|
+ 'state' => OrderStatus::CREATED->value,
|
|
|
+ 'remark' => $orderType == OrderType::OVERTIME->value ? '加钟订单' : '创建订单',
|
|
|
]);
|
|
|
|
|
|
+ if ($orderType == OrderType::GRAB->value) {
|
|
|
+ // 将订单地址经纬度存入redis的geo类型
|
|
|
+ Redis::geoadd(
|
|
|
+ 'order_locations',
|
|
|
+ $order->longitude,
|
|
|
+ $order->latitude,
|
|
|
+ 'order:'.$order->id
|
|
|
+ );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
return $order;
|
|
|
}
|
|
|
|
|
@@ -309,13 +345,13 @@ class OrderService
|
|
|
{
|
|
|
// 复用之前的用户验证逻辑
|
|
|
$user = MemberUser::where('id', $userId)
|
|
|
- ->where('state', 'enable')
|
|
|
+ ->where('state', UserStatus::OPEN->value)
|
|
|
->firstOrFail();
|
|
|
|
|
|
// 验证订单状态
|
|
|
$order = Order::where('user_id', $userId)
|
|
|
->where('id', $orderId)
|
|
|
- ->whereIn('state', ['wait_pay', 'wait_receive', 'on_the_way'])
|
|
|
+ ->whereIn('state', [OrderStatus::CREATED->value, OrderStatus::ASSIGNED->value, OrderStatus::PAID->value, OrderStatus::ACCEPTED->value, OrderStatus::DEPARTED->value])
|
|
|
->lockForUpdate()
|
|
|
->firstOrFail();
|
|
|
|
|
@@ -330,19 +366,19 @@ class OrderService
|
|
|
$user = $order->user;
|
|
|
|
|
|
switch ($order->state) {
|
|
|
- case 'wait_receive': // 已接单
|
|
|
+ case OrderStatus::ACCEPTED->value: // 已接单
|
|
|
// 扣除20%费用
|
|
|
$deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.2;
|
|
|
$this->handleRefund($user, $order, $deductAmount, false);
|
|
|
break;
|
|
|
|
|
|
- case 'on_the_way': // 已出发
|
|
|
+ case OrderStatus::DEPARTED->value: // 已出发
|
|
|
// 扣除50%费用并扣除路费
|
|
|
$deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.5;
|
|
|
$this->handleRefund($user, $order, $deductAmount, true);
|
|
|
break;
|
|
|
|
|
|
- case 'wait_pay':
|
|
|
+ case OrderStatus::CREATED->value:
|
|
|
// 待支付状态直接取消,无需退款
|
|
|
break;
|
|
|
|
|
@@ -734,10 +770,10 @@ class OrderService
|
|
|
): float {
|
|
|
try {
|
|
|
// 1. 校验技师
|
|
|
- $coach = CoachUser::where('state', 'enable')
|
|
|
- ->whereHas('info', fn ($q) => $q->where('state', 'approved'))
|
|
|
- ->whereHas('real', fn ($q) => $q->where('state', 'approved'))
|
|
|
- ->whereHas('qual', fn ($q) => $q->where('state', 'approved'))
|
|
|
+ $coach = CoachUser::where('state', TechnicianStatus::ACTIVE->value)
|
|
|
+ ->whereHas('info', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
+ ->whereHas('real', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
+ ->whereHas('qual', fn ($q) => $q->where('state', TechnicianAuthStatus::PASSED->value))
|
|
|
->with(['projects' => fn ($q) => $q->where('project_id', $projectId)])
|
|
|
->find($coachId);
|
|
|
|
|
@@ -845,14 +881,14 @@ class OrderService
|
|
|
|
|
|
// 1. 参数校验
|
|
|
$user = MemberUser::find($userId);
|
|
|
- abort_if(! $user || $user->state != 'enable', 404, '用户不存在或状态异常');
|
|
|
+ abort_if(! $user || $user->state != UserStatus::OPEN->value, 404, '用户不存在或状态异常');
|
|
|
|
|
|
// 2. 查询技师项目
|
|
|
$coach = $this->validateCoach($coachId);
|
|
|
|
|
|
abort_if(! $coach, 404, '技师不存在或状态异常');
|
|
|
$coachProject = $coach->projects()
|
|
|
- ->where('state', 'enable')
|
|
|
+ ->where('state', ProjectStatus::OPEN->value)
|
|
|
->where('project_id', $projectId)
|
|
|
->first();
|
|
|
|
|
@@ -1000,7 +1036,7 @@ class OrderService
|
|
|
try {
|
|
|
// 查询订单信息
|
|
|
$order = Order::where('id', $orderId)
|
|
|
- ->whereIn('state', ['wait_pay', 'wait_service'])
|
|
|
+ ->whereIn('state', [OrderStatus::CREATED->value])
|
|
|
->firstOrFail();
|
|
|
// 查询抢单池列表
|
|
|
$grabList = $order->grabRecords()->with(['coach.info'])->get();
|
|
@@ -1140,7 +1176,7 @@ class OrderService
|
|
|
// 验证订单状态
|
|
|
$order = Order::where('user_id', $userId)
|
|
|
->where('id', $orderId)
|
|
|
- ->whereIn('state', ['wait_pay', 'wait_receive'])
|
|
|
+ ->whereIn('state', [OrderStatus::CREATED->value])
|
|
|
->lockForUpdate()
|
|
|
->firstOrFail();
|
|
|
|
|
@@ -1156,14 +1192,14 @@ class OrderService
|
|
|
$order->coach_id = $coachId;
|
|
|
|
|
|
// 待支付订单需要重新计算金额
|
|
|
- if ($order->state == 'wait_pay') {
|
|
|
+ if ($order->state == OrderStatus::CREATED->value) {
|
|
|
$amounts = $this->calculateOrderAmount(
|
|
|
$order->user_id,
|
|
|
$order->address_id,
|
|
|
$coachId,
|
|
|
$order->project_id,
|
|
|
$order->agent_id,
|
|
|
- $order->payment_type === 'balance'
|
|
|
+ $order->payment_type === PaymentMethod::BALANCE->value
|
|
|
);
|
|
|
|
|
|
// 更新订单金额
|