get('type'); $bike_no = $request->get('bike_no'); $area_id = $request->get('area_id'); $lat = $request->get('lat'); $lng = $request->get('lng'); $cache_key = "OPEN_RENT_BIKE_ORDER_{$bike_no}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(5)); $bike = $bikeRepository->byNoIsCanRentBikeGetModel($bike_no); if (!$bike) { return $this->errorNoValidation('该车暂不能用'); } //以车的区域为主 if ($bike->put_area_id !== $area_id) { $area_id = $bike->put_area_id; } $setting = $areaSettingRepository->byAreaId($area_id); $user = $this->user; // 判断区域是否需要缴纳押金 if($setting['is_deposit'] == AreaSetting::DEPOSIT_OK) { // 判断用户押金,授权,认证,手机号状态是否正常 if (User::DEPOSIT_NO === (int)$user->is_deposit) { return $this->errorNoValidation('请您先交纳押金'); } } // if ((int)$user->deposit_type === User::DEPOSIT_CARD && (int)$user->is_deposit === User::DEPOSIT_OK) { // // 押金类型为免押金卡 判断是否过期 // if (!$userRepository->isDepositCardExpired($user->id)) { // return $this->errorNoValidation('免押金卡已到期,请您先交纳押金'); // } // } if (User::BIND_MOBILE_NO === (int)$user->is_bind_mobile) { return $this->errorNoValidation('请先绑定您的手机号'); } if (User::CARD_NO === (int)$user->is_card_certified) { return $this->errorNoValidation('请您先完善实名认证'); } if (User::RIDE_BIKE_AGE_NO === (int)$user->is_match_ride_age) { return $this->errorNoValidation('未成年人禁止骑车'); } if (!$setting->is_open_day_rent) { return $this->errorNoValidation('该区域租车暂不开放,敬请期待!'); } $punish = $punishmentOrderRepository->checkNoPayModel($user->id); if (!$punish) return $this->errorNoValidation('您有罚单未支付,请先处理'); // 判断用户是否有为支付的订单 if ($orderRepository->byUserIdCheckIsExistRideOrder($user->id)) { return $this->errorNoValidation('您有未完成的订单,请先处理'); } if ($rentOrderRepository->byUserIdCheckIsExistRideOrder($user->id)) { return $this->errorNoValidation('您有未完成的租车订单,请先处理'); } // 判断用户是否在车的距离范围内 $options = ['SORT' => 'ASC']; $redis = Redis::connection(); $nearby_bikes = $redis->georadius(Bike::REDIS_BIKE_LOCATION_TAG, $lng, $lat, 1, 'km', $options); if (!in_array($bike->bike_no, $nearby_bikes)) { return $this->errorNoValidation('小主,咱俩有点远!'); } $user_id = $this->user->id; $cache_key = "RIDE_RENT_ORDER_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); //不同类型处理价格(暂不用) // 下单 $rent_money = $setting->day_rent_money; $users = User::find($user['id']); $settingConfig = [ 'rent_money' => $setting->day_rent_money, 'rent_time' => $setting->day_rent_hours, 'over_rent_time_money' => $setting->per_hours_day_rent_timeout_money, 'over_rent_time_max_money' => $setting->day_rent_capping_money, ]; $data = [ 'user_id' => $user['id'], 'no' => RentOrder::makeNo(), 'type' => RentOrder::TYPE_DAY_RENT, 'bike_no' => $bike_no, 'bike_id' => $bike->id, 'area_id' => $area_id, 'phone_detail' => $users->userPhoneDetail->detail ?? '', 'start_use_bike_location' => [ 'latitude' => $lat, 'longitude' => $lng, ], 'rent_money' => $rent_money, 'rent_preferential_money' => 0.00, 'rent_total_money' => $rent_money, 'status' => RentOrder::STATUS_WAIT_PAY_RENT_MONEY, 'setting' => $settingConfig, ]; $order = RentOrder::create($data); // $this->dispatch(new CloseRentOrderJob($order, Carbon::now()->addMinutes(10))); // 更新用户的区域id if (!$user->register_area_id) { $user->register_area_id = $area_id; $user->save(); } $order->status = RentOrder::STATUS_RENT_BIKE; $order->start_use_bike_time = now(); $order->return_end_bike_time = Carbon::now()->addHours($settingConfig['rent_time'])->toDateTimeString(); $order->save(); $bike->is_rent = Bike::RENT_YES; $bike->is_riding = Bike::RIDING_YES; $bike->save(); //同步redis (new BikeStatusInfoSyncHandler())->toBikeRideStatus(BikeStatusInfoSyncHandler::ROLE_USER, $bike->bike_no, [ 'id' => $order->id, 'bike_id' => $order->bike_id, 'area_id' => $order->area_id, 'is_rent' => 1, ]); $params['no'] = $order->no; return $this->response->array($params); } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } public function useOrder(Request $request, RentOrderRepository $rentOrderRepository) { try { $no = $request->get('no'); $order = $rentOrderRepository->byNo($no); return $this->response->item($order, RentUseOrderTransformer::class); } catch (\Exception $exception) { } } /** * @param Request $request * @param RentOrderRepository $rentOrderRepository * * @return \Dingo\Api\Http\Response * User: Mead */ public function show(Request $request, RentOrderRepository $rentOrderRepository) { try { $no = $request->get('no'); $order = $rentOrderRepository->byNo($no); return $this->response->item($order, new RentOrderTransformer()); } catch (\Exception $exception) { } } /** * 结束租车 * User: Mead. */ public function closeOrder(Request $request, RentOrderRepository $rentOrderRepository, BikeRepository $bikeRepository, LocationLogRepository $locationLogRepository, AreaSettingRepository $areaSettingRepository) { try { $bike_no = $request->get('bike_no'); $order_no = $request->get('order_no'); $lat = $request->get('lat'); $lng = $request->get('lng'); $order = $rentOrderRepository->byNoGetRideOrder($order_no); if (!$order) { return $this->errorNoValidation('订单不存在或订单已结算'); } if (Bike::RIDING_YES === (int)$order->bike_is_riding) { return $this->errorNoValidation('请先关锁再还车'); } if ($rentOrderRepository->checkUserMoreCloseOrder($this->user->id)) { return $this->errorNoValidation('您今天太频繁操作车辆'); } $user_id = $this->user->id; $cache_key = "RIDE_CLOSE_RENT_ORDER_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); //获取车的最后位置 $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG); if ($location['lat'] <= 0) { $location['lat'] = $order->end_use_bike_location['latitude']; $location['lng'] = $order->end_use_bike_location['longitude']; if ($location['lat'] <= 0) { $location['lat'] = $lat; $location['lng'] = $lng; } } // 更新车的信息 $bikeModel = $bikeRepository->byIdGetModel($order->bike_id); $bikeModel->is_riding = Bike::RIDING_NO; $bikeModel->is_rent = Bike::RENT_NO; $bikeModel->save(); //更新redis (new BikeStatusInfoSyncHandler())->toBikeWaitRideStatus($order->bike_no, $location['lng'], $location['lat']); // 判断是否经常这样操作(未做) $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time)); if ($second <= AreaSetting::CLOSE_BIKE_TIME) { // 关闭订单 $order->status = RentOrder::STATUS_CLOSE_ORDER; $order->end_use_bike_location = [ 'latitude' => $lat, 'longitude' => $lng, ]; $order->end_use_bike_time = now(); $order->rent_money = 0; $order->save(); //退钱 // 记录临时关锁 return $this->response->item($order, RentOrderTransformer::class); } //检查是否在禁停区 $BikeHandler = new BikeHandler(); $is_ban_stop_bike = $BikeHandler->byLocationCheckIsInBanStopParking($location['lat'], $location['lng'], $order->area_id, $lat, $lng); if ($is_ban_stop_bike) { return $this->errorNoValidation('禁停区域内禁止停车!'); } // 结束订单 $setting = $order->setting; $money = 0.00; $over_hours = 0; //是否需要收取超出费用 $is_over_time = (strtotime($order->return_end_bike_time) < time()); if ($is_over_time) { //超出时间 $over_hours = ceil(Carbon::now()->diffInMinutes(Carbon::parse($order->return_end_bike_time)) / 60); $hours = ceil(Carbon::now()->diffInMinutes(Carbon::parse($order->start_use_bike_time)) / 60); if ($hours > 24) { //超过1天 $day = ceil($hours / 24); $end_hours = $hours % 24; //日封顶租金*天 $money = bcmul($setting['over_rent_time_max_money'], ($day - 1), 2); // $money = bcadd($money, $setting['rent_money'], 2); if ($end_hours > $setting['rent_time']) { // 超过一天 又超过8小时 // (超时费 + 日封顶租金*天) $money = bcadd(bcmul(($end_hours - $setting['rent_time']), $setting['over_rent_time_money'], 2), $money, 2); } } else { // 不超过1天 但是超过8小时 $money = bcmul($over_hours, $setting['over_rent_time_money'], 2); // (超时费 + 基础租金) 是否大于日封顶租金 $total_money = bcadd($money, $setting['rent_money'], 2); if ($total_money > $setting['over_rent_time_max_money']) { $money = bcsub($setting['over_rent_time_max_money'], $setting['rent_money'], 2); } } } //计算骑行距离 $order->use_bike_distance_length = bcdiv($location['mileage'], 1000, 2); // 日租结算 $order->time_money = $money; $order->distance_money = 0.00; $order->preferential_money = 0.00; $order->over_hours = $over_hours; // 租金 + 超时费 $order->total_money = bcadd($money, $order->rent_money, 2); $order->pay_money = $order->total_money; //判断是否收取调度费 if ($order->dispatch_money > 0) { $order->total_money = bcadd($order->total_money, $order->dispatch_money, 2); } if ($order->total_money > 0) { $order->status = RentOrder::STATUS_CLOSE_RENT_BIKE; } else { $order->status = RentOrder::STATUS_COMPLETE_ORDER; } //计算用车时间 (分) $order->use_bike_time_length = ceil($second / 60); // 车辆最后位置 (防止定位失败的情况) if (empty($order->end_use_bike_location)) { $order->end_use_bike_location = [ 'latitude' => $lat, 'longitude' => $lng, ]; } $order->end_use_bike_time = Carbon::now(); $order->order_total_money = $order->total_money; $order->save(); // 删除redis订单 if (RentOrder::STATUS_COMPLETE_ORDER === (int)$order->status) { (new BikeStatusInfoSyncHandler())->toBikeWaitRideStatus($order->bike_no, $location['lng'], $location['lat']); } return $this->response->item($order, RentOrderTransformer::class); } catch (HttpException $exception) { return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode()); } } public function payShow(Request $request, RentOrderRepository $rentOrderRepository, RentOrderBikeOperateRepository $rentOrderBikeOperateRepository) { try { $order_no = $request->get('order_no'); $order = $rentOrderRepository->byNoAndUserId($order_no, $this->user->id); if (!$order) { return $this->errorNoValidation('订单不存在!'); } // 检查用户余额是否够 $is_user_wallet = true; if ($order->pay_money > $this->user->wallet_money) { // 余额不够 $is_user_wallet = false; } if (bccomp($order->total_money, 0) === 0) { $order->pay_type = RentOrder::PAY_STATUS_OK; $order->status = RentOrder::STATUS_CLOSE_ORDER; } $order->save(); // 检查是否系统自动锁车 $is_system_off_lock = $rentOrderBikeOperateRepository->checkLowPowerOffLock($order->id); $is_coupon = false; $userCoupons = []; $ridingCard = []; return $this->response->array([ 'order' => $order->append(['use_bike_time_length_text', 'use_bike_distance_length_text', 'end_use_bike_time_timestamp'])->toArray(), 'orders' => [ 'id' => $order->id, 'no' => $order->no, 'bike_no' => $order->bike_no, 'use_bike_time_length_text' => $order->use_bike_time_length_text, 'use_bike_distance_length_text' => $order->use_bike_distance_length_text, 'end_use_bike_time_timestamp' => $order->end_use_bike_time_timestamp, 'pay_status' => $order->pay_status, 'pay_money' => $order->pay_money, 'time_money' => $order->time_money, // 时长费 'rent_money' => $order->rent_money, // 租费 'dispatch_money' => $order->dispatch_money, // 调度费 'distance_money' => $order->distance_money, // 里程费用 'total_money' => $order->total_money,// 加调度费的总金额 'order_total_money' => bcadd($order->rent_money, $order->time_money, 2), // 不加调度费的总金额 'order_wait_pay_money' => empty($userCoupons) ? $order->total_money : $userCoupons['order_wait_pay_money'], // 总待支付 'total_preferential_money' => empty($userCoupons) ? $order->preferential_money : $userCoupons['total_preferential_money'], // 总优惠 ], 'wallet_pay_status' => $is_user_wallet, 'wallet_money' => $this->user->wallet_money, 'user_coupon' => [ 'is_coupon' => $is_coupon, 'coupon_preferential_money' => empty($userCoupons) ? '0.00' : $userCoupons['coupon_preferential_money'], // 优惠券优惠的金额 'coupon_user_bags_id' => empty($userCoupons) ? 0 : $userCoupons['id'], ], 'user_card' => [ 'is_card' => empty($ridingCard) ? false : true, 'card' => $ridingCard, 'card_preferential_money' => $order->preferential_money, // 没支付之前优惠金额就是 骑行卡优惠的金额 ], 'system_off_lock' => [ 'is_system_off_lock' => empty($is_system_off_lock) ? false : true, 'system_off_lock_text' => '电量过低,系统自动还车,敬请谅解,如有疑问请致电客服' ], ]); } catch (\Exception $exception) { return $this->errorException($exception->getMessage()); } } public function pay(Request $request, RentOrderRepository $rentOrderRepository) { try { $pay_type = $request->get('pay_type'); $order_no = $request->get('order_no'); $order = $rentOrderRepository->byNo($order_no); if (!$order) { return $this->errorBadRequest('订单不存在'); } if (RentOrder::STATUS_COMPLETE_ORDER === (int)$order->status) { return $this->errorNoValidation('订单已完成'); } if (RentOrder::STATUS_CLOSE_ORDER === (int)$order->status) { return $this->errorNoValidation('订单已关闭'); } if (RentOrder::PAY_STATUS_OK === (int)$order->pay_status) { return $this->errorNoValidation('订单已支付'); } if (RentOrder::STATUS_RENT_BIKE === (int)$order->status) { return $this->errorNoValidation('请先结束租车订单,再支付'); } $user = $this->user; if ($order->user_id !== $user->id) { return $this->errorNoValidation('非法操作'); } $response = ''; $user_id = $user['id']; $cache_key = "PAY_RENT_ORDER_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(5)); switch ($pay_type) { case RentOrder::PAY_TYPE_ACCOUNT: //余额支付 if (bccomp($order->total_money, $this->user->wallet_money) === 1) { // 余额不够 return $this->errorNoValidation('用户余额不够'); } DB::transaction(function () use ($order, $user) { //添加钱包记录 WalletLog::log(WalletLog::OPERATE_TYPE_SUB, $order->total_money, $user->id, WalletLog::TYPE_SUB_WALLET_RENT_ORDER_MONEY, $order->area_id, $order->id, RentOrder::class); //修改订单记录 $order->pay_status = RentOrder::PAY_STATUS_OK; $order->pay_money = $order->total_money; $order->pay_time = now(); $order->pay_type = RentOrder::PAY_TYPE_ACCOUNT; $order->status = RentOrder::STATUS_COMPLETE_ORDER; $order->order_total_money = $order->total_money; $order->save(); }); $response = [ 'pay_order_status' => true, ]; break; case RentOrder::PAY_TYPE_WECHAT: //微信支付 $payment = app('wechat.payment'); // 微信支付 $username = $user->truename; $auth = $user->auth; $order->over_no = RentOrder::makeOverNo(); $order->save(); $result = $payment->order->unify([ 'body' => "用户支付日租车租车费用-" . config('app.name', '未来bike'), 'out_trade_no' => $order->no, 'trade_type' => 'JSAPI', // 必须为JSAPI 'openid' => $auth['credential'], // 这里的openid为付款人的openid 'total_fee' => wechat_fee($order->total_money), // 总价 'attach' => makeNoTag(RentOrder::NO_TAG), 'notify_url' => config('app.url') . '/api/payments/wechat-rent-notify', ]); if ($result['return_code'] === 'FAIL') return $this->errorNoValidation('下单失败'); // 如果成功生成统一下单的订单,那么进行二次签名 if ($result['result_code'] === 'FAIL') { //判断是否重复下单 if ($result['err_code'] === 'INVALID_REQUEST') { $order->no = RentOrder::makeNo(); $order->save(); $result = $payment->order->unify([ 'body' => "用户支付日租车租车费用-" . config('app.name', '未来bike'), 'out_trade_no' => $order->no, 'trade_type' => 'JSAPI', // 必须为JSAPI 'openid' => $auth['credential'], // 这里的openid为付款人的openid 'total_fee' => wechat_fee($order->total_money), // 总价 'attach' => makeNoTag(RentOrder::NO_TAG), 'notify_url' => config('app.url') . '/api/payments/wechat-rent-notify', ]); } elseif ($result['err_code'] === 'ORDERPAID') { $order->pay_status = RentOrder::PAY_STATUS_OK; $order->pay_time = now(); $order->pay_type = RentOrder::PAY_TYPE_WECHAT; $order->pay_money = $order->total_money; $order->order_total_money = $order->pay_money; $order->status = RentOrder::STATUS_COMPLETE_ORDER; $order->save(); $order->pay_rent_over_order_callback(); return $this->errorNoValidation('订单已支付,请勿重复支付!'); } else { return $this->errorNoValidation('下单失败'); } } if ('SUCCESS' === $result['return_code'] && 'SUCCESS' === $result['result_code']) { // 二次签名的参数必须与下面相同 $params = [ 'appId' => $auth['identifier'], 'timeStamp' => time(), 'nonceStr' => $result['nonce_str'], 'package' => 'prepay_id=' . $result['prepay_id'], 'signType' => 'MD5', ]; // config('wechat.payment.default.key')为商户的key $params['paySign'] = generate_sign($params, config('wechat.payment.default.key')); $response = $params; } else { return $this->errorNoValidation('下单失败'); } break; default: return $this->errorBadRequest('支付类型不对'); break; } $response['order_no'] = $order->no; return $this->response->array($response); } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } /** * 开锁 * User: Mead. */ public function openBike(Request $request, RentOrderRepository $rentOrderRepository, BikeRepository $bikeRepository) { try { $order_no = $request->get('order_no'); $lat = $request->get('lat'); $lng = $request->get('lng'); $order = $rentOrderRepository->byNoGetRideOrder($order_no); if (!$order) { return $this->errorNoValidation('订单不存在'); } if ($order->user_id !== $this->user->id) { return $this->errorNoValidation('非法操作'); } $user_id = $this->user['id']; $cache_key = "RENT_ORDER_OPEN_BIKE_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); $box_no = $bikeRepository->byIdGetBoxNo($order->bike_id); (new BaseBikeControl($box_no))::openLock(); (new BikeStatusInfoSyncHandler())->toBikeRentRideStatus($order->bike_no); // 记录日志信息 RentOrderBikeOperate::log($order->id, RentOrderBikeOperate::TYPE_OPEN_BIKE, $order->bike_id, $this->user->id, $lat, $lng); $order->bike_is_riding = Bike::RIDING_YES; $order->save(); //增加次数 Cache::remember('increment_use_bike', 1, function () use ($order) { return RentOrder::where('id', $order->id)->increment('use_bike_count'); }); return $this->success(); } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } /** * 关锁 * User: Mead. */ public function closeBike(Request $request, RentOrderRepository $rentOrderRepository, BikeRepository $bikeRepository, LocationLogRepository $locationLogRepository) { try { $order_no = $request->get('order_no'); $lat = $request->get('lat'); $lng = $request->get('lng'); $order = $rentOrderRepository->byNoGetRideOrder($order_no); if (!$order) { return $this->errorNoValidation('订单不存在'); } if ($order->user_id !== $this->user->id) { return $this->errorNoValidation('非法操作'); } $user_id = $this->user['id']; $cache_key = "RENT_ORDER_CLOSE_BIKE_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG); if ($location['lat'] <= 0) { $location['lat'] = $lat; $location['lng'] = $lng; } $order->end_use_bike_location = [ 'latitude' => $location['lat'], 'longitude' => $location['lng'], ]; $order->bike_is_riding = Bike::RIDING_NO; $order->save(); //最后骑行时间 $bikeModel = $bikeRepository->byIdGetModel($order->bike_id); $bikeModel->last_use_bike_end_time = date('Y-m-d H:i:s'); $bikeModel->save(); $box_no = $bikeRepository->byIdGetBoxNo($order->bike_id); (new BaseBikeControl($box_no))::closeLock(); // 记录日志信息 RentOrderBikeOperate::log($order->id, RentOrderBikeOperate::TYPE_CLONE_BIKE, $order->bike_id, $this->user->id, $lat, $lng); (new BikeStatusInfoSyncHandler())->toBikeRentWaitRideStatus($order->bike_no); return $this->success(); } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } /** * 日租订单列表页. * * @param Request $request * @param RentOrder $rentOrder * User: Mead */ public function orders(Request $request, RentOrder $rentOrder) { try { $query = $rentOrder->query(); $query->where('pay_status', RentOrder::PAY_STATUS_OK); if ($year = $request->get('year', date('Y'))) { $query->whereYear('created_at', $year); } if ($month = $request->get('month', date('m'))) { $query->whereMonth('created_at', $month); } $orders = $query->where('user_id', $this->user->id)->orderBy('id', 'desc')->paginate(); $orders->appends($request->only(['year', 'month']))->withPath(config('app.url') . '/api/rent/orders'); return $this->response->paginator($orders, RentOrderTransformer::class); } catch (\Exception $exception) { return $this->errorException($exception->getMessage()); } } /** * 检查是否在还车点 * User: Mead. */ public function checkBikeIsInStopParking(Request $request, BikeRepository $bikeRepository, RentOrderRepository $rentOrderRepository, AreaSettingRepository $areaSettingRepository, LocationLogRepository $locationLogRepository, AreaRepository $areaRepository) { $bike_no = $request->get('bike_no'); $order_no = $request->get('order_no'); $user_lat = $request->get('lat'); $user_lng = $request->get('lng'); try { $order = $rentOrderRepository->byNo($order_no); if (!$order) { return $this->errorBadRequest('非法请求'); } $user_id = $this->user['id']; $cache_key = "RENT_ORDER_CHECK_BIKE_IS_PARK_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no); (new BaseBikeControl($box_no))::nowBikeLocation(); $setting = $areaSettingRepository->byAreaId($order->area_id); $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG); if ($location['lat'] <= 0) { $location['lat'] = $order->end_use_bike_location['latitude']; $location['lng'] = $order->end_use_bike_location['longitude']; if ($location['lat'] <= 0) { $location['lat'] = $user_lat; $location['lng'] = $user_lng; } } //检查是否在骑行区域 $area = $areaRepository->byIdGetModelRedis($order->area_id); if (!$area) { $area = Area::where('id', $order->area_id)->first(); } $is_out_area = $this->isOutArea($location['lat'], $location['lng'], $area); if (!$is_out_area) { return $this->errorNoValidation('超出骑行区域,暂不能还车'); } //检查是否在禁停区 $BikeHandler = new BikeHandler(); $is_ban_stop_bike = $BikeHandler->byLocationCheckIsInBanStopParking($location['lat'], $location['lng'], $order->area_id, $user_lat, $user_lng); if ($is_ban_stop_bike) { return $this->errorNoValidation('禁停区域内禁止停车!'); } // //运动中不能锁车 // if ($location['speed']) { // (new BaseBikeControl($box_no))::nowBikeLocation(); // // return $this->errorNoValidation('运动中不能关锁', 450); // } //判断是否全区域内可停 if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_OK) { return [ 'is_dispatch' => true, 'is_stop_bike' => true, 'dispatch_money' => 0, ]; } // 判断是否在停车点 $BikeHandler = new BikeHandler(); $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id, $user_lat, $user_lng); if (!$is_huanche['status']) { // 不在还车点 $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting); RentOrder::where('id', $order->id)->update([ 'dispatch_money' => $dispatch_money, ]); return [ 'is_dispatch' => false, 'is_stop_bike' => false, 'dispatch_money' => $dispatch_money, ]; } return [ 'is_dispatch' => true, 'is_stop_bike' => true, 'dispatch_money' => 0, ]; } catch (HttpException $exception) { return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode()); } } /** * 判断是否在骑行区. * * @param $lat * @param $lng * @param $box_no * User: Mead */ private function isOutArea($lat, $lng, $area) { try { $location = [ 'latitude' => $lat, 'longitude' => $lng, ]; $fences = $area['area_fence']; $centre = $area['area_centre']; $radius = $area['area_radius']; // 判断是否在骑行区域 $ConvertHandler = (new ConvertHandler()); $is_out_area = $ConvertHandler->is_point_in_polygon($location, $fences); return $is_out_area; } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } /** * 寻铃 * @param Request $request * @param OrderRepository $orderRepository * @param BikeRepository $bikeRepository * User: Fx */ public function retryBell(RetryBikeRequest $request, RentOrderRepository $rentOrderRepository, BikeRepository $bikeRepository) { try { $order_no = $request->get('order_no'); $bike_no = $request->get('bike_no'); $order = $rentOrderRepository->checkUserIsRetryOpenLock($order_no, $bike_no, $this->user->id); if (!$order) return $this->errorNoValidation('没有此订单'); $box_no = $bikeRepository->byNoGetBoxNO($bike_no); $re = (new BaseBikeControl($box_no))::bellBike(); return $this->response->array([ 'is_ok' => $re ]); } catch (\Exception $exception) { return $this->errorNoValidation($exception->getMessage()); } } /** * 检查是否可以结束订单 * @param Request $request * @param BikeRepository $bikeRepository * @param RentOrderRepository $rentOrderRepository * @param LocationLogRepository $locationLogRepository * @param AreaRepository $areaRepository * @return array|void * Author: Mead */ public function checkBikeIsRidingArea(Request $request, BikeRepository $bikeRepository, RentOrderRepository $rentOrderRepository, LocationLogRepository $locationLogRepository, AreaRepository $areaRepository) { $bike_no = $request->get('bike_no'); $order_no = $request->get('order_no'); $user_lat = $request->get('lat'); $user_lng = $request->get('lng'); try { $order = $rentOrderRepository->byNo($order_no); if (!$order) { return $this->errorBadRequest('非法请求'); } $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time)); if ($second < AreaSetting::CLOSE_BIKE_TIME) { //小于60秒直接锁车 return [ 'is_close_order' => true, ]; } $user_id = $this->user['id']; $cache_key = "RENT_ORDER_CHECK_BIKE_IS_RIDING_PARK_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no); (new BaseBikeControl($box_no))::nowBikeLocation(); $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG); if ($location['lat'] <= 0) { $location['lat'] = $order->end_use_bike_location['latitude']; $location['lng'] = $order->end_use_bike_location['longitude']; if ($location['lat'] <= 0) { $location['lat'] = $user_lat; $location['lng'] = $user_lng; } } //检查是否在骑行区域 $area = $areaRepository->byIdGetModelRedis($order->area_id); if (!$area) { $area = Area::where('id', $order->area_id)->first(); } $is_out_area = $this->isOutArea($location['lat'], $location['lng'], $area); if (!$is_out_area) { return $this->errorNoValidation('超出骑行区域,暂不能还车'); } //检查是否在禁停区 $BikeHandler = new BikeHandler(); $is_ban_stop_bike = $BikeHandler->byLocationCheckIsInBanStopParking($location['lat'], $location['lng'], $order->area_id, $user_lat, $user_lng); if ($is_ban_stop_bike) { return $this->errorNoValidation('禁停区域内禁止停车!'); } return [ 'is_close_order' => false, ]; } catch (HttpException $exception) { return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode()); } } /** * Author: Mead */ public function expectRentOrderMoney(Request $request, BikeRepository $bikeRepository, RentOrderRepository $rentOrderRepository, AreaSettingRepository $areaSettingRepository, LocationLogRepository $locationLogRepository, AreaRepository $areaRepository) { $bike_no = $request->get('bike_no'); $order_no = $request->get('order_no'); $user_lat = $request->get('lat'); $user_lng = $request->get('lng'); try { $order = $rentOrderRepository->byNo($order_no); if (!$order) { return $this->errorBadRequest('非法请求'); } $second = Carbon::now()->diffInSeconds(Carbon::parse($order->start_use_bike_time)); if ($second < AreaSetting::CLOSE_BIKE_TIME) { //小于60秒直接锁车 return [ 'dispatch_money' => 0, 'time_money' => 0, 'rent_total_money' => 0, 'total_money' => 0, ]; } $user_id = $this->user['id']; $cache_key = "RENT_ORDER_EXPECT_MONEY_{$user_id}"; if (Cache::has($cache_key)) { return $this->errorNoValidation('您提交的太频繁了,请一会再提交!'); } Cache::put($cache_key, 1, Carbon::now()->addSeconds(3)); $box_no = $bikeRepository->byNoGetBoxNO($order->bike_no); (new BaseBikeControl($box_no))::nowBikeLocation(); $setting = $areaSettingRepository->byAreaId($order->area_id); $money = 0.00; $over_hours = 0; //是否需要收取超出费用 $is_over_time = (strtotime($order->return_end_bike_time) < time()); if ($is_over_time) { //超出时间 $over_hours = ceil(Carbon::now()->diffInMinutes(Carbon::parse($order->return_end_bike_time)) / 60); $hours = ceil(Carbon::now()->diffInMinutes(Carbon::parse($order->start_use_bike_time)) / 60); if ($hours > 24) { //超过1天 $day = ceil($hours / 24); $end_hours = $hours % 24; //日封顶租金*天 $money = bcmul($setting['over_rent_time_max_money'], ($day - 1), 2); // $money = bcadd($money, $setting['rent_money'], 2); if ($end_hours > $setting['rent_time']) { // 超过一天 又超过8小时 // (超时费 + 日封顶租金*天) $money = bcadd(bcmul(($end_hours - $setting['rent_time']), $setting['over_rent_time_money'], 2), $money, 2); } } else { // 不超过1天 但是超过8小时 $money = bcmul($over_hours, $setting['over_rent_time_money'], 2); // (超时费 + 基础租金) 是否大于日封顶租金 $total_money = bcadd($money, $setting['rent_money'], 2); if ($total_money > $setting['over_rent_time_max_money']) { $money = bcsub($setting['over_rent_time_max_money'], $setting['rent_money'], 2); } } } $location = $locationLogRepository->byBikeNoGetLastLocation($order->bike_no, CacheMap::IS_OPEN_MONGODB_DUG); //计算骑行距离 // $order->use_bike_distance_length = bcdiv($location['mileage'], 1000, 2); if ($location['lat'] <= 0) { $location['lat'] = $order->end_use_bike_location['latitude']; $location['lng'] = $order->end_use_bike_location['longitude']; if ($location['lat'] <= 0) { $location['lat'] = $user_lat; $location['lng'] = $user_lng; } } $money = floatval($money); $total_money = floatval(bcadd($money, $order->rent_total_money, 2)); $rent_total_money = floatval($order->rent_total_money); //判断是否全区域内可停 if ($areaSettingRepository->byAreaIdGetIsWholeAreaHuanche($order->area_id) === AreaSetting::WHOLE_AREA_HUANCHE_OK) { return [ 'dispatch_money' => 0, 'time_money' => $money, 'rent_total_money' => $rent_total_money, 'total_money' => $total_money, ]; } // 判断是否在停车点 $BikeHandler = new BikeHandler(); $is_huanche = $BikeHandler->byLocationCheckIsInStopParking($location['lat'], $location['lng'], $order->area_id, $user_lat, $user_lng); if (!$is_huanche['status']) { // 不在还车点 $dispatch_money = $BikeHandler->byDistanceGetDistanceMoney($is_huanche['distance'], $setting); RentOrder::where('id', $order->id)->update([ 'dispatch_money' => $dispatch_money, ]); return [ 'dispatch_money' => $dispatch_money, 'time_money' => $money, 'rent_total_money' => $rent_total_money, 'total_money' => floatval(bcadd($total_money, $dispatch_money, 2)), ]; } return [ 'dispatch_money' => 0, 'time_money' => $money, 'rent_total_money' => $rent_total_money, 'total_money' => $total_money, ]; } catch (HttpException $exception) { return $this->errorNoValidation($exception->getMessage(), $exception->getStatusCode()); } } }