OrderController.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mead
  5. * Date: 2019/8/19
  6. * Time: 2:11 PM
  7. */
  8. namespace App\Http\Controllers\V1;
  9. use App\Handlers\Activities\CouponActivityHandler;
  10. use App\Handlers\Activities\RidingCardActivityHandler;
  11. use App\Handlers\BaseBikeControl;
  12. use App\Handlers\BikeHandler;
  13. use App\Handlers\BikeStatusInfoSyncHandler;
  14. use App\Http\Requests\BikeCloseOrderRequest;
  15. use App\Http\Requests\OrderBikePositionRequest;
  16. use App\Http\Requests\OrderPayRequest;
  17. use App\Http\Requests\OrderPayShowRequest;
  18. use App\Http\Requests\RelayOrderAutoCloseRequest;
  19. use App\Http\Requests\RetryBikeRequest;
  20. use App\Maps\CacheMap;
  21. use App\Models\AreaSetting;
  22. use App\Models\Bike;
  23. use App\Models\CardRidingUserBags;
  24. use App\Models\CouponsUserBag;
  25. use App\Models\LocationLogMongodb;
  26. use App\Models\Order;
  27. use App\Models\OrderBikeOperate;
  28. use App\Models\WalletLog;
  29. use App\Repositories\AreaRepository;
  30. use App\Repositories\AreaSettingRepository;
  31. use App\Repositories\BikeRepository;
  32. use App\Repositories\CardRidingUserBagsRepository;
  33. use App\Repositories\LocationLogRepository;
  34. use App\Repositories\OrderBikeOperateRepository;
  35. use App\Repositories\OrderRepository;
  36. use App\Transformers\OrderPayTransformer;
  37. use App\Transformers\OrderTransformer;
  38. use Carbon\Carbon;
  39. use Dingo\Api\Http\Request;
  40. use EasyWeChat\Kernel\Exceptions\HttpException;
  41. use Illuminate\Support\Facades\Cache;
  42. use Illuminate\Support\Facades\DB;
  43. use Illuminate\Support\Facades\Log;
  44. use function EasyWeChat\Kernel\Support\generate_sign;
  45. /**
  46. * 临时订单管理
  47. * Class OrderController
  48. * @package App\Http\Controllers\V1
  49. */
  50. class OrderController extends BaseController
  51. {
  52. /**
  53. * 订单列表
  54. * @param Request $request
  55. * @param Order $order
  56. * @return \Dingo\Api\Http\Response|void
  57. * User: Mead
  58. */
  59. public function index(Request $request, Order $order)
  60. {
  61. try {
  62. $query = $order->query();
  63. if ($year = $request->get('year', date('Y'))) {
  64. $query->whereYear('created_at', $year);
  65. }
  66. if ($month = $request->get('month', date('m'))) {
  67. $query->whereMonth('created_at', $month);
  68. }
  69. $orders = $query->where('user_id', $this->user->id)->orderBy('id', 'desc')->paginate();
  70. $orders->appends($request->only(['year', 'month']))->withPath(config('app.url') . '/api/orders');
  71. return $this->response->paginator($orders, OrderTransformer::class);
  72. } catch (\Exception $exception) {
  73. return $this->errorException($exception->getMessage());
  74. }
  75. }
  76. /**
  77. * 支付页面
  78. * @param OrderPayShowRequest $request
  79. * @param OrderRepository $orderRepository
  80. * @return mixed
  81. * User: Mead
  82. */
  83. public function payShow(OrderPayShowRequest $request, OrderRepository $orderRepository, LocationLogRepository $locationLogRepository, AreaSettingRepository $areaSettingRepository, CouponActivityHandler $couponActivityHandler, CardRidingUserBagsRepository $cardRidingUserBagsRepository, RidingCardActivityHandler $ridingCardActivityHandler, OrderBikeOperateRepository $orderBikeOperateRepository)
  84. {
  85. try {
  86. $order_no = $request->get('order_no');
  87. $is_first = $request->get('is_first') ?? false;
  88. $couponUserBagsId = $request->get('coupon_user_bags_id') ?? '';
  89. $order = $orderRepository->byNoAndUserId($order_no, $this->user->id);
  90. // 骑行卡优惠
  91. $ridingCardActivityHandler->main($order);
  92. // 判断车是否在停车的区域
  93. if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_NO) {
  94. //检查车是否在停车位置
  95. if (((int)$order->is_admin_settle_order === Order::IS_ADMIN_SETTLE_ORDER_USER) && ($order->dispatch_money > 0) && (int)$order->status === Order::STATUS_CLOSE_BIKE) {
  96. $location = [];
  97. $is_in_time = (Carbon::now()->diffInSeconds(Carbon::parse($order->end_use_bike_time)) < 15);
  98. if ($is_in_time) {
  99. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG);
  100. } else {
  101. $location = $locationLogRepository->byOrderIdGetLastLocation($order->id, CacheMap::IS_OPEN_MONGODB_DUG);
  102. }
  103. // 判断是否在停车点
  104. if (!is_null($location['lat']) && ($location['lat'] > 0)) {
  105. $BikeHandler = new BikeHandler();
  106. $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id);
  107. if (!$is_huanche['status']) {
  108. // 不在还车点
  109. $setting = $areaSettingRepository->byAreaId($order->area_id);
  110. $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting);
  111. $order->dispatch_money = $dispatch_money;
  112. } else {
  113. $order->dispatch_money = 0;
  114. }
  115. $order->order_money = bcadd($order->time_money, $order->dispatch_money, 2);
  116. //计算优惠金额
  117. $order->order_money = bcsub($order->order_money, $order->preferential_money, 2);
  118. $order->pay_money = $order->order_money;
  119. }
  120. $is_in_parking = Bike::IN_PARKING_YES;
  121. if ($order->dispatch_money > 0) {
  122. $is_in_parking = Bike::IN_PARKING_NO;
  123. }
  124. if ($is_in_time) {
  125. Bike::where('id', $order->bike_id)->update([
  126. 'is_in_parking' => $is_in_parking
  127. ]);
  128. }
  129. }
  130. }
  131. if (bccomp($order->order_money, 0) === 0) {
  132. $order->status = Order::STATUS_COMPLETE_ORDER;
  133. if ($order->use_bike_time_length === 0) {
  134. $order->status = Order::STATUS_CLOSE_ORDER;
  135. }
  136. }
  137. $order->save();
  138. if ($is_first) {
  139. // 首次
  140. $data = $couponActivityHandler->isCouponsByOrder($order);
  141. if (empty($data['dataYes'])) {
  142. $userCoupons = [];
  143. } else {
  144. // 取最大优惠
  145. $userCoupons = $data['dataYes'][0];
  146. }
  147. } else {
  148. $userCoupons = $couponActivityHandler->getCouponsByOrderAndId($order, $couponUserBagsId);
  149. }
  150. $ridingCard = $cardRidingUserBagsRepository->isExist($this->user->id);
  151. // 能否选择优惠券
  152. $couponData = $couponActivityHandler->isCouponsByOrder($order);
  153. if (count($couponData['dataYes']) + count($couponData['dataNo']) > 0) {
  154. $is_coupon = true;
  155. } else {
  156. $is_coupon = false;
  157. }
  158. // 检查用户余额是否够
  159. $is_user_wallet = true;
  160. if (empty($userCoupons)) {
  161. if ($order->pay_money > $this->user->wallet_money) {
  162. // 余额不够
  163. $is_user_wallet = false;
  164. }
  165. } elseif ($userCoupons['order_wait_pay_money'] > $this->user->wallet_money) {
  166. // 余额不够
  167. $is_user_wallet = false;
  168. }
  169. $system_off_lock_text = '';
  170. if (in_array(Order::PREFERENTIAL_FREE_MINUTE, str2arr($order->preferential_type, '-'))) {
  171. $system_off_lock_text = $areaSettingRepository->byAreaIdGetFreeMinute($order->area_id) . '分钟内免费骑行';;
  172. }
  173. // 检查是否系统自动锁车
  174. $is_system_off_lock = $orderBikeOperateRepository->checkLowPowerOffLock($order->id);
  175. if ($is_system_off_lock) {
  176. $system_off_lock_text = $is_system_off_lock->name . ',敬请谅解,如有疑问请致电客服';
  177. }
  178. return $this->response->array([
  179. // 'order' => $order->append(['use_bike_time_length_text', 'pause_bike_time_length_text', 'use_bike_distance_length_text', 'end_use_bike_time_timestamp', 'preferential_type_name'])->toArray(),
  180. 'orders' => [
  181. 'id' => $order->id,
  182. 'no' => $order->no,
  183. 'bike_no' => $order->bike_no,
  184. 'use_bike_time_length_text' => $order->use_bike_time_length_text,
  185. 'use_bike_distance_length_text' => $order->use_bike_distance_length_text,
  186. 'end_use_bike_time_timestamp' => $order->end_use_bike_time_timestamp,
  187. 'pay_status' => $order->pay_status,
  188. 'pay_money' => $order->pay_money,
  189. 'time_money' => $order->time_money, // 时长费
  190. 'dispatch_money' => $order->dispatch_money, // 调度费
  191. 'distance_money' => $order->distance_money, // 里程费用
  192. 'order_money' => bcadd(bcadd($order->time_money, $order->distance_money, 2), $order->dispatch_money, 2),// 加调度费的总金额
  193. 'order_total_money' => bcadd($order->time_money, $order->distance_money, 2), // 不加调度费的总金额
  194. 'order_wait_pay_money' => empty($userCoupons) ? $order->order_money : $userCoupons['order_wait_pay_money'], // 总待支付
  195. 'total_preferential_money' => empty($userCoupons) ? $order->preferential_money : $userCoupons['total_preferential_money'], // 总优惠
  196. ],
  197. 'wallet_pay_status' => $is_user_wallet,
  198. 'wallet_money' => $this->user->wallet_money,
  199. 'user_coupon' => [
  200. 'is_coupon' => $is_coupon,
  201. 'coupon_preferential_money' => empty($userCoupons) ? '0.00' : $userCoupons['coupon_preferential_money'], // 优惠券优惠的金额
  202. 'coupon_user_bags_id' => empty($userCoupons) ? 0 : $userCoupons['id'],
  203. ],
  204. 'user_card' => [
  205. 'is_card' => empty($ridingCard) ? false : true,
  206. 'card' => $ridingCard,
  207. 'card_preferential_money' => $order->preferential_money, // 没支付之前优惠金额就是 骑行卡优惠的金额
  208. ],
  209. 'system_off_lock' => [
  210. 'is_system_off_lock' => empty($system_off_lock_text) ? false : true,
  211. 'system_off_lock_text' => $system_off_lock_text
  212. ],
  213. ]);
  214. } catch (\Exception $exception) {
  215. return $this->errorException($exception->getMessage());
  216. }
  217. }
  218. /**
  219. * 订单详情页
  220. * @param OrderPayShowRequest $request
  221. * @param OrderRepository $orderRepository
  222. * @return \Dingo\Api\Http\Response
  223. * User: Mead
  224. */
  225. public function show(OrderPayShowRequest $request, OrderRepository $orderRepository)
  226. {
  227. try {
  228. $order_no = $request->get('order_no');
  229. $order = $orderRepository->byNoAndUserId($order_no, $this->user->id);
  230. if (!$order) return $this->errorNoValidation('找不到该订单');
  231. return $this->response->item($order, new OrderPayTransformer());
  232. } catch (\Exception $exception) {
  233. return $this->errorException($exception->getMessage());
  234. }
  235. }
  236. /**
  237. * 订单支付
  238. * @param OrderPayRequest $request
  239. * @param OrderRepository $orderRepository
  240. * User: Mead
  241. */
  242. public function pay(OrderPayRequest $request, OrderRepository $orderRepository, CouponActivityHandler $couponActivityHandler, RidingCardActivityHandler $ridingCardActivityHandler)
  243. {
  244. try {
  245. $pay_type = $request->get('pay_type');
  246. $order_no = $request->get('order_no');
  247. $couponUserBagsId = $request->get('coupon_user_bags_id') ?? '';
  248. $order = $orderRepository->byNo($order_no);
  249. if (!$order) return $this->errorBadRequest('订单不存在');
  250. if ((int)$order->pay_status === Order::PAY_STATUS_OK) return $this->errorNoValidation('订单已支付');
  251. if (in_array($order->status, [Order::STATUS_PAUSE_BIKE, Order::STATUS_RIDE_BIKE])) return $this->errorNoValidation('订单状态可能出在骑行中,请先锁车');
  252. $user = $this->user;
  253. if ($order->user_id !== $user->id) return $this->errorNoValidation('非法操作');
  254. $user_id = $user['id'];
  255. $cache_key = "PAY_ORDER_{$user_id}";
  256. if (Cache::has($cache_key)) {
  257. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  258. }
  259. Cache::put($cache_key, 1, Carbon::now()->addSeconds(5));
  260. // 骑行卡优惠
  261. $ridingCardActivityHandler->main($order);
  262. // 优惠券优惠
  263. $couponActivityHandler->main($order, $couponUserBagsId);
  264. $order->save();
  265. $response = '';
  266. switch ($pay_type) {
  267. case Order::PAY_TYPE_ACCOUNT:
  268. //余额支付
  269. if ($order->order_money > $this->user->wallet_money) {
  270. // 余额不够
  271. return $this->errorNoValidation('用户余额不够');
  272. }
  273. DB::transaction(function () use ($order, $user, $couponUserBagsId) {
  274. //添加钱包记录
  275. WalletLog::log(WalletLog::OPERATE_TYPE_SUB, $order->order_money, $user->id, WalletLog::TYPE_SUB_WALLET_BIKE_ORDER, $order->area_id, $order->id, Order::class);
  276. //修改订单记录
  277. $order->pay_status = Order::PAY_STATUS_OK;
  278. $order->pay_time = now();
  279. $order->pay_type = Order::PAY_TYPE_ACCOUNT;
  280. $order->pay_money = $order->order_money;
  281. $order->status = Order::STATUS_COMPLETE_ORDER;
  282. if ($order->is_coupon == Order::COUPON_OK) {
  283. CouponsUserBag::useCoupon($order->id, $couponUserBagsId);
  284. // 优惠方式
  285. if ($order->preferential_type == 0) {
  286. $order->preferential_type = arr2str([Order::PREFERENTIAL_COUPON], '-');
  287. } else {
  288. $arr = str2arr($order->preferential_type, '-');
  289. $order->preferential_type = arr2str(array_merge($arr, [Order::PREFERENTIAL_COUPON]), '-');
  290. }
  291. // 更新订单得优惠金额
  292. $order->coupon_user_bags_id = $couponUserBagsId;
  293. $order->preferential_money = bcsub(bcadd($order->time_money, $order->dispatch_money, 2), $order->pay_money, 2);
  294. // 更新优惠券优惠金额
  295. $order->coupon_preferential_money = bcsub($order->preferential_money, $order->card_preferential_money, 2);
  296. }
  297. $order->save();
  298. });
  299. $response = [
  300. 'pay_order_status' => true
  301. ];
  302. break;
  303. case Order::PAY_TYPE_WECHAT:
  304. //微信支付
  305. $payment = app('wechat.payment'); // 微信支付
  306. $username = $user->truename;
  307. $auth = $user->auth;
  308. $result = $payment->order->unify([
  309. 'body' => "用户支付临时骑行订单-" . config('app.name', '未来bike'),
  310. 'out_trade_no' => $order->no,
  311. 'trade_type' => 'JSAPI', // 必须为JSAPI
  312. 'openid' => $auth['credential'], // 这里的openid为付款人的openid
  313. 'total_fee' => wechat_fee($order->order_money), // 总价
  314. 'attach' => makeNoTag(Order::NO_TAG)
  315. ]);
  316. if ($result['return_code'] === 'FAIL') return $this->errorNoValidation('下单失败');
  317. // 如果成功生成统一下单的订单,那么进行二次签名
  318. if ($result['result_code'] === 'FAIL') {
  319. //判断是否重复下单
  320. if ($result['err_code'] === 'INVALID_REQUEST') {
  321. $order->no = Order::makeNo();
  322. $order->save();
  323. $result = $payment->order->unify([
  324. 'body' => "用户支付临时骑行订单-" . config('app.name', '未来bike'),
  325. 'out_trade_no' => $order->no,
  326. 'trade_type' => 'JSAPI', // 必须为JSAPI
  327. 'openid' => $auth['credential'], // 这里的openid为付款人的openid
  328. 'total_fee' => wechat_fee($order->order_money), // 总价
  329. 'attach' => makeNoTag(Order::NO_TAG)
  330. ]);
  331. } else {
  332. return $this->errorNoValidation('下单失败');
  333. }
  334. }
  335. // 二次签名的参数必须与下面相同
  336. $params = [
  337. 'appId' => $auth['identifier'],
  338. 'timeStamp' => time(),
  339. 'nonceStr' => $result['nonce_str'],
  340. 'package' => 'prepay_id=' . $result['prepay_id'],
  341. 'signType' => 'MD5',
  342. ];
  343. // config('wechat.payment.default.key')为商户的key
  344. $params['paySign'] = generate_sign($params, config('wechat.payment.default.key'));
  345. $response = $params;
  346. $response['order_no'] = $order->no;
  347. break;
  348. default:
  349. return $this->errorBadRequest('支付类型不对');
  350. break;
  351. }
  352. return $this->response->array($response);
  353. } catch (\Exception $exception) {
  354. return $this->errorException($exception->getMessage());
  355. }
  356. }
  357. /**
  358. * 重试开车
  359. * @param Request $request
  360. * @param OrderRepository $orderRepository
  361. * @param BikeRepository $bikeRepository
  362. * User: Mead
  363. */
  364. public function retryOpenLock(RetryBikeRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository)
  365. {
  366. try {
  367. $order_no = $request->get('order_no');
  368. $bike_no = $request->get('bike_no');
  369. $order = $orderRepository->checkUserIsRetryOpenLock($order_no, $bike_no, $this->user->id);
  370. if (!$order) return $this->errorNoValidation('没有此订单');
  371. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time));
  372. if ($second > 60) {
  373. return $this->errorNoValidation('暂不能操作开车');
  374. }
  375. $box_no = $bikeRepository->byIdGetBoxNo($order->bike_id);
  376. if (!$box_no) return $this->errorNoValidation('找不到该车');
  377. (new BaseBikeControl($box_no))::openLock();
  378. return $this->response->array([
  379. 'status' => 1
  380. ]);
  381. } catch (\Exception $exception) {
  382. return $this->errorNoValidation($exception->getMessage());
  383. }
  384. }
  385. /**
  386. * 重试锁车
  387. * @param Request $request
  388. * @param OrderRepository $orderRepository
  389. * @param BikeRepository $bikeRepository
  390. * User: Mead
  391. */
  392. public function retryCloseLock(RetryBikeRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository)
  393. {
  394. try {
  395. $order_no = $request->get('order_no');
  396. $bike_no = $request->get('bike_no');
  397. $order = $orderRepository->checkUserIsRetryOpenLock($order_no, $bike_no, $this->user->id);
  398. if (!$order) return $this->errorNoValidation('没有此订单');
  399. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->end_use_bike_time));
  400. if ($second > 60) {
  401. return $this->errorNoValidation('暂不能操作关车');
  402. }
  403. $box_no = $bikeRepository->byIdGetNoRidingBoxNo($order->bike_id);
  404. if (!$box_no) return $this->errorNoValidation('找不到该车,或咱不能操作该车');
  405. (new BaseBikeControl($box_no))::closeLock();
  406. return $this->response->array([
  407. 'status' => 1
  408. ]);
  409. } catch (\Exception $exception) {
  410. return $this->errorNoValidation($exception->getMessage());
  411. }
  412. }
  413. /**
  414. * 临时停车时寻铃
  415. * @param Request $request
  416. * @param OrderRepository $orderRepository
  417. * @param BikeRepository $bikeRepository
  418. * User: Mead
  419. */
  420. public function retryBellLock(RetryBikeRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository)
  421. {
  422. try {
  423. $order_no = $request->get('order_no');
  424. $bike_no = $request->get('bike_no');
  425. $order = $orderRepository->checkUserIsRetryOpenLock($order_no, $bike_no, $this->user->id);
  426. if (!$order) return $this->errorNoValidation('没有此订单');
  427. $box_no = $bikeRepository->byNoGetBoxNO($bike_no);
  428. $re = (new BaseBikeControl($box_no))::bellBike();
  429. return $this->response->array([
  430. 'is_ok' => $re
  431. ]);
  432. } catch (\Exception $exception) {
  433. return $this->errorNoValidation($exception->getMessage());
  434. }
  435. }
  436. /**
  437. * 系统自动关闭订单(replay端接口)
  438. * User: Mead
  439. */
  440. public function autoCloseOrder(RelayOrderAutoCloseRequest $request, OrderRepository $orderRepository, BikeRepository $bikeRepository, LocationLogRepository $locationLogRepository, AreaSettingRepository $areaSettingRepository)
  441. {
  442. try {
  443. $bike_no = $request->get('bike_no');
  444. $box_no = $request->get('box_no');
  445. $type = $request->get('type');
  446. $key = $request->get('key');
  447. if ($key !== config('auth.api_token')) {
  448. return $this->error('key不对');
  449. }
  450. $is_bike = $bikeRepository->byBoxNoAndBikeNoCheckRide($box_no, $bike_no);
  451. if (!$is_bike) {
  452. return $this->error('找不到该车');
  453. }
  454. $order = $orderRepository->byBikeNoGetRideOrder($bike_no);
  455. if (!$order) {
  456. return $this->error('找不到合适的订单');
  457. }
  458. //获取车的最后位置
  459. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG);
  460. // 更新车的信息
  461. $bikeModel = $bikeRepository->byIdGetModel($order->bike_id);
  462. $bikeModel->is_riding = Bike::RIDING_NO;
  463. $bikeModel->last_use_bike_end_time = date('Y-m-d H:i:s');
  464. $bikeModel->save();
  465. (new BikeStatusInfoSyncHandler())->toBikeWaitRideStatus($bike_no, $location['lng'], $location['lat']);
  466. // 判断是否经常这样操作(未做)
  467. (new BaseBikeControl($box_no))::closeLock();
  468. // 记录日志信息
  469. OrderBikeOperate::log($order->id, OrderBikeOperate::TYPE_CLONE_BIKE, $order->bike_id, $order->user_id, $location['lat'], $location['lng'], OrderBikeOperate::IS_ADMIN_SYSTEM, "[系统自动:{$type}]");
  470. // 保存轨迹信息
  471. $setting = $areaSettingRepository->byAreaId($order->area_id);
  472. // 是否处于临时停车的状态
  473. if ((int)$order->status === Order::STATUS_PAUSE_BIKE) {
  474. $order->pause_bike_time_length += Carbon::now()->diffInMinutes(Carbon::parse($order->pause_bike_time));
  475. }
  476. $order->status = Order::STATUS_CLOSE_BIKE;
  477. $order->end_use_bike_time = now();
  478. $order->end_use_bike_location = [
  479. 'latitude' => $location['lat'],
  480. 'longitude' => $location['lng'],
  481. ];
  482. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time));
  483. //计算用车时间
  484. $order->use_bike_time_length = ceil($second / 60);
  485. // 计算价格
  486. if (bccomp($setting->starting_price_time, $order->use_bike_time_length) >= 0) {
  487. // 起步价时间内只收起步价
  488. $time_money = $setting->starting_price;
  489. } else {
  490. $time_money = $setting->per_money * ceil(bcsub($order->use_bike_time_length, $setting->starting_price_time) / $setting->per_minute);
  491. $time_money = bcadd($time_money, $setting->starting_price, 2);
  492. }
  493. // $time_money = $setting->per_money * ceil($order->use_bike_time_length / $setting->per_minute);
  494. // 计算是否在免费分钟内
  495. if ($setting->is_minute_free == AreaSetting::FREE_MINUTE_OK && $setting->many_minute_free >= $order->use_bike_time_length) {
  496. if ($setting->minute_free_times == 0) {
  497. $time_money = 0;
  498. if ($order->preferential_type == 0) {
  499. $order->preferential_type = arr2str([Order::PREFERENTIAL_FREE_MINUTE], '-');
  500. } else {
  501. $arr = str2arr($order->preferential_type, '-');
  502. $order->preferential_type = arr2str(array_merge($arr, [Order::PREFERENTIAL_FREE_MINUTE]), '-');
  503. }
  504. } else {
  505. $key = sprintf(CacheMap::FREE_MINUTE_USER_ID, $order->user_id);
  506. app()->redis->sadd($key, $order->id);
  507. app()->redis->expireat($key, Carbon::tomorrow()->timestamp);
  508. if (app()->redis->scard($key) <= $setting->minute_free_times) {
  509. $time_money = 0;
  510. if ($order->preferential_type == 0) {
  511. $order->preferential_type = arr2str([Order::PREFERENTIAL_FREE_MINUTE], '-');
  512. } else {
  513. $arr = str2arr($order->preferential_type, '-');
  514. $order->preferential_type = arr2str(array_merge($arr, [Order::PREFERENTIAL_FREE_MINUTE]), '-');
  515. }
  516. }
  517. }
  518. }
  519. if ($time_money < 0) {
  520. $time_money = 0;
  521. }
  522. //计算骑行距离
  523. $order->use_bike_distance_length = bcdiv($location['mileage'], 1000, 2);
  524. // 判断车是否在停车的区域
  525. $order->dispatch_money = 0;
  526. if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_NO) {
  527. $BikeHandler = new BikeHandler();
  528. $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id);
  529. $bikeModel->is_in_parking = Bike::IN_PARKING_YES;
  530. if (!$is_huanche['status']) {
  531. // 不在还车点
  532. $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting);
  533. $order->dispatch_money = $dispatch_money;
  534. $bikeModel->is_in_parking = Bike::IN_PARKING_NO;
  535. }
  536. } else {
  537. //全区域内可停
  538. $bikeModel->is_in_parking = Bike::IN_PARKING_YES;
  539. }
  540. $order->time_money = $time_money;
  541. $order->pause_money = 0;
  542. $order->preferential_money = 0;
  543. $order->order_money = bcadd($time_money, $order->dispatch_money, 2);
  544. $order->pay_money = $order->order_money;
  545. $order->pay_type = Order::PAY_STATUS_NO;
  546. $order->is_admin_settle_order = Order::IS_ADMIN_SETTLE_ORDER_SYSTEM;
  547. $order->save();
  548. $bikeModel->save();
  549. (new BaseBikeControl($box_no))::closeLock();
  550. return $this->success();
  551. } catch (HttpException $exception) {
  552. return $this->error($exception->getMessage());
  553. }
  554. }
  555. /**
  556. * 骑行订单车辆位置 orderBikePosition
  557. *
  558. * @param OrderBikePositionRequest $request
  559. * @return void
  560. * @author Fx
  561. *
  562. */
  563. public function orderBikePosition(OrderBikePositionRequest $request)
  564. {
  565. try {
  566. $bike_no = $request->get('bike_no');
  567. $position = LocationLogMongodb::getNewestLocationByBikeNo($bike_no);
  568. // Log::info($position);
  569. return $this->response->array($position);
  570. } catch (\Exception $exception) {
  571. return $this->errorException($exception->getMessage());
  572. }
  573. }
  574. /**
  575. *
  576. * Author: Mead
  577. */
  578. public function expectOrderMoney(BikeCloseOrderRequest $request, BikeRepository $bikeRepository, OrderRepository $orderRepository, AreaSettingRepository $areaSettingRepository, LocationLogRepository $locationLogRepository)
  579. {
  580. $bike_no = $request->get('bike_no');
  581. $order_no = $request->get('order_no');
  582. $lat = $request->get('lat');
  583. $lng = $request->get('lng');
  584. try {
  585. $order = $orderRepository->byNo($order_no);
  586. if (!$order) return $this->errorBadRequest('非法请求');
  587. $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time));
  588. if ($second < AreaSetting::CLOSE_BIKE_TIME) {
  589. //小于60秒直接锁车
  590. return [
  591. 'dispatch_money' => 0,
  592. 'time_money' => 0,
  593. 'total_money' => 0
  594. ];
  595. }
  596. $user_id = $this->user['id'];
  597. $cache_key = "EXPECT_ORDER_MONEY_{$user_id}";
  598. if (Cache::has($cache_key)) {
  599. return $this->errorNoValidation('您提交的太频繁了,请一会再提交!');
  600. }
  601. Cache::put($cache_key, 1, Carbon::now()->addSeconds(3));
  602. $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no);
  603. (new BaseBikeControl($box_no))::nowBikeLocation();
  604. $setting = $areaSettingRepository->byAreaId($order->area_id);
  605. $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG);
  606. if ($location['lat'] <= 0) {
  607. $location['lat'] = $lat;
  608. $location['lng'] = $lng;
  609. }
  610. //计算用车时间
  611. $use_bike_time_length = ceil($second / 60);
  612. // 计算价格
  613. if (bccomp($setting->starting_price_time, $use_bike_time_length) >= 0) {
  614. // 起步价时间内只收起步价
  615. $time_money = $setting->starting_price;
  616. } else {
  617. $time_money = $setting->per_money * ceil(bcsub($use_bike_time_length, $setting->starting_price_time) / $setting->per_minute);
  618. $time_money = bcadd($time_money, $setting->starting_price, 2);
  619. }
  620. // $time_money = floatval($setting->per_money * ceil($use_bike_time_length / $setting->per_minute));
  621. // //免费时长
  622. // if ($setting->is_minute_free == AreaSetting::FREE_MINUTE_OK && $setting->many_minute_free >= $use_bike_time_length) {
  623. // if ($setting->minute_free_times == 0) {
  624. // $time_money = 0;
  625. // } else {
  626. // $key = sprintf(CacheMap::FREE_MINUTE_USER_ID, $order->user_id);
  627. // if (app()->redis->scard($key) < $setting->minute_free_times) {
  628. // $time_money = 0;
  629. // }
  630. // }
  631. // }
  632. if ($time_money < 0) {
  633. $time_money = 0;
  634. }
  635. //计算骑行距离
  636. // $use_bike_distance_length = bcdiv($location['mileage'], 1000, 2);
  637. // $distance_money = 0;
  638. $BikeHandler = new BikeHandler();
  639. //判断是否全区域内可停
  640. if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_OK) {
  641. return [
  642. 'dispatch_money' => 0,
  643. 'time_money' => $time_money,
  644. 'total_money' => $time_money
  645. ];
  646. }
  647. // 判断是否在停车点
  648. $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id, $lat, $lng);
  649. if (!$is_huanche['status']) {
  650. (new BaseBikeControl($box_no))::nowBikeLocation();
  651. // 不在还车点
  652. $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting);
  653. return [
  654. 'dispatch_money' => $dispatch_money,
  655. 'time_money' => $time_money,
  656. 'total_money' => floatval(bcadd($dispatch_money, $time_money, 2))
  657. ];
  658. }
  659. return [
  660. 'dispatch_money' => 0,
  661. 'time_money' => $time_money,
  662. 'total_money' => $time_money
  663. ];
  664. } catch (HttpException $exception) {
  665. return $this->errorNoValidation($exception->getMessage());
  666. }
  667. }
  668. }