OrderService.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. <?php
  2. namespace addons\ValetOrder\common\service;
  3. use addons\ValetOrder\common\enums\ValetOrderEnum;
  4. use addons\ValetOrder\common\logic\order\OrderMarketingLogicV2;
  5. use addons\ValetOrder\common\models\ValetOrder;
  6. use addons\ValetOrder\common\models\ValetOrderGoods;
  7. use common\enums\GlobalFuncEnum;
  8. use common\enums\MarketingTypeEnum;
  9. use common\enums\OrderSourceEnum;
  10. use common\enums\OrderStatusEnum;
  11. use common\enums\ShippingTypeEnum;
  12. use common\enums\StatusEnum;
  13. use common\events\user\UserRegisterEvent;
  14. use common\globals\GlobalInvoke;
  15. use common\helpers\FormatHelper;
  16. use common\logic\order\BaseOrderForm;
  17. use common\models\goods\Goods;
  18. use common\models\goods\GoodsAttr;
  19. use common\models\order\Order;
  20. use common\models\order\OrderDetail;
  21. use common\models\user\User;
  22. use common\models\user\UserPartitionRelationship;
  23. use RuntimeException;
  24. use Yii;
  25. use yii\helpers\Json;
  26. class OrderService
  27. {
  28. public function page(int $mall_id, array $params)
  29. {
  30. $where = [
  31. ['mall_id' => $mall_id],
  32. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]
  33. ];
  34. // 买家
  35. if (!empty($params['user_id'])) {
  36. $where[] = ['user_id' => $params['user_id']];
  37. }
  38. if (!empty($params['user'])) {
  39. $uids = User::find()
  40. ->where(['mall_id' => $mall_id])
  41. ->andWhere(['status' => StatusEnum::ENABLED])
  42. ->andWhere(['or', ['like', 'username', $params['user']], ['like', 'nickname', $params['user']], ['like', 'mobile', $params['user']]])
  43. ->select('id')
  44. ->column();
  45. if (empty($uids)) return [];
  46. $where[] = ['user_id' => $uids];
  47. }
  48. if (isset($params['buy_user_id']) && $params['buy_user_id'] !== '') {
  49. $where[] = ['buy_user_id' => intval($params['buy_user_id'])];
  50. }
  51. if (!empty($params['buy_user'])) {
  52. $uids = User::find()
  53. ->where(['mall_id' => $mall_id])
  54. ->andWhere(['status' => StatusEnum::ENABLED])
  55. ->andWhere(['or', ['like', 'username', $params['buy_user']], ['like', 'nickname', $params['buy_user']], ['like', 'mobile', $params['buy_user']]])
  56. ->select('id')
  57. ->column();
  58. if (empty($uids)) return [];
  59. $where[] = ['buy_user_id' => $uids];
  60. }
  61. if (!empty($params['start_date'])) $where[] = ['>=', 'created_at', strtotime($params['start_date'])];
  62. if (!empty($params['end_date'])) $where[] = ['<=', 'created_at', strtotime($params['end_date'])];
  63. if (!empty($params['goods_name'])) $where[] = ['like', 'order_goods_names', $params['goods_name']];
  64. $ret = ValetOrder::listPage([
  65. 'where' => $where,
  66. 'order' => 'id desc',
  67. 'limit' => $params['limit'] ?? 10,
  68. 'with' => ['user', 'buyUser', 'order' => function($query) {
  69. $query->with(['detail']);
  70. }]
  71. ]);
  72. if (!empty(ValetOrder::getStaticError())) return ValetOrder::getStaticError();
  73. if (!empty($ret['list'])) {
  74. foreach ($ret['list'] as &$item) {
  75. if (empty($item['buyUser'])) {
  76. $item['buyUser'] = [
  77. 'id' => 0,
  78. 'nickname' => '平台',
  79. 'avatar_url'=> '',
  80. 'mobile' => '',
  81. ];
  82. }
  83. }
  84. }
  85. array_unshift($where, 'AND');
  86. $ret['total_amount'] = ValetOrder::find()->where($where)->sum("order_amount");
  87. return $ret;
  88. }
  89. public function frontPage(int $mall_id, int $user_id, array $data, array $mall, string $platform)
  90. {
  91. // 通过用户ID去取数据
  92. $head_where = [
  93. ['mall_id' => $mall_id],
  94. ['buy_user_id' => $user_id],
  95. ['status' => StatusEnum::ENABLED]
  96. ];
  97. if (isset($data['order_status']) && $data['order_status'] != 999) {
  98. if ($data['order_status'] == OrderStatusEnum::SING) { // 如果筛选的是已收货的订单那么就将已提货的订单一起取出来
  99. $data['order_status'] = [OrderStatusEnum::SING, OrderStatusEnum::TAKE_FINISH];
  100. }
  101. $head_where[] = ['order_status' => $data['order_status']];
  102. } else {
  103. if (!empty($data['wait_pending'])) {
  104. $head_where[] = ['not in', 'order_status', [OrderStatusEnum::ACCOMPLISH, OrderStatusEnum::REPEAL,
  105. OrderStatusEnum::TAKE_FINISH, OrderStatusEnum::SING]]; // 排除 已完成, 已关闭, 已自提, 已签收
  106. }
  107. }
  108. if (!empty($data['keyword'])) {
  109. $u_ids = User::find()->where(['mall_id' => $mall_id])
  110. ->andWhere(['or', ['like', 'mobile', $data['keyword']], ['like', 'nickname', $data['keyword']]])
  111. ->select('id')
  112. ->column();
  113. if (!empty($u_ids)) {
  114. $head_where[] = ['user_id' => $u_ids];
  115. } else {
  116. $head_where[] = ['user_id' => 0];
  117. }
  118. }
  119. $map['where'] = $head_where;
  120. $map['select'] = 'id, order_id';
  121. $map['limit'] = $data['limit'] ?? 5;
  122. // $map['page'] = $params['page'] ?? 1;
  123. $map['order'] = 'id desc';
  124. $ret = ValetOrder::listPage($map);
  125. if (!empty($ret['list'])) {
  126. $order_ids = array_column($ret['list'], 'order_id');
  127. $where[] = ['in', 'id', $order_ids];
  128. $where[] = ['is_feedback' => OrderStatusEnum::NOT_FEEDBACK];
  129. $where[] = ['!=', 'order_source', OrderSourceEnum::SOURCE_SELF_MALL];
  130. $select = 'id,pay_money,order_status,shipping_type,is_recycle,marketing_type,extra_info,order_source,store_id,mch_id,receiver_name,mobile,
  131. consign_time, mall_id, order_no, created_at';
  132. $params['order'] = 'pay_time desc';
  133. $params['select'] = $select;
  134. $params['where'] = $where;
  135. $params['with'] = ['detail' => function ($query) {
  136. $query->select('id,order_id,goods_id,goods_name,pic_url,goods_attr_id,num,price,is_feedback,sign_id,goods_attr_name,extra_info,adjust_money');
  137. }];
  138. $order_list = Order::lists($params);
  139. $ret['mall_logo'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo');
  140. if (!empty($order_list)) {
  141. foreach ($order_list as $key => $val) {
  142. array_map(function ($arg) use (&$val) {
  143. if (!isset($val['num'])) $val['num'] = 0;
  144. $val['num'] += $arg['num'];
  145. }, $val['detail']);
  146. // 剩余库存
  147. $stock = [];
  148. if($val['detail']){
  149. foreach ($val['detail'] as $k => $v){
  150. $order_list[$key]['detail'][$k]['price'] = $order_list[$key]['detail'][$k]['price'] + $order_list[$key]['detail'][$k]['adjust_money'];
  151. $order_list[$key]['detail'][$k]['price'] = round($order_list[$key]['detail'][$k]['price'],2);
  152. $goods_unit = Goods::getOne([['=','id',$v['goods_id']]],false,'','','unit')['unit'];
  153. $val['detail'][$k]['unit'] = $goods_unit;
  154. // 当订单关闭时可以直接再次购买
  155. if ($val['order_status'] == OrderStatusEnum::REPEAL) {
  156. // 查询商品是否有货
  157. $stock[] = [
  158. 'num' => $v['num'],
  159. 'store_id' => $v['store_id']??0,
  160. 'goods_id' => $v['goods_id'],
  161. 'attr_id' => $v['goods_attr_id'],
  162. 'stock' => GoodsAttr::find()->where(['id' => $v['goods_attr_id']])->select('stock')->scalar(),
  163. ];
  164. }
  165. }
  166. }
  167. // 获取支付金额
  168. $order_list[$key] = GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $mall_id, [
  169. 'order' => $val,
  170. 'mall_id' => $mall_id,
  171. ]) ?: $val;
  172. $order_list[$key]['mall_name'] = $mall['name'];
  173. $order_list[$key]['mall_logo'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo');
  174. // 判断是否可以再次购买
  175. $is_agent = empty($stock) ? 0 : 1;
  176. foreach ($stock as $v) {
  177. // 当库存小于购买数量 不可再次购买
  178. if ($v['stock'] < $v['num']) {
  179. $is_agent = 0;
  180. }
  181. }
  182. $order_list[$key]['is_agent'] = $is_agent;
  183. $order_list[$key]['extra_info'] = Json::decode($order_list[$key]['extra_info']);
  184. $order_list[$key]['is_agent_data'] = $is_agent ? $stock : [];
  185. $order_list[$key]['created_at'] = date('Y-m-d H:i:s', $order_list[$key]['created_at']);
  186. }
  187. $order_list = GlobalInvoke::exec(GlobalFuncEnum::ORDER_LIST, $mall_id, [
  188. 'order' => $order_list, 'mall_id' => $mall_id
  189. ]) ?: $order_list;
  190. $ret['shipping_type_text'] = ShippingTypeEnum::getMap();
  191. $ret['order_status_text'] = OrderStatusEnum::getMap();
  192. $ret['order_status_text'][OrderStatusEnum::SHIPMENTS] = '待取货';
  193. $ret['is_feedback_text'] = OrderStatusEnum::getFeedbackMap();
  194. }
  195. $ret['pay_type_list'] = \Yii::$app->services->pay->getEnablePayment($mall_id, $platform);
  196. $ret['marketing_type_map'] = MarketingTypeEnum::getMap();
  197. $ret['list'] = $order_list;
  198. }
  199. return $ret;
  200. }
  201. /**
  202. * @param array $orders
  203. * @param array $ext
  204. * @return true
  205. * @throws \Exception
  206. */
  207. public function create(array $orders, array $ext)
  208. {
  209. $t = \Yii::$app->db->beginTransaction();
  210. try {
  211. // 获取上级且注册账号
  212. $users = [];
  213. // 新增用户列表
  214. $add_new_users = [];
  215. foreach ($ext as $order_id => $info) {
  216. $parent_id = $orders[0]['buy_user_id']; // 默认上级
  217. if (!empty($info['parent'])) {
  218. $pid = User::find()->where(['mall_id' => $orders[0]['mall_id']])
  219. ->andWhere(['mobile' => $info['parent']])->select('id')->scalar();
  220. if (!empty($pid)) $parent_id = $pid;
  221. }
  222. // 判断当前用户是否存在
  223. if (empty($users[$info['mobile']])) {
  224. $user = User::getOne([
  225. ['mall_id' => $orders[0]['mall_id']],
  226. ['mobile' => $info['mobile']],
  227. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]
  228. ]);
  229. if (empty($user)) {
  230. // 实施注册
  231. $user = User::setData([
  232. 'parent_id' => $parent_id,
  233. 'nickname' => '代客下单用户',
  234. 'mobile' => $info['mobile'],
  235. 'mall_id' => $orders[0]['mall_id'],
  236. 'username' => "{$info['mobile']}",
  237. 'source' => User::SOURCE_VALET_ORDER,
  238. 'platform' => User::PLATFORM_H5,
  239. 'password' => Yii::$app->getSecurity()->generatePasswordHash(substr($info['mobile'],-6,6))
  240. ]);
  241. if ($user) {
  242. $add_new_users[] = $user;
  243. }
  244. } else {
  245. // 判断当前老用户是否没有上级,如果没有的话那么就需要指定上级
  246. if (empty($user->parent_id) && !empty($parent_id)) {
  247. // 考虑代下单的对象是自己团队的上级并且浏览路径是平台
  248. $parentIds = UserPartitionRelationship::getParentIdArr($parent_id);
  249. if (!in_array($user->id, $parentIds)) {
  250. // 给其更改上级
  251. $flag = UserPartitionRelationship::changeRelationship([
  252. 'user_id' => $user->id,
  253. 'parent_id' => $parent_id,
  254. 'operator_user_id' => $orders[0]['buy_user_id']
  255. ]);
  256. if ($flag === false) throw new \Exception("修改关系链失败");
  257. }
  258. }
  259. }
  260. if (!$user) throw new \Exception(User::getStaticError()); // 注册失败
  261. $users[$info['mobile']] = $user;
  262. }
  263. }
  264. // 创建订单
  265. foreach ($orders as &$order) {
  266. $uid = $users[$ext[$order['order_id']]['mobile']]->id;
  267. $order['user_id'] = $uid;
  268. // 修改订单所属人
  269. Order::updateAll(['user_id' => $uid, 'marketing_type' => ValetOrderEnum::ADDONS_NAME], ['id' => $order['order_id']]);
  270. OrderDetail::updateAll(['user_id' => $uid], ['order_id' => $order['order_id']]);
  271. }
  272. // 执行
  273. \Yii::$app->db->createCommand()->batchInsert(ValetOrder::tableName(), array_keys($orders[0]), $orders)->execute();
  274. $t->commit();
  275. if (!empty($add_new_users)) {
  276. foreach ($add_new_users as $user) {
  277. // 触发注册成功事件,事务提交完成后触发
  278. $event = new UserRegisterEvent($user->mall_id);
  279. $data = ['user_id' => $user->id, 'platform' => 'h5'];
  280. Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  281. }
  282. }
  283. } catch (\Exception $e) {
  284. $t->rollBack();
  285. var_dump($e->getMessage(), $e->getFile(), $e->getLine());
  286. \Yii::error(FormatHelper::exception($e, __METHOD__));
  287. throw new \Exception($e->getMessage());
  288. }
  289. // 执行写入
  290. return true;
  291. }
  292. /**
  293. * @param int $order_id
  294. * @param int $status
  295. * @return true
  296. * @throws \Exception
  297. */
  298. public function update(int $order_id, int $status)
  299. {
  300. $order = ValetOrder::getOne([
  301. ['order_id' => $order_id]
  302. ]);
  303. if (empty($order)) return true;
  304. // 判断有没有开启插件
  305. $config = (new SettingService())->get($order->mall_id);
  306. if (empty($config['is_enable'])) return true;
  307. $order->order_status = $status;
  308. if (!$order->save()) throw new \Exception($order->getErrorMessage());
  309. return true;
  310. }
  311. /**
  312. * 确认订单
  313. * @param array $params
  314. * @return mixed
  315. */
  316. public function preview(array $params)
  317. {
  318. $input = $params['params'];
  319. $response = $params['data'];
  320. // 只能是一件商品
  321. if (count($response['group_order_goods']) > 1) return $response;
  322. $response[ValetOrderEnum::ORDER_EXT_KEY][ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::DISABLED;
  323. $response[ValetOrderEnum::ORDER_EXT_KEY][ValetOrderEnum::ORDER_VALET_SMS_CODE] = StatusEnum::DISABLED;
  324. foreach ($response['group_order_goods'] as $goods) {
  325. if (count($goods['goods']) > 1) return $response;
  326. // 判断当前商品是否能够参与代客下单
  327. $gids = array_keys($goods['goods']);
  328. $valet = ValetOrderGoods::getOne([
  329. ['mall_id' => $params['mall_id']],
  330. ['goods_id' => $gids[0]],
  331. ['status' => StatusEnum::ENABLED],
  332. ], true, [], null, 'id');
  333. if (!empty($valet)) {
  334. $response[ValetOrderEnum::ORDER_EXT_KEY][ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::ENABLED;
  335. }
  336. }
  337. if (!empty($response[ValetOrderEnum::ORDER_EXT_KEY][ValetOrderEnum::ORDER_IS_VALET_KEY])) {
  338. // 需要验证码
  339. $config = (new SettingService())->get($params['mall_id']);
  340. $response[ValetOrderEnum::ORDER_EXT_KEY][ValetOrderEnum::ORDER_VALET_SMS_CODE] = $config['is_enable_sms_code'] ?? StatusEnum::DISABLED;
  341. }
  342. // 是否需要校验短信验证码
  343. return $response;
  344. }
  345. /**
  346. * 公共调用订单详情
  347. * @param $params
  348. * @return mixed
  349. */
  350. public function globalDetail($params)
  351. {
  352. // $params['order'] // 订单主体信息
  353. // 判断是否为代客下单
  354. $params['order'][ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::DISABLED;
  355. if (!empty($params['order']['extra_info']) && $params['order']['marketing_type'] == ValetOrderEnum::ADDONS_NAME) {
  356. try {
  357. $ext = Json::decode($params['order']['extra_info']);
  358. if (!empty($ext[ValetOrderEnum::ORDER_EXT_KEY])) {
  359. // 需要取出下单人
  360. $valetOrder = ValetOrder::getOne([
  361. ['order_id' => $params['order']['id']],
  362. ['mall_id' => $params['order']['mall_id']]
  363. ], true, ['buyUser']);
  364. if (!empty($valetOrder['buyUser'])) {
  365. $config = (new SettingService())->get($params['mall_id']);
  366. $params['order'][ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::ENABLED;
  367. $params['order'][ValetOrderEnum::ORDER_VALET_CAN_REFUND] = $config['is_enable_order_refund'];
  368. $params['order'][ValetOrderEnum::ORDER_VALET_BUYER_KEY] = $valetOrder['buyUser'];
  369. }
  370. }
  371. } catch (\Exception $e) {}
  372. }
  373. return $params['order'];
  374. }
  375. /**
  376. * 公共调用 - 订单列表
  377. * @param $params
  378. * @return mixed
  379. */
  380. public function globalList($params)
  381. {
  382. if (!empty($params['order'])) {
  383. foreach ($params['order'] as &$item) {
  384. $item[ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::DISABLED;
  385. if (!empty($item['extra_info']) && $item['marketing_type'] == ValetOrderEnum::ADDONS_NAME) {
  386. try {
  387. $ext = Json::decode($item['extra_info']);
  388. if (!empty($ext[ValetOrderEnum::ORDER_EXT_KEY])) {
  389. // 需要取出下单人
  390. $valetOrder = ValetOrder::getOne([
  391. ['order_id' => $item['id']],
  392. ['mall_id' => $params['mall_id']]
  393. ], true, ['buyUser']);
  394. if (!empty($valetOrder['buyUser'])) {
  395. $item[ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::ENABLED;
  396. $item[ValetOrderEnum::ORDER_VALET_BUYER_KEY] = $valetOrder['buyUser'];
  397. }
  398. }
  399. } catch (\Exception $e) {}
  400. }
  401. }
  402. }
  403. return $params['order'];
  404. }
  405. /**
  406. * 公共调用 - 总后台订单列表
  407. * @param $params
  408. * @return mixed
  409. */
  410. public function globalBackendLists($params)
  411. {
  412. foreach ($params['order'] as &$item) {
  413. $item[ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::DISABLED;
  414. if (!empty($item['extra_info']) && $item['marketing_type'] == ValetOrderEnum::ADDONS_NAME) {
  415. try {
  416. $ext = Json::decode($item['extra_info']);
  417. if (!empty($ext[ValetOrderEnum::ORDER_EXT_KEY])) {
  418. // 需要取出下单人
  419. $valetOrder = ValetOrder::getOne([
  420. ['order_id' => $params['order']['id']],
  421. ['mall_id' => $params['order']['mall_id']]
  422. ], true, ['buyUser']);
  423. if (!empty($valetOrder['buyUser'])) {
  424. $item[ValetOrderEnum::ORDER_IS_VALET_KEY] = StatusEnum::ENABLED;
  425. $item[ValetOrderEnum::ORDER_VALET_BUYER_KEY] = $valetOrder['buyUser'];
  426. }
  427. }
  428. } catch (\Exception $e) {}
  429. }
  430. }
  431. return $params['order'];
  432. }
  433. /**
  434. * @param $order_id
  435. * @return bool
  436. */
  437. public function refund($order_id)
  438. {
  439. $order = ValetOrder::getOne([['order_id' => $order_id]], true, [], null, 'id');
  440. if (empty($order)) return false;
  441. return true;
  442. }
  443. /**
  444. * @param $order_id
  445. * @return bool
  446. */
  447. public function getValetOrderByOrderId($order_id)
  448. {
  449. return ValetOrder::getOne([['order_id' => $order_id]], true, [], null);
  450. }
  451. /**
  452. * 营销减免,决定使用哪个用户
  453. *
  454. * @param BaseOrderForm $form
  455. *
  456. * @return false|mixed|object
  457. */
  458. public function orderMarketing(BaseOrderForm $form)
  459. {
  460. $settingService = new SettingService;
  461. $originUserId = $form->user_id;
  462. $originUser = $form->user;
  463. $form->process_extra_data['valet_order_origin_user_id'] = $originUserId;
  464. if (!empty($settingService->get($form->mall_id)['is_enable_other_identity_price'])) {
  465. // 输入了手机号并且用户存在
  466. if (
  467. !empty($form->attributes['data']['extra_info']['valet_order']['mobile']) &&
  468. $valetOrderUser = User::getUser([
  469. [
  470. 'mall_id' => $form->mall_id,
  471. 'mobile' => $form->attributes['data']['extra_info']['valet_order']['mobile'],
  472. 'status' => StatusEnum::ENABLED
  473. ]
  474. ])
  475. ) {
  476. $form->user_id = $valetOrderUser->id;
  477. $form->user = $valetOrderUser;
  478. } else {
  479. $form->user_id = $settingService->getValetOrderDefaultUser($form->mall_id);
  480. if (empty($form->user_id)) {
  481. throw new RuntimeException('系统异常');
  482. }
  483. $form->user = User::getOne([['id' => $form->user_id, 'mall_id' => $form->mall_id]]);
  484. if (empty($form->user)) {
  485. throw new RuntimeException('系统异常');
  486. }
  487. }
  488. }
  489. $orderMarketingLogic = new OrderMarketingLogicV2();
  490. $form = $orderMarketingLogic->run($form);
  491. if ($form === false) {
  492. throw new RuntimeException($orderMarketingLogic->getError());
  493. }
  494. $form->user_id = $originUserId;
  495. $form->user = $originUser;
  496. unset($form->process_extra_data['valet_order_origin_user_id']);
  497. return $form;
  498. }
  499. }