OrderController.php 36 KB

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