OrderService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services\Common;
  12. use App\Models\AccountModel;
  13. use App\Models\ActionLogModel;
  14. use App\Models\DriverModel;
  15. use App\Models\GoodsModel;
  16. use App\Models\MemberModel;
  17. use App\Models\OrderFreightModel;
  18. use App\Models\OrderModel;
  19. use App\Models\ScoreGoodsModel;
  20. use App\Services\Api\MessageService;
  21. use App\Services\BaseService;
  22. use App\Services\ConfigService;
  23. use App\Services\RedisService;
  24. use Illuminate\Support\Facades\DB;
  25. /**
  26. * 积分商城订单管理-服务类
  27. * @author laravel开发员
  28. * @since 2020/11/11
  29. * Class OrderService
  30. * @package App\Services\Common
  31. */
  32. class OrderService extends BaseService
  33. {
  34. // 静态对象
  35. protected static $instance = null;
  36. /**
  37. * 构造函数
  38. * @author laravel开发员
  39. * @since 2020/11/11
  40. * OrderService constructor.
  41. */
  42. public function __construct()
  43. {
  44. $this->model = new OrderModel();
  45. }
  46. /**
  47. * 静态入口
  48. * @return static|null
  49. */
  50. public static function make()
  51. {
  52. if (!self::$instance) {
  53. self::$instance = (new static());
  54. }
  55. return self::$instance;
  56. }
  57. /**
  58. * @param $params
  59. * @param int $pageSize
  60. * @return array
  61. */
  62. public function getDataList($params, $pageSize = 15)
  63. {
  64. $where = ['a.mark' => 1];
  65. $status = isset($params['status']) ? $params['status'] : 0;
  66. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  67. $serviceType = isset($params['service_type']) ? $params['service_type'] : 0;
  68. $deliveryType = isset($params['delivery_type']) ? $params['delivery_type'] : 0;
  69. $travelType = isset($params['travel_type']) ? $params['travel_type'] : 0;
  70. $driverId = isset($params['driver_id']) ? $params['driver_id'] : 0;
  71. $payStyle = isset($params['pay_style']) ? $params['pay_style'] : 0;
  72. $type = isset($params['type']) ? $params['type'] : 0;
  73. if ($driverId > 0) {
  74. $where['a.driver_id'] = $driverId;
  75. }
  76. if ($status > 0) {
  77. $where['a.status'] = $status;
  78. }
  79. if ($type > 0) {
  80. $where['a.type'] = $type;
  81. }
  82. if ($payStyle > 0) {
  83. $where['a.pay_style'] = $payStyle;
  84. }
  85. if ($serviceType > 0) {
  86. $where['a.service_type'] = $serviceType;
  87. }
  88. if ($deliveryType > 0) {
  89. $where['a.delivery_type'] = $deliveryType;
  90. }
  91. if ($travelType > 0) {
  92. $where['a.travel_type'] = $travelType;
  93. }
  94. $model = $this->model->with(['agent','carCategory','payUser'])->from('orders as a')
  95. ->leftJoin('member as b', 'a.user_id', '=', 'b.id')
  96. ->leftJoin('driver as c', 'c.id', '=', 'a.driver_id')
  97. ->leftJoin('agent as d', 'd.id', '=', 'a.agent_id')
  98. ->where($where)
  99. ->where(function ($query) use ($params) {
  100. $keyword = isset($params['keyword']) ? $params['keyword'] : '';
  101. if ($keyword) {
  102. $query->where('a.order_no', 'like', "%{$keyword}%")->orWhere('a.deposit_order_no', 'like', "%{$keyword}%");
  103. }
  104. })
  105. ->where(function ($query) use ($params) {
  106. $account = isset($params['account']) ? $params['account'] : '';
  107. if ($account) {
  108. $query->where('b.nickname', 'like', "%{$account}%")->orWhere('b.mobile', 'like', "%{$account}%");
  109. }
  110. })
  111. ->where(function ($query) use ($params) {
  112. $driver = isset($params['driver']) ? $params['driver'] : '';
  113. if ($driver) {
  114. $query->where('c.realname', 'like', "%{$driver}%")->orWhere('c.mobile', 'like', "%{$driver}%");
  115. }
  116. })
  117. ->where(function ($query) use ($params) {
  118. $agent = isset($params['agent']) ? $params['agent'] : '';
  119. if ($agent) {
  120. $query->where('d.realname', 'like', "%{$agent}%")->orWhere('d.mobile', 'like', "%{$agent}%");
  121. }
  122. })
  123. ->where(function ($query) use ($userId) {
  124. if($userId){
  125. $query->where('a.user_id', '=', $userId);
  126. }
  127. })
  128. ->select(['a.*', 'b.nickname as buy_nickname', 'b.mobile as buy_mobile', 'c.realname as driver_name', 'c.mobile as driver_mobile','c.car_number'])
  129. ->orderBy('a.create_time', 'desc')
  130. ->orderBy('a.pay_time', 'desc')
  131. ->orderBy('a.id', 'desc');
  132. $countModel = clone $model;
  133. $countModel1 = clone $model;
  134. $counts = [
  135. 'total'=> $countModel->count('a.pay_money'),
  136. 'count'=> $countModel1->count('a.id'),
  137. ];
  138. $list = $model->paginate($pageSize > 0 ? $pageSize : 9999999);
  139. $list = $list ? $list->toArray() : [];
  140. if ($list) {
  141. foreach ($list['data'] as &$item) {
  142. $item['create_time'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d H:i:s') : '';
  143. $item['pay_time'] = $item['pay_time'] ? datetime($item['pay_time'], 'Y-m-d H:i:s') : '';
  144. $item['delivery_distance'] = $item['delivery_distance'] ? moneyFormat($item['delivery_distance']/1000,2) : '0.00';
  145. $item['freight'] = [];
  146. if($item['service_type'] == 2){
  147. $item['freight'] = $this->getFreightList($item['order_no']);
  148. }
  149. $payUser = $item['pay_user']? $item['pay_user'] : [];
  150. $item['receipt_nickname'] = isset($payUser['nickname'])? $payUser['nickname'] : '';
  151. $item['receipt_mobile'] = isset($payUser['mobile'])? $payUser['mobile'] : '';
  152. }
  153. }
  154. return [
  155. 'pageSize' => $pageSize,
  156. 'total' => isset($counts['count']) ? $counts['count'] : 0,
  157. 'counts' => $counts,
  158. 'list' => isset($list['data']) ? $list['data'] : []
  159. ];
  160. }
  161. /**
  162. * 订单货物列表
  163. * @param $orderNo
  164. * @return array|mixed
  165. */
  166. public function getFreightList($orderNo)
  167. {
  168. $cacheKey = "caches:orders:freight:{$orderNo}";
  169. $datas = RedisService::get($cacheKey);
  170. if($datas){
  171. return $datas;
  172. }
  173. $datas = OrderFreightModel::with(['package','spec'])->where(['order_no'=> $orderNo,'mark'=>1])
  174. ->select(['id','goods_name','package_id','price','total','spec_id','thumb','albums','accept_albums','num','volume','length','height','weight','car_remark'])
  175. ->get();
  176. $datas = $datas? $datas->toArray() : [];
  177. if($datas){
  178. foreach ($datas as &$item){
  179. $item['thumb'] = $item['thumb']? get_image_url($item['thumb']): '';
  180. $item['albums'] = $item['albums']? get_images_preview($item['albums']): [];
  181. $item['accept_albums'] = $item['accept_albums']? get_images_preview($item['accept_albums']): [];
  182. }
  183. unset($item);
  184. RedisService::set($cacheKey, $datas, rand(300,600));
  185. }
  186. return $datas;
  187. }
  188. /**
  189. * 按日期统计订单数
  190. * @param string $beginAt 开始时间
  191. * @param string $endAt 结束时间
  192. * @param int[] $status 状态:数组或数值
  193. * @return mixed
  194. */
  195. public function getCountByTime($beginAt='', $endAt='', $status=4, $serviceType=0)
  196. {
  197. $where = ['mark' => 1];
  198. return $this->model->where($where)->where(function($query) use($beginAt,$endAt,$status,$serviceType){
  199. if($beginAt && $endAt){
  200. $query->whereBetween('create_time', [strtotime($beginAt), strtotime($endAt)]);
  201. }else if($beginAt){
  202. $query->where('create_time','>=', strtotime($beginAt));
  203. }
  204. if($status && is_array($status)){
  205. $query->whereIn('status',$status);
  206. }else if($status){
  207. $query->where('status',$status);
  208. }
  209. // 订单服务类型
  210. if($serviceType){
  211. $query->where('service_type',$serviceType);
  212. }
  213. })->count('id');
  214. }
  215. /**
  216. * 待处理订单数
  217. * @return int[]
  218. */
  219. public function countByWait()
  220. {
  221. $cacheKey = "caches:orders:counts";
  222. $counts = RedisService::get($cacheKey);
  223. if($counts){
  224. return $counts;
  225. }
  226. $counts = [
  227. 'travel'=> 0, // 出行订单,待处理数量
  228. 'freight'=> 0, // 快运订单,待处理数
  229. ];
  230. $type = request()->post('service_type', 0);
  231. if($type == 0 || $type == 1){
  232. $counts['travel'] = $this->model->whereIn('status',[1,2,3,4,7])->where(function($query){
  233. $query->where('pay_status',1)->orWhere('deposit_status',1);
  234. })->where(['service_type'=>1,'mark'=>1])->where('create_time','>=',time() - 600)->count('id');
  235. }
  236. if($type == 0 || $type == 2){
  237. $counts['freight'] = $this->model->whereIn('status',[1,2,3,4,7])->where(function($query){
  238. $query->where('pay_status',1)->orWhere('deposit_status',1);
  239. })->where(['service_type'=>2,'mark'=>1])->where('create_time','>=',time() - 600)->count('id');
  240. }
  241. RedisService::set($cacheKey, $counts, rand(2,5));
  242. return $counts;
  243. }
  244. /**
  245. * 添加或编辑
  246. * @return array
  247. * @since 2020/11/11
  248. * @author laravel开发员
  249. */
  250. public function edit()
  251. {
  252. $params = request()->post();
  253. $data = [
  254. 'id'=> isset($params['id'])? intval($params['id']) : 0,
  255. 'update_time'=> time(),
  256. ];
  257. if(isset($params['status'])){
  258. $data['status'] = intval($params['status']);
  259. }
  260. if(isset($params['exception_remark'])){
  261. $data['exception_remark'] = intval($params['exception_remark']);
  262. }
  263. if(isset($params['cancel_type'])){
  264. $data['cancel_type'] = intval($params['cancel_type']);
  265. }
  266. if(isset($params['remark'])){
  267. $data['remark'] = intval($params['remark']);
  268. }
  269. if(isset($params['driver_id'])){
  270. $data['driver_id'] = intval($params['driver_id']);
  271. }
  272. $status = isset($data['status'])? $data['status'] : 0;
  273. $deiverId = isset($data['driver_id'])? $data['driver_id'] : 0;
  274. if($status>=3 && $deiverId<=0){
  275. return message('该订单未接单,状态不可修改未接单后状态',false);
  276. }
  277. return parent::edit($data); // TODO: Change the autogenerated stub
  278. }
  279. /**
  280. * 异常
  281. * @return bool
  282. */
  283. public function exception()
  284. {
  285. $params = request()->all();
  286. $id = isset($params['id'])? intval($params['id']) : 0; // 订单ID
  287. $remark = isset($params['exception_remark'])? trim($params['exception_remark']) : ''; // 异常备注
  288. $cacheKey = "caches:orders:exception_lock:{$id}";
  289. if(RedisService::get($cacheKey)){
  290. $this->error = 1034;
  291. return false;
  292. }
  293. // 缓存锁
  294. RedisService::set($cacheKey, ['id'=> $id], rand(2,3));
  295. $orderInfo = $this->model->with(['member','driver','payment'])->where(['id'=> $id,'mark'=>1])
  296. ->select(['id','order_no','pay_money','user_id','driver_id','deposit','deposit_order_no','transaction_id','coupon_id','service_type','pay_style','pay_type','status'])
  297. ->first();
  298. $orderStatus = isset($orderInfo['status'])? $orderInfo['status'] : 0;
  299. $orderUserId = isset($orderInfo['user_id'])? $orderInfo['user_id'] : 0;
  300. $orderDriverId = isset($orderInfo['driver_id'])? $orderInfo['driver_id'] : 0;
  301. $orderNo = isset($orderInfo['order_no'])? $orderInfo['order_no'] : '';
  302. if(empty($id) || empty($orderInfo)){
  303. $this->error = 2128;
  304. return false;
  305. }
  306. // 接单订单状态
  307. if(!in_array($orderStatus,[3,7])){
  308. $this->error = 2129;
  309. return false;
  310. }
  311. // 司机信息
  312. $driverInfo = DriverModel::where(['id'=> $orderDriverId, 'mark'=>1])
  313. ->select(['id','mobile','realname','car_number','status'])
  314. ->first();
  315. $status = isset($driverInfo['status'])? $driverInfo['status'] : 0;
  316. $realname = isset($driverInfo['realname'])? $driverInfo['realname'] : '';
  317. // 订单处理
  318. DB::beginTransaction();
  319. if(!$this->model->where(['id'=> $id,'mark'=>1])->update(['status'=> 6,'exception_remark'=> $remark,'update_time'=>time()])){
  320. DB::rollBack();
  321. $this->error = 1003;
  322. return false;
  323. }
  324. DB::commit();
  325. // 消息推送给用户
  326. $memberInfo = isset($orderInfo['member'])? $orderInfo['member'] : [];
  327. $nickname = isset($memberInfo['nickname'])? $memberInfo['nickname'] : '';
  328. if($memberInfo){
  329. $params = [
  330. 'title' => "订单异常通知",
  331. 'description' => "您的订单【{$orderNo}】已被平台处理为异常订单,请及时查看订单进度",
  332. 'type' => 2, // 1-公告通知,2-订单通知,3-交易通知,4-其他
  333. 'content' => json_encode([
  334. 'order_no' => ['name' => '订单号', 'text' => $orderNo],
  335. 'catch_time' => ['name' => '处理时间', 'text' => date('Y-m-d H:i:s')],
  336. 'realname' => ['name' => '司机', 'text' => $realname],
  337. 'remark' => ['name' => '异常备注', 'text' => $remark],
  338. 'status' => ['name' => '状态', 'text' => '订单异常'],
  339. ], 256),
  340. 'bind_id' => $id,
  341. ];
  342. // 推送消息给用户处理
  343. MessageService::make()->pushMessage($orderUserId, $params);
  344. }
  345. // 消息推送给司机
  346. if($driverInfo){
  347. $params = [
  348. 'title' => "订单异常通知",
  349. 'description' => "您的订单【{$orderNo}】已被平台处理为异常订单,请及时查看订单进度",
  350. 'type' => 2, // 1-公告通知,2-订单通知,3-交易通知,4-其他
  351. 'content' => json_encode([
  352. 'order_no' => ['name' => '订单号', 'text' => $orderNo],
  353. 'catch_time' => ['name' => '处理时间', 'text' => date('Y-m-d H:i:s')],
  354. 'nickname' => ['name' => '用户', 'text' => $nickname],
  355. 'remark' => ['name' => '异常备注', 'text' => $remark],
  356. 'status' => ['name' => '状态', 'text' => '订单异常'],
  357. ], 256),
  358. 'bind_id' => $id,
  359. ];
  360. // 推送消息给用户处理
  361. MessageService::make()->pushMessage($orderDriverId, $params, 2);
  362. }
  363. // 设置日志标题
  364. ActionLogModel::setTitle("订单异常处理");
  365. ActionLogModel::record();
  366. // 更新校验数据
  367. $cacheCheckKey = "caches:orders:check:{$id}";
  368. $data = [
  369. 'status'=> 6,
  370. 'order_no'=> $orderNo,
  371. 'pay_money'=> $orderInfo['pay_money'],
  372. 'cancel_type'=> 3,
  373. ];
  374. RedisService::set($cacheCheckKey, $data, rand(10,20));
  375. $this->error = 1002;
  376. return true;
  377. }
  378. /**
  379. * 订单取消
  380. * @return bool
  381. */
  382. public function cancel()
  383. {
  384. $params = request()->post();
  385. if(!\App\Services\Api\OrderService::make()->cancel(0, $params,4)){
  386. $this->error = \App\Services\Api\OrderService::make()->getError();
  387. return false;
  388. }else{
  389. // 设置日志标题
  390. ActionLogModel::setTitle("订单取消处理");
  391. ActionLogModel::record();
  392. $this->error = \App\Services\Api\OrderService::make()->getError();
  393. return true;
  394. }
  395. }
  396. /**
  397. * 订单完成
  398. * @return bool
  399. */
  400. public function complete()
  401. {
  402. $params = request()->post();
  403. if(!\App\Services\Api\OrderService::make()->complete(0, $params,4)){
  404. $this->error = \App\Services\Api\OrderService::make()->getError();
  405. return false;
  406. }else{
  407. // 设置日志标题
  408. ActionLogModel::setTitle("订单完成处理");
  409. ActionLogModel::record();
  410. $this->error = \App\Services\Api\OrderService::make()->getError();
  411. return true;
  412. }
  413. }
  414. /**
  415. * 删除
  416. * @return array
  417. */
  418. public function delete()
  419. {
  420. RedisService::keyDel("caches:orders:check*");
  421. return parent::delete(); // TODO: Change the autogenerated stub
  422. }
  423. }