OrderService.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. <?php
  2. namespace App\Services\Client;
  3. use App\Models\AgentConfig;
  4. use App\Models\AgentInfo;
  5. use App\Models\CoachConfig;
  6. use App\Models\CoachSchedule;
  7. use App\Models\CoachUser;
  8. use App\Models\Coupon;
  9. use App\Models\MemberUser;
  10. use App\Models\Order;
  11. use App\Models\OrderGrabRecord;
  12. use App\Models\OrderRecord;
  13. use App\Models\Project;
  14. use App\Models\SysConfig;
  15. use App\Models\User;
  16. use App\Models\WalletRefundRecord;
  17. use Carbon\Carbon;
  18. use Exception;
  19. use Illuminate\Support\Facades\Auth;
  20. use Illuminate\Support\Facades\DB;
  21. use Illuminate\Support\Facades\Log;
  22. class OrderService
  23. {
  24. protected AgentService $agentService;
  25. protected ProjectService $projectService;
  26. public function __construct(
  27. AgentService $agentService,
  28. ProjectService $projectService
  29. ) {
  30. $this->agentService = $agentService;
  31. $this->projectService = $projectService;
  32. }
  33. /**
  34. * 订单初始化
  35. */
  36. public function initialize($userId, $data)
  37. {
  38. $user = MemberUser::find($userId);
  39. if (! $user) {
  40. throw new Exception('用户不存在');
  41. }
  42. if ($user->state != 'enable') {
  43. throw new Exception('用户状态异常');
  44. }
  45. // 查询用户钱包
  46. $wallet = $user->wallet;
  47. // 查询默认地址
  48. $address = $user->address;
  49. $areaCode = $address ? $address->area_code : $data['area_code'];
  50. // 查询技师数据
  51. $coach = CoachUser::where('state', 'enable')
  52. ->whereHas('info', function ($query) {
  53. $query->where('state', 'approved');
  54. })
  55. ->whereHas('real', function ($query) {
  56. $query->where('state', 'approved');
  57. })
  58. ->whereHas('qual', function ($query) {
  59. $query->where('state', 'approved');
  60. })
  61. ->with(['info:id,nickname,avatar,gender'])
  62. ->find($data['coach_id']);
  63. if (! $coach) {
  64. throw new Exception('技师不存在');
  65. }
  66. // 查询技师排班
  67. // $schedule = CoachSchedule::where('coach_id', $coachId)
  68. // ->where('date', date('Y-m-d'))
  69. // ->first();
  70. // // 查询用户优惠券
  71. // $coupons = Coupon::where('user_id', $userId)
  72. // ->where('state', 'enable')
  73. // ->where('expire_time', '>', now())
  74. // ->get();
  75. // 获取项目详情
  76. $project = $this->projectService->getProjectDetail($data['project_id'], $areaCode);
  77. // 计算订单金额
  78. $amounts = $this->calculateOrderAmount($userId, $address?->id, $data['coach_id'], $data['project_id'], $project?->agent_id);
  79. return [
  80. 'wallet' => $wallet,
  81. 'coach' => $coach,
  82. 'project' => $project,
  83. 'address' => $address,
  84. // 'schedule' => $schedule,
  85. 'amounts' => $amounts,
  86. // 'coupons' => $coupons
  87. ];
  88. }
  89. /**
  90. * 创建订单
  91. */
  92. public function createOrder($userId, array $data)
  93. {
  94. try {
  95. return DB::transaction(function () use ($userId, $data) {
  96. // 1. 参数校验
  97. $user = MemberUser::where('id', $userId)
  98. ->where('state', 'enable')
  99. ->firstOrFail();
  100. $project = Project::where('id', $data['project_id'])
  101. ->where('state', 'enable')
  102. ->firstOrFail();
  103. // 2. 创建订单
  104. $orderType = isset($data['order_id']) ? 'add_time' : 'normal';
  105. if ($orderType == 'normal') {
  106. // 查询技师及其认证状态
  107. $coach = CoachUser::where('id', $data['coach_id'])
  108. ->where('state', 'enable')
  109. ->whereHas('info', function ($query) {
  110. $query->where('state', 'approved');
  111. })
  112. ->whereHas('qual', function ($query) {
  113. $query->where('state', 'approved');
  114. })
  115. ->whereHas('real', function ($query) {
  116. $query->where('state', 'approved');
  117. })
  118. ->firstOrFail();
  119. } else {
  120. // 1. 检查原订单
  121. $originalOrder = $user->orders->where('id', $data['order_id'])
  122. ->whereIn('state', ['service_ing', 'service_end']) // 只有服务中和服务结束的订单可以加钟
  123. ->firstOrFail();
  124. // 2. 设置加钟订单的服务时间
  125. if ($originalOrder->state == 'service_ing') {
  126. // 服务中订单,加钟开始时间为原订单结束时间
  127. $startTime = now(); // Carbon::parse($originalOrder->service_time)->addMinutes($originalOrder->project->duration);
  128. } else {
  129. // 服务结束订单,加钟开始时间为当前时间
  130. $startTime = now();
  131. }
  132. // 3. 构建加钟订单数据
  133. $data['order_id'] = $data['order_id']; // 关联原订单ID
  134. $data['address_id'] = $originalOrder->address_id;
  135. $data['service_time'] = $startTime;
  136. $data['coach_id'] = $originalOrder->coach_id;
  137. }
  138. $address = $user->addresses()
  139. ->where('id', $data['address_id'])
  140. ->firstOrFail();
  141. // 计算订单金额
  142. $amounts = $this->calculateOrderAmount(
  143. $userId,
  144. $data['address_id'],
  145. $data['coach_id'],
  146. $data['project_id'],
  147. $project->agent_id,
  148. $data['use_balance'] ?? false
  149. );
  150. $order = new Order;
  151. $order->user_id = $userId;
  152. $order->project_id = $data['project_id'];
  153. $order->coach_id = $data['coach_id'];
  154. $order->type = $orderType;
  155. $order->state = 'wait_pay';
  156. $order->source = 'platform';
  157. $order->total_amount = $amounts['total_amount'];
  158. $order->balance_amount = $amounts['balance_amount'];
  159. $order->pay_amount = $amounts['pay_amount'];
  160. $order->project_amount = $amounts['project_amount'];
  161. $order->traffic_amount = $orderType == 'add_time' ? 0 : $amounts['delivery_fee'];
  162. $order->payment_type = ($data['use_balance'] && $amounts['pay_amount'] == 0) ? 'balance' : null;
  163. $order->service_time = $data['service_time'];
  164. // 从用户地址获取位置信息
  165. $order->address_id = $data['address_id'];
  166. $order->longitude = $address->longitude; // 经度
  167. $order->latitude = $address->latitude; // 纬度
  168. $order->location = $address->location; // 定位地址
  169. $order->address = $address->address; // 详细地址
  170. $order->area_code = $address->area_code; // 行政区划代码
  171. $order->save();
  172. // 3. 创建订单记录
  173. OrderRecord::create([
  174. 'order_id' => $order->id,
  175. 'object_id' => $userId,
  176. 'object_type' => MemberUser::class,
  177. 'state' => $orderType == 'add_time' ? 'add_time' : 'create',
  178. 'remark' => $orderType == 'add_time' ? '加钟订单' : '创建订单',
  179. ]);
  180. // 4. 余额支付处理
  181. if ($order->payment_type == 'balance') {
  182. $order->state = $orderType == 'normal' ? 'wait_receive' : 'service_ing';
  183. $order->save();
  184. // 创建订单支付记录
  185. OrderRecord::create([
  186. 'order_id' => $order->id,
  187. 'object_id' => $userId,
  188. 'object_type' => MemberUser::class,
  189. 'state' => 'pay',
  190. 'remark' => '余额支付',
  191. ]);
  192. // 扣除用户钱包总余额
  193. $user->wallet->decrement('total_balance', $order->balance_amount);
  194. // 扣除用户钱包可用余额
  195. $user->wallet->decrement('available_balance', $order->balance_amount);
  196. $user->wallet->save();
  197. // 创建技师排班
  198. // CoachSchedule::create([
  199. // 'coach_id' => $data['coach_id'],
  200. // 'date' => date('Y-m-d'),
  201. // 'state' => 'busy',
  202. // ]);
  203. // TODO: 发送抢单通知
  204. }
  205. return [
  206. 'order_id' => $order->id,
  207. 'payment_type' => $order->payment_type,
  208. ];
  209. });
  210. } catch (Exception $e) {
  211. Log::error('创建订单失败:', [
  212. 'message' => $e->getMessage(),
  213. 'user_id' => $userId,
  214. 'data' => $data,
  215. ]);
  216. throw $e;
  217. }
  218. }
  219. /**
  220. * 取消订单
  221. */
  222. public function cancelOrder($userId, $orderId)
  223. {
  224. return DB::transaction(function () use ($userId, $orderId) {
  225. try {
  226. $user = MemberUser::where('id', $userId)->firstOrFail();
  227. $order = $user->orders()->find($orderId);
  228. if (! $order) {
  229. throw new Exception('订单不存在');
  230. }
  231. // 判断订单状态
  232. if ($order->state == 'wait_receive') { // 已接单
  233. // 扣除20%费用
  234. $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.2;
  235. $this->handleRefund($user, $order, $deductAmount, false);
  236. } elseif ($order->state == 'on_the_way') { // 已出发
  237. // 扣除50%费用并扣除路费
  238. $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.5;
  239. $this->handleRefund($user, $order, $deductAmount, true);
  240. } elseif ($order->state == 'wait_pay') {
  241. // 待支付状态直接取消,无需退款
  242. } else {
  243. throw new Exception('当前订单状态不允许取消');
  244. }
  245. // 添加订单取消记录
  246. OrderRecord::create([
  247. 'order_id' => $orderId,
  248. 'object_id' => $userId,
  249. 'object_type' => MemberUser::class,
  250. 'state' => 'cancel',
  251. 'remark' => '用户取消订单',
  252. ]);
  253. // 修改订单状态
  254. $order->state = 'cancel';
  255. $order->save();
  256. return ['message' => '订单已取消'];
  257. } catch (Exception $e) {
  258. Log::error('取消订单失败:', [
  259. 'message' => $e->getMessage(),
  260. 'user_id' => $userId,
  261. 'order_id' => $orderId,
  262. ]);
  263. throw $e;
  264. }
  265. });
  266. }
  267. /**
  268. * 处理退款
  269. */
  270. private function handleRefund($user, $order, $deductAmount, $deductTrafficFee)
  271. {
  272. // 计算实际退款金额
  273. $refundAmount = $order->payment_amount + $order->balance_amount;
  274. if ($deductTrafficFee) {
  275. $refundAmount -= $order->traffic_amount;
  276. // 记录技师路费收入
  277. // ...
  278. }
  279. $refundAmount -= $deductAmount;
  280. // 优先从余额支付金额中扣除
  281. $balanceRefund = min($order->balance_amount, $refundAmount);
  282. if ($balanceRefund > 0) {
  283. // 添加钱包退款记录
  284. $refundRecord = $user->wallet->refundRecords()->create([
  285. 'refund_method' => 'balance',
  286. 'total_refund_amount' => $order->payment_amount + $order->balance_amount,
  287. 'actual_refund_amount' => '0.00',
  288. 'wallet_balance_refund_amount' => $balanceRefund,
  289. 'recharge_balance_refund_amount' => '0.00',
  290. 'remark' => '订单取消退还余额',
  291. 'order_id' => $order->id,
  292. ]);
  293. // 添加钱包交易记录
  294. $user->wallet->transRecords()->create([
  295. 'amount' => $balanceRefund,
  296. 'owner_type' => $refundRecord::class,
  297. 'owner_id' => $refundRecord->id,
  298. 'remark' => '订单取消退还余额',
  299. 'trans_type' => 'income',
  300. 'storage_type' => 'balance',
  301. 'amount' => $balanceRefund,
  302. 'before_balance' => $user->wallet->total_balance,
  303. 'after_balance' => $user->wallet->total_balance + $balanceRefund,
  304. 'before_recharge_balance' => '0.00',
  305. 'after_recharge_balance' => '0.00',
  306. 'trans_time' => now(),
  307. 'state' => 'success',
  308. ]);
  309. $user->wallet->increment('total_balance', $balanceRefund);
  310. $user->wallet->increment('available_balance', $balanceRefund);
  311. $user->wallet->save();
  312. }
  313. // 剩余退款金额从支付金额中退还
  314. $paymentRefund = $refundAmount - $balanceRefund;
  315. if ($paymentRefund > 0) {
  316. // 添加钱包退款记录
  317. $refundRecord = $user->wallet->refundRecords()->create([
  318. 'refund_method' => 'balance',
  319. 'total_refund_amount' => $order->payment_amount + $order->balance_amount,
  320. 'actual_refund_amount' => '0.00',
  321. 'wallet_balance_refund_amount' => $balanceRefund,
  322. 'recharge_balance_refund_amount' => '0.00',
  323. 'remark' => '订单取消退还余额',
  324. 'order_id' => $order->id,
  325. ]);
  326. // 添加钱包交易记录
  327. $user->wallet->transRecords()->create([
  328. 'amount' => $balanceRefund,
  329. 'owner_type' => $refundRecord::class,
  330. 'owner_id' => $refundRecord->id,
  331. 'remark' => '订单取消退还余额',
  332. 'trans_type' => 'income',
  333. 'storage_type' => 'balance',
  334. 'amount' => $balanceRefund,
  335. 'before_balance' => $user->wallet->total_balance,
  336. 'after_balance' => $user->wallet->total_balance + $balanceRefund,
  337. 'before_recharge_balance' => '0.00',
  338. 'after_recharge_balance' => '0.00',
  339. 'trans_time' => now(),
  340. 'state' => 'success',
  341. ]);
  342. $user->wallet->increment('total_balance', $paymentRefund);
  343. $user->wallet->increment('available_balance', $paymentRefund);
  344. $user->wallet->save();
  345. }
  346. // 记录平台收入
  347. if ($deductAmount > 0) {
  348. // TODO: 添加平台收入记录
  349. // PlatformIncome::create([...]);
  350. }
  351. }
  352. /**
  353. * 结束订单
  354. */
  355. public function finishOrder($userId, $orderId)
  356. {
  357. return DB::transaction(function () use ($userId, $orderId) {
  358. try {
  359. // 1. 参数校验
  360. $order = Order::where('user_id', $userId)
  361. ->where('id', $orderId)
  362. ->where('state', 'service_ing') // 订单状态必须是服务中
  363. ->firstOrFail();
  364. if (! $order) {
  365. throw new Exception('订单不能结束');
  366. }
  367. // 2. 创建订单历史记录
  368. OrderRecord::create([
  369. 'order_id' => $orderId,
  370. 'object_id' => $userId,
  371. 'object_type' => MemberUser::class,
  372. 'state' => 'finish',
  373. 'remark' => '服务完成',
  374. ]);
  375. // 3. 修改订单状态为服务结束
  376. $order->state = 'service_end';
  377. $order->save();
  378. return ['message' => '订单已完成'];
  379. } catch (Exception $e) {
  380. Log::error('结束订单失败:', [
  381. 'message' => $e->getMessage(),
  382. 'user_id' => $userId,
  383. 'order_id' => $orderId,
  384. ]);
  385. throw $e;
  386. }
  387. });
  388. }
  389. /**
  390. * 确认技师离开
  391. */
  392. public function confirmLeave($userId, $orderId)
  393. {
  394. return DB::transaction(function () use ($userId, $orderId) {
  395. try {
  396. // 1. 参数校验
  397. $order = Order::where('user_id', $userId)
  398. ->where('id', $orderId)
  399. ->where('state', 'service_end') // 订单状态必须是服务结束
  400. ->firstOrFail();
  401. if (! $order) {
  402. throw new Exception('订单不能撤离');
  403. }
  404. // 2. 添加订单撤离记录
  405. OrderRecord::create([
  406. 'order_id' => $orderId,
  407. 'object_id' => $userId,
  408. 'object_type' => MemberUser::class,
  409. 'state' => 'leave',
  410. 'remark' => '技师已离开',
  411. ]);
  412. // 3. 修��订单状态为撤离
  413. $order->state = 'leave';
  414. $order->save();
  415. return ['message' => '已确认技师离开'];
  416. } catch (Exception $e) {
  417. Log::error('确认技师离开失败:', [
  418. 'message' => $e->getMessage(),
  419. 'user_id' => $userId,
  420. 'order_id' => $orderId,
  421. ]);
  422. throw $e;
  423. }
  424. });
  425. }
  426. /**
  427. * 获取订单列表
  428. */
  429. public function getOrderList($user_id)
  430. {
  431. $user = MemberUser::find($user_id);
  432. return $user->orders()
  433. ->with([
  434. 'coach.info:id,nickname,avatar,gender',
  435. ])
  436. ->orderBy('created_at', 'desc')
  437. ->paginate(10);
  438. }
  439. /**
  440. * 获取订单详情
  441. */
  442. public function getOrderDetail($userId, $orderId)
  443. {
  444. $user = MemberUser::find($userId);
  445. return $user->orders()->with([
  446. 'coach.info:id,nickname,avatar,gender',
  447. 'records' => function ($query) {
  448. $query->orderBy('created_at', 'asc');
  449. },
  450. ])
  451. ->firstOrFail();
  452. }
  453. /**
  454. * 订单退款
  455. */
  456. public function refundOrder($orderId)
  457. {
  458. $userId = Auth::id();
  459. return DB::transaction(function () use ($orderId, $userId) {
  460. // 查询并锁定订单
  461. $order = Order::where('id', $orderId)
  462. ->where('user_id', $userId)
  463. ->where('state', 'pending')
  464. ->lockForUpdate()
  465. ->firstOrFail();
  466. // 更新订单状态
  467. $order->state = 'refunded';
  468. $order->save();
  469. // 添加订单记录
  470. OrderRecord::create([
  471. 'order_id' => $orderId,
  472. 'object_id' => $userId,
  473. 'object_type' => 'user',
  474. 'state' => 'refund',
  475. 'remark' => '订单退款',
  476. ]);
  477. // 创建退款记录
  478. WalletRefundRecord::create([
  479. 'order_id' => $orderId,
  480. 'user_id' => $userId,
  481. 'amount' => $order->total_amount,
  482. 'state' => 'success',
  483. ]);
  484. return ['message' => '退款成功'];
  485. });
  486. }
  487. /**
  488. * 获取代理商配置
  489. */
  490. public function getAgentConfig($agentId)
  491. {
  492. $agent = AgentInfo::where('id', $agentId)
  493. ->where('state', 'enable')
  494. ->firstOrFail();
  495. // $config = AgentConfig::where('agent_id', $agentId)->firstOrFail();
  496. return [
  497. // 'min_distance' => $config->min_distance,
  498. // 'min_fee' => $config->min_fee,
  499. // 'per_km_fee' => $config->per_km_fee
  500. ];
  501. }
  502. /**
  503. * 获取技师配置
  504. */
  505. public function getCoachConfig($coachId)
  506. {
  507. $coach = CoachUser::where('id', $coachId)
  508. ->where('state', 'enable')
  509. ->where('auth_state', 'passed')
  510. ->firstOrFail();
  511. // $config = CoachConfig::where('coach_id', $coachId)->firstOrFail();
  512. return [
  513. // 'delivery_fee_type' => $config->delivery_fee_type,
  514. // 'charge_delivery_fee' => $config->charge_delivery_fee
  515. ];
  516. }
  517. /**
  518. * 计算路费金额
  519. */
  520. public function calculateDeliveryFee($coachId, $projectId, $agentId, $distance)
  521. {
  522. // 查询技师数据
  523. $coach = CoachUser::where('state', 'enable')
  524. ->whereHas('info', function ($query) {
  525. $query->where('state', 'approved');
  526. })
  527. ->whereHas('real', function ($query) {
  528. $query->where('state', 'approved');
  529. })
  530. ->whereHas('qual', function ($query) {
  531. $query->where('state', 'approved');
  532. })
  533. ->find($coachId);
  534. if (! $coach) {
  535. throw new Exception('技师不存在');
  536. }
  537. // 查询技师项目
  538. $coachProject = $coach->projects()
  539. ->where('state', 'enable')
  540. ->where('project_id', $projectId)
  541. ->first();
  542. if (! $coachProject) {
  543. throw new Exception('项目不存在');
  544. }
  545. // 技师免收路费
  546. if ($coachProject->traffic_fee_type == 'free') {
  547. return 0;
  548. }
  549. // 查询代理商
  550. $agent = AgentInfo::where('state', 'enable')->find($agentId);
  551. if ($agent) {
  552. $agentProject = $agent->projects()
  553. ->where('state', 'enable')
  554. ->where('project_id', $projectId)
  555. ->first();
  556. if (! $agentProject) {
  557. throw new Exception('代理商项目不存在');
  558. }
  559. $config = $agent->projectConfig;
  560. } else {
  561. // 系统配置
  562. $config = SysConfig::where('key', 'delivery_fee')->firstOrFail();
  563. dd('暂停处理');
  564. }
  565. $fee = 0;
  566. if ($distance <= $config->min_distance) {
  567. $fee = $config->min_fee;
  568. } else {
  569. $extraDistance = $distance - $config->min_distance;
  570. $fee = $config->min_fee + ($extraDistance * $config->per_km_fee);
  571. }
  572. return $coachProject->delivery_fee_type == 'round_trip' ? $fee * 2 : $fee;
  573. }
  574. /**
  575. * 计算订单金额
  576. */
  577. public function calculateOrderAmount($userId, $addressId, $coachId, $projectId, $agentId, $useBalance = false)
  578. {
  579. // 参数校验
  580. $user = MemberUser::find($userId);
  581. if (! $user) {
  582. throw new Exception('用户不存在');
  583. }
  584. if ($user->state != 'enable') {
  585. throw new Exception('用户状态异常');
  586. }
  587. // 查询地址
  588. $address = $user->address()->find($addressId);
  589. // 查询技师数据
  590. $coach = CoachUser::where('state', 'enable')
  591. ->whereHas('info', function ($query) {
  592. $query->where('state', 'approved');
  593. })
  594. ->whereHas('real', function ($query) {
  595. $query->where('state', 'approved');
  596. })
  597. ->whereHas('qual', function ($query) {
  598. $query->where('state', 'approved');
  599. })
  600. ->with(['info:id,nickname,avatar,gender'])
  601. ->find($coachId);
  602. if (! $coach) {
  603. throw new Exception('技师不存在');
  604. }
  605. // 查询技师项目
  606. $coachProject = $coach->projects()
  607. ->where('state', 'enable')
  608. ->where('project_id', $projectId)
  609. ->first();
  610. if (! $coachProject) {
  611. throw new Exception('项目不存在');
  612. }
  613. // 查询项目
  614. $project = $coachProject->basicInfo;
  615. if (! $project) {
  616. throw new Exception('项目不存在');
  617. }
  618. if ($project->state != 'enable') {
  619. throw new Exception('项目状态异常');
  620. }
  621. // 查询代理商
  622. $agent = AgentInfo::where('state', 'enable')->find($agentId);
  623. if ($agent) {
  624. $agentProject = $agent->projects()
  625. ->where('state', 'enable')
  626. ->where('project_id', $projectId)
  627. ->first();
  628. if (! $agentProject) {
  629. throw new Exception('代理商项目不在');
  630. }
  631. $project->price = $agentProject->price;
  632. $project->duration = $agentProject->duration;
  633. $project->distance = $address->distance;
  634. }
  635. // 计算金额
  636. $projectAmount = $project->price;
  637. $deliveryFee = $this->calculateDeliveryFee($coachId, $projectId, $agentId, $address?->distance);
  638. // $tipAmount = request()->has('order_id') ? Order::find(request()->input('order_id'))->tip_amount : 0;
  639. $couponAmount = 0;
  640. if (request()->has('coupon_id')) {
  641. // $coupon = Coupon::where('id', request()->input('coupon_id'))
  642. // ->where('state', 'enable')
  643. // ->firstOrFail();
  644. // $couponAmount = $coupon->amount;
  645. }
  646. $totalAmount = $projectAmount + $deliveryFee - $couponAmount;
  647. $balanceAmount = 0;
  648. $payAmount = $totalAmount;
  649. if ($useBalance) {
  650. $wallet = $user->wallet;
  651. if ($wallet && $wallet->available_balance >= $totalAmount) {
  652. $balanceAmount = $totalAmount;
  653. $payAmount = 0;
  654. } elseif ($wallet) {
  655. $balanceAmount = $wallet->available_balance;
  656. $payAmount = $totalAmount - $balanceAmount;
  657. }
  658. }
  659. return [
  660. 'total_amount' => $totalAmount,
  661. 'balance_amount' => $balanceAmount,
  662. 'pay_amount' => $payAmount,
  663. 'coupon_amount' => $couponAmount,
  664. // 'tip_amount' => $tipAmount,
  665. 'project_amount' => $projectAmount,
  666. 'delivery_fee' => $deliveryFee,
  667. ];
  668. }
  669. /**
  670. * 指定技师
  671. */
  672. public function assignCoach($userId, $orderId, $coachId)
  673. {
  674. return DB::transaction(function () use ($userId, $orderId, $coachId) {
  675. // 参数校验
  676. $user = MemberUser::where('id', $userId)
  677. ->where('state', 'enable')
  678. ->firstOrFail();
  679. $order = Order::where('id', $orderId)
  680. ->where('user_id', $userId)
  681. ->whereIn('state', [0, 1, 6])
  682. ->firstOrFail();
  683. $coach = CoachUser::where('id', $coachId)
  684. ->where('state', 'enable')
  685. ->where('auth_state', 'passed')
  686. ->firstOrFail();
  687. // $schedule = CoachSchedule::where('coach_id', $coachId)
  688. // ->where('date', date('Y-m-d'))
  689. // ->where('state', 'free')
  690. // ->firstOrFail();
  691. // 修改订单
  692. $order->coach_id = $coachId;
  693. if ($order->state == 'created') {
  694. $amounts = $this->calculateOrderAmount($userId, $order->address_id, $coachId, $order->project_id, $order->agent_id, $order->payment_type == 'balance');
  695. $order->total_amount = $amounts['total_amount'];
  696. $order->balance_amount = $amounts['balance_amount'];
  697. $order->pay_amount = $amounts['pay_amount'];
  698. $order->coupon_amount = $amounts['coupon_amount'];
  699. // $order->tip_amount = $amounts['tip_amount'];
  700. $order->project_amount = $amounts['project_amount'];
  701. $order->delivery_fee = $amounts['delivery_fee'];
  702. if ($order->payment_type == 'balance') {
  703. $order->state = 'paid';
  704. }
  705. }
  706. if ($order->state == 'paid') {
  707. $order->state = 'assigned';
  708. }
  709. $order->save();
  710. // 创建订单历史
  711. OrderRecord::create([
  712. 'order_id' => $order->id,
  713. 'type' => 'assigned',
  714. 'user_id' => $userId,
  715. 'coach_id' => $coachId,
  716. ]);
  717. OrderRecord::create([
  718. 'order_id' => $order->id,
  719. 'type' => 'accepted',
  720. 'user_id' => $userId,
  721. 'coach_id' => $coachId,
  722. 'remark' => '抢单成功',
  723. ]);
  724. // 更新抢单池
  725. OrderGrabRecord::where('order_id', $orderId)
  726. ->update(['state' => 'success', 'coach_id' => $coachId]);
  727. // 更新排班
  728. // $schedule->state = 'busy';
  729. // $schedule->save();
  730. return true;
  731. });
  732. }
  733. }