You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
12 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Controller\v3;
  3. use App\Constants\v3\ErrorCode;
  4. use App\Constants\v3\LogLabel;
  5. use App\Constants\v3\OrderState;
  6. use App\Controller\BaseController;
  7. use App\Exception\ErrorCodeException;
  8. use App\Model\v3\Market;
  9. use App\Model\v3\OrderMain;
  10. use App\Request\v3\OrderOnlineDetailRequest;
  11. use App\Request\v3\OrderOnlineRequest;
  12. use App\Request\v3\OrderOnlineStateRequest;
  13. use App\Request\v3\UserRequest;
  14. use App\Service\v3\Implementations\PaymentService;
  15. use App\Service\v3\Interfaces\CouponRecServiceInterface;
  16. use App\Service\v3\Interfaces\DistributionPriceServiceInterface;
  17. use App\Service\v3\Interfaces\LocationServiceInterface;
  18. use App\Service\v3\Interfaces\SeparateAccountsServiceInterface;
  19. use App\Service\v3\Interfaces\ShopCartServiceInterface;
  20. use GuzzleHttp\Client;
  21. use Hyperf\DbConnection\Db;
  22. use Hyperf\Di\Annotation\Inject;
  23. use App\Service\v3\Interfaces\OrderOnlineServiceInterface;
  24. use App\Service\v3\Interfaces\UserBindTelServiceInterface;
  25. use App\Service\v3\Interfaces\AppointmentTimeServiceInterface;
  26. use Psr\Http\Message\ResponseInterface;
  27. use App\Model\v3\UserAddress;
  28. class OrderOnlineController extends BaseController
  29. {
  30. /**
  31. * @Inject
  32. * @var UserBindTelServiceInterface
  33. */
  34. protected $userBindTelService;
  35. /**
  36. * @Inject
  37. * @var CouponRecServiceInterface
  38. */
  39. protected $couponRecService;
  40. /**
  41. * @Inject
  42. * @var AppointmentTimeServiceInterface
  43. */
  44. protected $appointmentTimeService;
  45. /**
  46. * @Inject
  47. * @var OrderOnlineServiceInterface
  48. */
  49. protected $orderOnlineService;
  50. /**
  51. * @Inject
  52. * @var ShopCartServiceInterface
  53. */
  54. protected $shopCartService;
  55. /**
  56. * @Inject
  57. * @var SeparateAccountsServiceInterface
  58. */
  59. protected $separateAccountsService;
  60. /**
  61. * @Inject
  62. * @var LocationServiceInterface
  63. */
  64. protected $locationService;
  65. /**
  66. * @Inject
  67. * @var DistributionPriceServiceInterface
  68. */
  69. protected $distributionPriceService;
  70. /*
  71. * 如果没有绑手机号去绑定页面
  72. * 收货地址接口
  73. * 返回预约送达时间
  74. * 商品数据接口
  75. * 红包独立接口
  76. * 配送费独立接口 可根据距离动态计算费用
  77. * 增值服务接口
  78. * */
  79. public function review(UserRequest $request)
  80. {
  81. $userId = $this->request->input('user_id','');
  82. $marketId = $this->request->input('market_id','');
  83. $shopcartIds = $this->request->input('shopcart_ids','');
  84. //判断用户有没有绑定手机
  85. $telExists = $this->userBindTelService->check($userId);
  86. if(!$telExists){
  87. throw new ErrorCodeException(ErrorCode::NOT_BIND_TEL_ERROR);
  88. }
  89. //获取用户收货地址
  90. $address = UserAddress::query()
  91. ->where('user_id',$userId)
  92. //->where('is_default',1)
  93. ->orderByDesc('is_default')
  94. ->orderByDesc('updated_at')
  95. ->get()->toArray();
  96. $market = Market::find($marketId);
  97. $type = 'bicycling';
  98. $key = config('map.tencent');
  99. $url = 'https://apis.map.qq.com/ws/distance/v1/matrix?mode='.$type.'&from='.$market->lat.','.$market->lng.'&to=';
  100. $client = new Client();
  101. foreach ($address as $item) {
  102. $url .= $item['lat'] . ',';
  103. $url .= $item['lng'] . ';';
  104. }
  105. $url = rtrim($url, ";");
  106. $response = $client->request('GET', $url.'&output=json&key='.$key);
  107. $response = $response->getBody()->getContents();
  108. $resultArr = json_decode($response,true);
  109. $resultArr = $resultArr['result']['rows'][0]['elements'];
  110. $deliveryDistance = config('distance.delivery_distance');
  111. foreach ($address as $key => &$item) {
  112. if($resultArr[$key]['distance'] <= $deliveryDistance){
  113. $item['distance'] = $resultArr[$key]['distance'];
  114. $addressNew[] = $item;
  115. }
  116. }
  117. $collection = collect($addressNew);
  118. $sorted = $collection->sortBy('distance')->sortByDesc('is_default');
  119. $address = $sorted->values()->first();
  120. if($address){
  121. $distance = $address['distance'];
  122. if($distance >= 1000){
  123. $distance_text = '距您收货地址 ' . bcdiv($distance,1000,2) . 'km';
  124. }else{
  125. $distance_text = '距您收货地址 ' . $distance . 'm';
  126. }
  127. if($address['is_default'] == 1){
  128. $address['tags'] = ['id' => 5,'name' => '默认'];
  129. }else{
  130. $address['tags'] = ['id' => 6,'name' => '距离最近'];
  131. }
  132. $distributionPrice = $this->distributionPriceService->do($distance);
  133. $originalPrice = $this->distributionPriceService->original($distance);
  134. $res['location'] = [
  135. 'address' => $address,
  136. 'distribution_price' => $distributionPrice,
  137. 'original_price' => $originalPrice,
  138. 'distance' => $distance,
  139. 'within' => true,
  140. 'style' => 'strike',
  141. // 'distribution_text' => '¥ '.$distributionPrice .'(' .$distance_text .')'
  142. 'distribution_text' => $distance_text,
  143. 'distribution_price_text' => '¥ '.$distributionPrice,
  144. 'original_price_text' => $originalPrice > $distributionPrice ? '¥ '.$originalPrice : ''
  145. ];
  146. }else{
  147. $res['location'] = [
  148. 'address' => '',
  149. 'distribution_price' => 0,
  150. 'original_price' => 0,
  151. 'distance' => 0,
  152. 'within' => false,
  153. 'style' => 'strike',
  154. 'distribution_text' => '',
  155. 'distribution_price_text' => '¥ 0',
  156. 'original_price_text' => ''
  157. ];
  158. }
  159. //返回预约送达时间 数组
  160. $res['appointment_time'] = $this->appointmentTimeService->get($shopcartIds);
  161. $res['store_list'] = $this->shopCartService->getGoodsByShopcartId($shopcartIds);
  162. //获取用户优惠券
  163. $coupons = $this->couponRecService->allForOnlineOrderAvailable( $userId, $marketId, explode(',', $shopcartIds) );
  164. $res['coupon'] = [
  165. 'available' => [],
  166. 'not_available' => [],
  167. ];
  168. foreach ($coupons as $key => &$item) {
  169. foreach ($item as $k => &$rec) {
  170. for ($i=0; $i<$rec->number_remain; $i++) {
  171. if ($key == 'available') {
  172. $res['coupon']['available'][] = $rec;
  173. } elseif ($key == 'not_available') {
  174. $res['coupon']['not_available'][] = $rec;
  175. }
  176. }
  177. }
  178. }
  179. // $res['coupon'] = $coupons;
  180. //增值服务接口
  181. $res['value_added_service'] = [
  182. 'text' => '增值服务包含洗菜、切菜、打包等所产生的人工成本费及包装费。',
  183. 'select' => 0,
  184. 'price' => 0,
  185. 'original_price' => 3.5
  186. ];
  187. $total = 0;
  188. foreach ($res['store_list'] as $store)
  189. {
  190. $total = bcadd($total,$store['subtotal'],2);
  191. }
  192. $total = bcadd($total,$res['value_added_service']['price'],2);
  193. $total = bcadd($total,$res['location']['distribution_price'],2);
  194. $res['total'] = $total;
  195. //优惠券排序
  196. $collection = collect($res['coupon']['available']);
  197. $sorted = $collection->sortBy(function ($product, $key) use ($total){
  198. if($product['coupon']['discount_type'] == 2){
  199. return bcmul($total,bcdiv($product['coupon']['discounts'],10,2),2);
  200. }elseif($product['coupon']['discount_type'] == 1){
  201. return bcsub($total,$product['coupon']['discounts'],2);
  202. }
  203. });
  204. $res['coupon']['available'] = $sorted->values()->all();
  205. // 新增返回市场信息
  206. $res['market'] = $market;
  207. return $this->success($res);
  208. }
  209. /**
  210. * 订单详情
  211. * 1、主订单信息,用户配送信息(地址、姓名、电话、配送时间、配送类型)、基础信息(订单ID、订单编号、下单时间、订单金额、付款时间、支付方式、红包优惠、服务站电话、增值服务费)
  212. * 2、子订单以及订单商品,按商户分组,有商户信息(ID、商户名、商户logo),商品信息(id、名字、封面、规格、tag、原价、售价、库存、总销、月销、是否失效、失效原因)
  213. * @param OrderOnlineDetailRequest $request
  214. * @return ResponseInterface
  215. */
  216. public function detailByUser(OrderOnlineDetailRequest $request)
  217. {
  218. $params = $request->validated();
  219. return $this->success(['detail' => $this->orderOnlineService->detailByUser($params['global_order_id'], $params['user_id'])]);
  220. }
  221. /**
  222. * 下单并进行支付,返回支付参数
  223. * 1、用户传参,用户地址ID,用于获取用户地址经纬度来计算配送费
  224. * 2、用户传参,购物车IDs,去获取购物车里的商品详情
  225. * 3、预约送达时间
  226. * 4、优惠券IDs
  227. * 5、订单总金额,用于校验比对
  228. * 6、下单成功,请求支付
  229. * @param OrderOnlineRequest $request
  230. * @return ResponseInterface
  231. */
  232. public function add(OrderOnlineRequest $request){
  233. // 下单
  234. $params = $request->validated();
  235. $couponIds = isset($params['coupon_ids'])&&$params['coupon_ids'] ? explode(',', $params['coupon_ids']) : [];
  236. $data = $this->orderOnlineService->do(
  237. $params['market_id'],
  238. $params['user_id'],
  239. ($params['user_address_id'] ?? 0),
  240. json_decode($params['store_list']),
  241. $params['total_money'],
  242. $params['delivery_time_note'],
  243. ($params['service_money'] ?? 0),
  244. $couponIds,
  245. $params['plat'] ?: '',
  246. ($params['self_take'] ?? 0)
  247. );
  248. return $this->success(['data' => $data]);
  249. }
  250. /**
  251. * 待支付订单重新发起支付
  252. * 1、用户id、订单id
  253. * 2、发起支付
  254. * @param OrderOnlineStateRequest $request
  255. * @return ResponseInterface
  256. */
  257. public function pay(OrderOnlineStateRequest $request)
  258. {
  259. $params = $request->validated();
  260. $data = $this->orderOnlineService->doPay($params['global_order_id'], $params['user_id']);
  261. return $this->success(['data' => $data]);
  262. }
  263. /**
  264. * 取消订单
  265. * @param OrderOnlineStateRequest $request
  266. * @return ResponseInterface
  267. */
  268. public function cancel(OrderOnlineStateRequest $request)
  269. {
  270. $params = $request->validated();
  271. $this->orderOnlineService->undo($params['global_order_id'], $params['user_id']);
  272. return $this->success([]);
  273. }
  274. /**
  275. * 删除订单
  276. * @param OrderOnlineStateRequest $request
  277. * @return ResponseInterface
  278. */
  279. public function del(OrderOnlineStateRequest $request)
  280. {
  281. $params = $request->validated();
  282. $this->orderOnlineService->doDel($params['global_order_id'], $params['user_id']);
  283. return $this->success([]);
  284. }
  285. /**
  286. * 申请退款
  287. * @param OrderOnlineStateRequest $request
  288. * @return ResponseInterface
  289. */
  290. public function applyRefund(OrderOnlineStateRequest $request)
  291. {
  292. $params = $request->validated();
  293. $this->orderOnlineService->doApplyRefund($params['global_order_id'], $params['user_id']);
  294. return $this->success([]);
  295. }
  296. /**
  297. * 完成订单
  298. * @param OrderOnlineStateRequest $request
  299. * @return ResponseInterface
  300. */
  301. public function complete(OrderOnlineStateRequest $request)
  302. {
  303. Db::beginTransaction();
  304. try {
  305. $params = $request->validated();
  306. $this->orderOnlineService->doComplete($params['global_order_id'], $params['user_id']);
  307. $this->separateAccountsService->orderOnlineCompleted($params['global_order_id'], $params['user_id']);
  308. Db::commit();
  309. return $this->success([]);
  310. } catch (\Exception $e) {
  311. Db::rollBack();
  312. $this->log->event(LogLabel::ORDER_COMPLETE_LOG, ['exception' => $e->getMessage()]);
  313. throw new ErrorCodeException(ErrorCode::ORDER_COMPLETE_FAIL);
  314. }
  315. }
  316. }