DeliveryOrderRepository.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\common\repositories\delivery;
  12. use app\common\dao\delivery\DeliveryOrderDao;
  13. use app\common\model\delivery\DeliveryStation;
  14. use app\common\model\store\order\StoreOrder;
  15. use app\common\repositories\BaseRepository;
  16. use app\common\repositories\store\order\StoreOrderRepository;
  17. use app\common\repositories\store\order\StoreOrderStatusRepository;
  18. use app\common\repositories\system\merchant\MerchantRepository;
  19. use app\common\repositories\system\serve\ServeOrderRepository;
  20. use app\common\repositories\user\UserRepository;
  21. use crmeb\services\DeliverySevices;
  22. use FormBuilder\Factory\Elm;
  23. use think\exception\ValidateException;
  24. use think\facade\Db;
  25. use think\facade\Log;
  26. use think\facade\Route;
  27. class DeliveryOrderRepository extends BaseRepository
  28. {
  29. protected $statusData = [
  30. 2 => '待取货',
  31. 3 => '配送中',
  32. 4 => '已完成',
  33. -1 => '已取消',
  34. 9 => '物品返回中',
  35. 10 => '物品返回完成',
  36. 100 => '骑士到店',
  37. ];
  38. protected $message = [
  39. 2 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_WAITING,
  40. 3 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_ING,
  41. 4 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_OVER,
  42. -1 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_CANCEL,
  43. 9 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_REFUNDING,
  44. 10 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_REFUND,
  45. 100 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_ARRIVE,
  46. ];
  47. public function __construct(DeliveryOrderDao $dao)
  48. {
  49. $this->dao = $dao;
  50. }
  51. public function merList(array $where, int $page, int $limit)
  52. {
  53. $query = $this->dao->getSearch($where)->with(['station','storeOrder'])->order('create_time DESC');
  54. $count = $query->count();
  55. $list = $query->page($page, $limit)->select();
  56. return compact('count', 'list');
  57. }
  58. public function sysList(array $where, int $page, int $limit)
  59. {
  60. $query = $this->dao->getSearch($where)->with([
  61. 'merchant' => function($query) {
  62. $query->field('mer_id,mer_name');
  63. },
  64. 'station',
  65. 'storeOrder'=> function($query) {
  66. $query->field('order_id,order_sn');
  67. },
  68. ])->order('create_time DESC');
  69. $count = $query->count();
  70. $list = $query->page($page, $limit)->select();
  71. return compact('count', 'list');
  72. }
  73. public function detail(int $id, ?int $merId)
  74. {
  75. $where[$this->dao->getPk()] = $id;
  76. if ($merId) $where['mer_id'] = $merId;
  77. $res = $this->dao->getSearch($where)->with([
  78. 'merchant' => function($query) {
  79. $query->field('mer_id,mer_name');
  80. },
  81. 'station',
  82. ])->find();
  83. $order = DeliverySevices::create($res['station_type'])->getOrderDetail($res);
  84. $res['data'] = [
  85. 'order_code' => $order['order_code'],
  86. 'to_address' => $order['to_address'],
  87. 'from_address' => $order['from_address'],
  88. 'state' => $order['state'],
  89. 'note' => $order['note'],
  90. 'order_price' => $order['order_price'],
  91. 'distance' => round(($order['distance'] / 1000),2) . ' km',
  92. ];
  93. if (!$res) throw new ValidateException('订单不存在');
  94. return $res;
  95. }
  96. public function cancelForm($id)
  97. {
  98. $formData = $this->dao->get($id);
  99. if (!$formData) throw new ValidateException('订单不存在');
  100. if ($formData['status'] == -1) throw new ValidateException('订单已取消,无法操作');
  101. $form = Elm::createForm(Route::buildUrl('merchantStoreDeliveryOrderCancel',['id' => $id])->build());
  102. $rule = [];
  103. if ($formData['station_type'] == DeliverySevices::DELIVERY_TYPE_DADA){
  104. $options = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->reasons();
  105. $rule[] = Elm::select('reason', '取消原因')->options($options);
  106. $rule[] = Elm::text('cancel_reason', '其他原因说明');
  107. }
  108. if ($formData['station_type'] == DeliverySevices::DELIVERY_TYPE_UU){
  109. $rule[] = Elm::input('reason', '取消原因')->required(1);
  110. }
  111. $form->setRule($rule);
  112. return $form->setTitle('取消同城配送订单',$formData);
  113. }
  114. public function cancel($id, $merId, $reason)
  115. {
  116. $order = $this->dao->getWhere([$this->dao->getPk() => $id, 'mer_id' => $merId]);
  117. if (!$order) throw new ValidateException('配送订单不存在');
  118. if ($order['status'] == -1) throw new ValidateException('请勿重复操作');
  119. $data = [
  120. 'origin_id' => $order['order_sn'],
  121. 'order_code'=> $order['order_code'],
  122. 'reason' => $reason['reason'],
  123. 'cancel_reason' => $reason['cancel_reason'],
  124. ];
  125. return Db::transaction(function () use($order, $data){
  126. $mark = $data['reason'];
  127. if ($order['station_type'] == DeliverySevices::DELIVERY_TYPE_DADA) {
  128. $options = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->reasons();
  129. $mark = $options[$data['reason']];
  130. }
  131. if ($data['cancel_reason']) $mark .= ','.$data['cancel_reason'];
  132. $res = DeliverySevices::create($order['station_type'])->cancelOrder($data);
  133. $deduct_fee = $res['deduct_fee'] ?? 0;
  134. $this->cancelAfter($order, $deduct_fee, $mark);
  135. $statusRepository = app()->make(StoreOrderStatusRepository::class);
  136. $statusRepository->status($order['order_id'], $statusRepository::ORDER_DELIVERY_CITY_CANCEL, '已取消');
  137. });
  138. }
  139. public function cancelAfter($deliveryOrder, $deductFee, $mark)
  140. {
  141. //修改配送订单
  142. $deliveryOrder->status = -1;
  143. $deliveryOrder->reason = $mark;
  144. $deliveryOrder->deduct_fee = $deductFee;
  145. $deliveryOrder->save();
  146. //修改商城订单
  147. $res = app()->make(StoreOrderRepository::class)->get($deliveryOrder['order_id']);
  148. $res->status = 0;
  149. $res->delivery_type = 0;
  150. $res->delivery_name = '';
  151. $res->delivery_id = '';
  152. $res->save();
  153. //修改商户
  154. $merchant = app()->make(MerchantRepository::class)->get($deliveryOrder['mer_id']);
  155. $balance = bcadd(bcsub($deliveryOrder['fee'], $deductFee, 2), $merchant->delivery_balance, 2);
  156. $merchant->delivery_balance = $balance;
  157. $merchant->save();
  158. }
  159. /**
  160. * TODO 回调
  161. * @param $data
  162. * @author Qinii
  163. * @day 2/17/22
  164. */
  165. public function notify($data)
  166. {
  167. //达达
  168. /**
  169. * 订单状态(待接单=1,待取货=2,配送中=3,已完成=4,已取消=5, 指派单=8,妥投异常之物品返回中=9, 妥投异常之物品返回完成=10, 骑士到店=100,创建达达运单失败=1000 可参考文末的状态说明)
  170. */
  171. Log::info('同城回调参数:'.var_export(['=======',$data,'======='],1));
  172. if (isset($data['data'])) {
  173. $data = json_decode($data['data'], 1);
  174. }
  175. $reason = '';
  176. $deductFee = 0;
  177. $delivery = [];
  178. if (isset($data['order_status'])){
  179. $order_sn = $data['order_id'];
  180. if ($data['order_status'] == 1) {
  181. $orderData = $this->dao->getSearch(['sn' => $data['order_id']])->find();
  182. if (!$orderData['finish_code']) {
  183. $orderData->finish_code = $data['finish_code'];
  184. $orderData->save();
  185. }
  186. return ;
  187. } else if (in_array( $data['order_status'],[2,3,4,5,9,10,100])){
  188. $status = $data['order_status'];
  189. if ($data['order_status'] == 5){
  190. $msg = [
  191. '取消:',
  192. '达达配送员取消:',
  193. '商家主动取消:',
  194. '系统或客服取消:',
  195. ];
  196. //1:达达配送员取消;2:商家主动取消;3:系统或客服取消;0:默认值
  197. $status = -1;
  198. $reason = $msg[$data['cancel_from']].$data['cancel_reason'];
  199. }
  200. $deductFee = $data['deductFee'] ?? 0;
  201. if (isset($data['dm_name']) && $data['dm_name']) {
  202. $delivery = [
  203. 'delivery_name' => $data['dm_name'],
  204. 'delivery_id' => $data['dm_mobile'],
  205. ];
  206. }
  207. }
  208. } else if (isset($data['state'])){ //uu
  209. if (!$data['origin_id']) $deliveryOrder = $this->dao->getWhere(['order_code' => $data['order_code']]);
  210. $order_sn = $data['origin_id'] ?: $deliveryOrder['order_sn'] ;
  211. //当前状态 1下单成功 3跑男抢单 4已到达 5已取件 6到达目的地 10收件人已收货 -1订单取消
  212. switch ($data['state']) {
  213. case 3:
  214. $status = 2;
  215. break;
  216. case 4:
  217. $status = 100;
  218. break;
  219. case 5:
  220. $status = 3;
  221. break;
  222. case 10:
  223. $status = 4;
  224. break;
  225. case -1:
  226. $status = -1;
  227. $reason = $data['state_text'];
  228. break;
  229. default:
  230. break;
  231. }
  232. if (isset($data['driver_name']) && $data['driver_name']) {
  233. $delivery = [
  234. 'delivery_name' => $data['driver_name'],
  235. 'delivery_id' => $data['driver_mobile'],
  236. ];
  237. }
  238. }
  239. if (isset($order_sn) && isset($status)){
  240. $res = $this->dao->getWhere(['order_sn' => $order_sn]);
  241. if ($res) {
  242. $this->notifyAfter($status, $reason, $res, $delivery, $deductFee);
  243. }else {
  244. Log::info('同城配送回调,未查询到订单:'.$order_sn);
  245. }
  246. }
  247. }
  248. public function notifyAfter($status, $reason, $res, $data, $deductFee)
  249. {
  250. if (!isset($this->statusData[$status])) return ;
  251. $make = app()->make(StoreOrderRepository::class);
  252. $orderData = $make->get($res['order_id']);
  253. if ($orderData['status'] != $status ) {
  254. $res->status = $status;
  255. $res->reason = $reason;
  256. $res->save();
  257. $message = '订单已配送【'. $this->statusData[$status].'】';
  258. app()->make(StoreOrderStatusRepository::class)->status($res['order_id'], $this->message[$status], $message);
  259. if ($status == 2 && !empty($data)) $make->update($res['order_id'],$data);
  260. if ($status == 4){
  261. $order = $make->get($res['order_id']);
  262. $user = app()->make(UserRepository::class)->get($order['uid']);
  263. $make->update($res['order_id'],['status' => 2]);
  264. $make->takeAfter($order, $user);
  265. }
  266. if ($status == -1) $this->cancelAfter($res, $deductFee , $reason);
  267. }
  268. }
  269. public function create($id, $merId, $data, $order)
  270. {
  271. $type = systemConfig('delivery_type');
  272. $callback_url = rtrim(systemConfig('site_url'), '/') . '/api/notice/callback';
  273. $where = ['station_id' => $data['station_id'], 'mer_id' => $merId, 'status' => 1, 'type' => $type];
  274. $station = app()->make(DeliveryStationRepository::class)->getWhere($where);
  275. if (!$station) throw new ValidateException('门店信息不存在');
  276. if (!$station['city_name']) throw new ValidateException('门店缺少所在城市,请重新编辑门店信息');
  277. //地址转经纬度
  278. try{
  279. $addres = lbs_address($station['city_name'], $order['user_address']);
  280. }catch (\Exception $e) {
  281. throw new ValidateException('获取经纬度失败');
  282. }
  283. $getPriceParams = $this->getPriceParams($station, $order, $addres['location'],$type);
  284. $orderSn = $this->getOrderSn();
  285. $getPriceParams['origin_id'] = $orderSn;
  286. $getPriceParams['callback_url'] = $callback_url;
  287. $getPriceParams['cargo_weight'] = $data['cargo_weight'] ?? '';
  288. $service = DeliverySevices::create($type);
  289. //计算价格
  290. $priceData = $service->getOrderPrice($getPriceParams);
  291. if ($type == DeliverySevices::DELIVERY_TYPE_UU) { //uu
  292. $priceData['receiver'] = $order['real_name'];
  293. $priceData['receiver_phone'] = $order['user_phone'];
  294. $priceData['note'] = $data['mark'];
  295. $priceData['callback_url'] = $callback_url;
  296. $priceData['push_type'] = 2;
  297. $priceData['special_type'] = $data['special_type'] ?? 0;
  298. }
  299. app()->make(MerchantRepository::class)->changeDeliveryBalance($merId, $priceData['fee'] ?? $priceData['need_paymoney']);
  300. //发布订单
  301. Db::startTrans();
  302. try{
  303. $res = $service->addOrder($priceData);
  304. $ret = [
  305. 'station_id' => $data['station_id'],
  306. 'order_sn' => $orderSn,
  307. 'city_code' => $station['city_name'],
  308. 'receiver_phone' => $order['user_phone'],
  309. 'user_name' => $order['real_name'],
  310. 'from_address' => $station['station_address'],
  311. 'to_address' => $order['user_address'],
  312. 'order_code' => $type == 2 ? $res['ordercode'] : $priceData['deliveryNo'],
  313. 'order_id' => $id,
  314. 'mer_id' => $merId,
  315. 'info' => $data['mark'],
  316. 'status' => $res['status'] ?? 0,
  317. 'station_type' => $type,
  318. 'to_lat' => $addres['location']['lat'],
  319. 'to_lng' => $addres['location']['lng'],
  320. 'from_lat' => $station['lat'],
  321. 'from_lng' => $station['lng'],
  322. 'distance' => $priceData['distance'],
  323. 'fee' => $priceData['fee'] ?? $priceData['need_paymoney'],
  324. 'mark' => $data['mark'],
  325. 'uid' => $order['uid'],
  326. ];
  327. //入库操作
  328. $this->dao->create($ret);
  329. Db::commit();
  330. return true;
  331. }catch (\Exception $exception) {
  332. if (isset($res['status']) && $res['status'] == 'success'){
  333. $error['origin_id'] = $orderSn;
  334. $error['reason'] = $type == 1 ? 36 : '信息错误';
  335. $error['order_code'] = $type == 2 ? $res['ordercode'] : $priceData['deliveryNo'];
  336. sleep(1);
  337. $service->cancelOrder($error);
  338. }
  339. Db::rollback();
  340. throw new ValidateException($exception->getMessage());
  341. }
  342. }
  343. public function getPriceParams(DeliveryStation $deliveryStation, StoreOrder $order, array $addres, int $type)
  344. {
  345. $data = [];
  346. $type = (int)$type;
  347. switch ($type) {
  348. case 1:
  349. $city = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->getCity([]);
  350. $res = [];
  351. foreach ($city as $item) {
  352. $res[$item['label']] = $item['key'];
  353. }
  354. $data = [
  355. 'shop_no' => $deliveryStation['origin_shop_id'],
  356. 'city_code' => $res[$deliveryStation['city_name']],
  357. 'cargo_price' => $order['pay_price'],
  358. 'is_prepay' => 0,
  359. 'receiver_name' => $order['real_name'],
  360. 'receiver_address' => $order['user_address'],
  361. 'cargo_weight' => 0,
  362. 'receiver_phone' => $order['user_phone'],
  363. 'is_finish_code_needed' => 1,
  364. ];
  365. break;
  366. case 2:
  367. $data = [
  368. 'from_address' => $deliveryStation['station_address'],
  369. 'to_address' => $order['user_address'],
  370. 'city_name' => $deliveryStation['city_name'],
  371. 'goods_type' => $deliveryStation['business']['label'],
  372. 'send_type' =>'0',
  373. 'to_lat' => $addres['lat'],
  374. 'to_lng' => $addres['lng'],
  375. 'from_lat' => $deliveryStation['lat'],
  376. 'from_lng' => $deliveryStation['lng'],
  377. ];
  378. break;
  379. }
  380. return $data;
  381. }
  382. public function getTitle()
  383. {
  384. $query = app()->make(MerchantRepository::class)->getSearch(['is_del' => 0]);
  385. $merchant = $query->count();
  386. $price = app()->make(ServeOrderRepository::class)
  387. ->getSearch(['type' => 10,'status' => 1])->sum('pay_price');
  388. $balance = $query->sum('delivery_balance');
  389. return [
  390. [
  391. 'className' => 'el-icon-s-order',
  392. 'count' => $merchant,
  393. 'field' => '个',
  394. 'name' => '商户数'
  395. ],
  396. [
  397. 'className' => 'el-icon-s-order',
  398. 'count' => $price,
  399. 'field' => '元',
  400. 'name' => '商户充值总金额'
  401. ],
  402. [
  403. 'className' => 'el-icon-s-order',
  404. 'count' => $balance,
  405. 'field' => '元',
  406. 'name' => '商户当前余额'
  407. ],
  408. ];
  409. }
  410. public function destory($id, $merId)
  411. {
  412. $where = [
  413. $this->dao->getPk() => $id,
  414. 'mer_id' => $merId,
  415. ];
  416. $res = $this->dao->getSearch($where)->find();
  417. if (!$res) throw new ValidateException('订单不存在');
  418. return $this->dao->delete($id);
  419. }
  420. /**
  421. * TODO 订单SN
  422. * @return string
  423. * @author Qinii
  424. * @day 2/17/22
  425. */
  426. public function getOrderSn()
  427. {
  428. list($msec, $sec) = explode(' ', microtime());
  429. $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', '');
  430. $orderId = 'dc' . $msectime . random_int(10000, max(intval($msec * 10000) + 10000, 98369));
  431. return $orderId;
  432. }
  433. public function show(int $id, int $uid)
  434. {
  435. $where['order_id'] = $id;
  436. $where['uid'] = $uid;
  437. $res = $this->dao->getSearch($where)->with(['storeOrderStatus','storeOrder'])->find();
  438. if (!$res) throw new ValidateException('订单不存在');
  439. return $res;
  440. }
  441. }