OrderController.php 38 KB

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