SharerService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <?php
  2. namespace addons\WechatVideoShop\common\service;
  3. use addons\WechatVideoShop\common\enums\WechatVideoShopEnums;
  4. use addons\WechatVideoShop\common\expand\sdk\weixin\src\model\sharer\SharerListModel;
  5. use addons\WechatVideoShop\common\expand\sdk\weixin\src\model\sharer\SharerUnbindModel;
  6. use addons\WechatVideoShop\common\expand\sdk\weixin\src\request\sharer\SharerListRequest;
  7. use addons\WechatVideoShop\common\expand\sdk\weixin\src\request\sharer\SharerUnbindRequest;
  8. use addons\WechatVideoShop\common\helper\WechatRequestHelper;
  9. use addons\WechatVideoShop\common\logic\ConditionUpgradeLogic;
  10. use addons\WechatVideoShop\common\logic\SyncSharerLogic;
  11. use addons\WechatVideoShop\common\models\WechatVideoShop;
  12. use addons\WechatVideoShop\common\models\WechatVideoShopLevel;
  13. use addons\WechatVideoShop\common\models\WechatVideoShopOrder;
  14. use addons\WechatVideoShop\common\models\WechatVideoShopSharer;
  15. use common\enums\AddonsEnum;
  16. use common\enums\RabbitMqEnum;
  17. use common\enums\StatusEnum;
  18. use common\helpers\FormatHelper;
  19. use common\models\order\Order;
  20. use common\models\user\User;
  21. use common\models\user\UserInfo;
  22. class SharerService extends AbstractService
  23. {
  24. /**
  25. * 分销员
  26. * @param int $mall_id
  27. * @param array $params
  28. * @return array|false|mixed|string|void
  29. */
  30. public function page(int $mall_id, array $params)
  31. {
  32. $where = [
  33. ['mall_id' => $mall_id],
  34. ['status' => StatusEnum::ENABLED]
  35. ];
  36. if (!empty($params['shop_id'])) {
  37. $where[] = ['shop_id' => $params['shop_id']];
  38. }
  39. if (!empty($params['level'])) {
  40. $where[] = ['level' => $params['level']];
  41. }
  42. if (!empty($params['member'])) {
  43. $uids = User::find()
  44. ->where(['mall_id' => $mall_id])
  45. ->andWhere(['or', ['like', 'username', $params['member']], ['like', 'mobile', $params['member']], ['like', 'nickname', $params['member']]])
  46. ->select('id')->column();
  47. if (empty($uids)) return [];
  48. $where[] = ['user_id' => $uids];
  49. }
  50. if (!empty($params['status'])) {
  51. if ($params['status'] == 1) { // 100已绑定,1未绑定
  52. $where[] = ['user_id' => 0];
  53. } else {
  54. $where[] = ['>', 'user_id', 0];
  55. }
  56. }
  57. // 邀请时间
  58. if (!empty($params['invite_start_date'])) $where[] = ['>=', 'invite_at', strtotime($params['invite_start_date'])];
  59. if (!empty($params['invite_end_date'])) $where[] = ['<=', 'invite_at', strtotime($params['invite_end_date'])];
  60. // 绑定时间
  61. if (!empty($params['bind_start_date'])) $where[] = ['>=', 'bind_at', strtotime($params['bind_start_date'])];
  62. if (!empty($params['bind_end_date'])) $where[] = ['<=', 'bind_at', strtotime($params['bind_end_date'])];
  63. $ret = WechatVideoShopSharer::listPage([
  64. 'where' => $where,
  65. 'limit' => $params['limit'] ?? 10,
  66. 'page' => $params['page'] ?? 1,
  67. 'order' => 'id desc',
  68. 'with' => ['user', 'shop' => function($query) {
  69. $query->select('id, name');
  70. }]
  71. ]);
  72. if (!empty(WechatVideoShop::getStaticError())) return WechatVideoShop::getStaticError();
  73. return $ret;
  74. }
  75. /**
  76. * 废弃
  77. * @param int $mall_id
  78. * @param array $params
  79. * @return array|string
  80. * @throws \Exception
  81. */
  82. public function index(int $mall_id, array $params)
  83. {
  84. $request = new SharerListRequest($this->config);
  85. $shareModel = new SharerListModel();
  86. $shareModel->page = intval($params['page'] ?? 1);
  87. $shareModel->page_size = intval($params['limit'] ?? 10);
  88. $shareModel->sharer_type = intval($params['sharer_type'] ?? 1);
  89. $resp = WechatRequestHelper::accessTokenAndToArray($request, $shareModel);
  90. if (!empty($resp['sharer_info_list'])) {
  91. $openIds = array_column($resp['sharer_info_list'], "openid");
  92. // 获取用户
  93. $users = $this->getSharerByOpenIds($mall_id, $openIds);
  94. $flag = $this->checkBind($mall_id, $users, $resp['sharer_info_list'], $openIds, $params['shop_id']);
  95. if (is_string($flag)) return $flag;
  96. if ($flag === true) { // 需要重载
  97. $users = $this->getSharerByOpenIds($mall_id, $openIds);
  98. }
  99. foreach ($resp['sharer_info_list'] as &$item) {
  100. $item['sharer'] = $users[$item['openid']] ?? null;
  101. }
  102. return $resp['sharer_info_list'];
  103. }
  104. return [];
  105. }
  106. /**
  107. * @param int $mall_id
  108. * @param array $openIds
  109. * @return false|mixed|string
  110. */
  111. protected function getSharerByOpenIds(int $mall_id, array $openIds)
  112. {
  113. $users = WechatVideoShopSharer::lists([
  114. 'where' => [
  115. ['mall_id' => $mall_id],
  116. ['openid' => $openIds],
  117. ['status' => StatusEnum::ENABLED],
  118. ],
  119. 'with' => ['user' => function($query) {
  120. $query->select('id, username, nickname, avatar_url, mobile');
  121. }, 'shop'],
  122. 'index' => 'openid'
  123. ]);
  124. if (!empty(WechatVideoShopSharer::getStaticError())) return WechatVideoShopSharer::getStaticError();
  125. return $users;
  126. }
  127. /**
  128. * 检测是否需要绑定
  129. * @param int $mall_id
  130. * @param array $users
  131. * @param array $sharers
  132. * @param array $openIds
  133. * @param int $shop_id
  134. * @return bool|string
  135. */
  136. protected function checkBind(int $mall_id, array $users, array $sharers, array $openIds, int $shop_id)
  137. {
  138. throw new \Exception("废弃方法");
  139. $tmp_sharers = [];
  140. foreach ($sharers as $sharer) {
  141. $tmp_sharers[$sharer['openid']] = $sharer;
  142. }
  143. // 判断是否有绑定过
  144. $userInfos = UserInfo::lists([
  145. 'where' => [
  146. ['mall_id' => $mall_id],
  147. ['openid' => $openIds],
  148. ['status' => StatusEnum::ENABLED]
  149. ],
  150. 'index' => 'openid'
  151. ]);
  152. $ret = false;
  153. if (!empty($userInfos)) {
  154. // 需要绑定用户
  155. foreach ($userInfos as $openid => $userInfo) {
  156. if (empty($users[$openid])) {
  157. $data = $tmp_sharers[$openid];
  158. $data['user_id'] = $userInfo['user_id'];
  159. $data['shop_id'] = $shop_id;
  160. // 执行绑定
  161. $flag = $this->bind($mall_id, $data, false);
  162. if (is_string($flag)) return $flag;
  163. $ret = true;
  164. }
  165. }
  166. }
  167. return $ret;
  168. }
  169. /**
  170. * 绑定
  171. * @param int $mall_id
  172. * @param array $params
  173. * @param bool $bind_user_info
  174. * @return true|string
  175. */
  176. public function bind(int $mall_id, array $params, bool $bind_user_info = true)
  177. {
  178. $sharer = WechatVideoShopSharer::getOne([
  179. ['mall_id' => $mall_id],
  180. ['openid' => $params['openid']],
  181. ['id' => $params['id']]
  182. ]);
  183. if (empty($sharer)) return '分销员不存在';
  184. if (!empty($sharer->user_id)) return '当前用户已绑定分销员';
  185. $t = \Yii::$app->db->beginTransaction();
  186. try {
  187. $sharer->user_id = $params['user_id'];
  188. $sharer->bind_at = time();
  189. if (!$sharer->save()) throw new \Exception($sharer->getErrorMessage());
  190. // 有可能已经存在
  191. if ($bind_user_info) {
  192. // 用户那边需要加数据
  193. UserInfo::setData([
  194. 'openid' => $params['openid'],
  195. 'unionid' => $params['unionid'],
  196. 'platform' => User::PLATFORM_WECHAT_VIDEO_SHOP,
  197. 'mall_id' => $mall_id,
  198. 'user_id' => $params['user_id']
  199. ]);
  200. if (!empty(UserInfo::getStaticError())) throw new \Exception(UserInfo::getStaticError());
  201. }
  202. // 触发升级
  203. $cond_upgrade = new ConditionUpgradeLogic();
  204. $cond_upgrade->execute(AddonsEnum::ADDONS_NAME_WECHAT_VIDEO_SHOP,
  205. (new WechatVideoShopSharer()), (new WechatVideoShopLevel()), [
  206. 'id' => 0,
  207. 'user_id' => $params['user_id'],
  208. 'mall_id' => $this->config['mall_id']
  209. ]);
  210. $t->commit();
  211. } catch (\Exception $e) {
  212. $t->rollBack();
  213. return $e->getMessage();
  214. }
  215. return true;
  216. }
  217. /**
  218. * 解绑
  219. * @param int $mall_id
  220. * @param array $params
  221. * @return string|true
  222. */
  223. public function unbind(int $mall_id, array $params)
  224. {
  225. try {
  226. $config = (new ShopService())->getShop($params['shop_id']);
  227. // 请求微信端
  228. $sharerRequest = new SharerUnbindRequest($config);
  229. $sharerModel = new SharerUnbindModel();
  230. $sharerModel->openid_list = [
  231. $params['openid']
  232. ];
  233. WechatRequestHelper::accessTokenAndToArray($sharerRequest, $sharerModel);
  234. $sharer = WechatVideoShopSharer::getOne([
  235. ['mall_id' => $mall_id],
  236. ['openid' => $params['openid']]
  237. ]);
  238. // 删除分销员
  239. if (!empty($sharer)) {
  240. $t = \Yii::$app->db->beginTransaction();
  241. $sharer->status = StatusEnum::DELETE;
  242. if (!$sharer->save()) throw new \Exception($sharer->getErrorMessage());
  243. $userInfo = UserInfo::getOne([
  244. ['mall_id' => $mall_id],
  245. ['openid' => $params['openid']]
  246. ]);
  247. if (!empty($userInfo)) {
  248. $userInfo->status = StatusEnum::DELETE;
  249. if (!$userInfo->save()) throw new \Exception($userInfo->getErrorMessage());
  250. }
  251. $t->commit();
  252. }
  253. } catch (\Exception $e) {
  254. if (!empty($t)) $t->rollBack();
  255. return $e->getMessage();
  256. }
  257. return true;
  258. }
  259. /**
  260. * 同步分销员
  261. * @param array $params
  262. * @return bool 如果返回false则跳过循环,否则继续下一页
  263. * @throws \Exception
  264. */
  265. public function sync(array $params): bool
  266. {
  267. $request = new SharerListRequest($this->config);
  268. $shareModel = new SharerListModel();
  269. $shareModel->page = intval($params['page'] ?? 1);
  270. $shareModel->page_size = intval($params['limit'] ?? 10);
  271. $shareModel->sharer_type = intval($params['sharer_type'] ?? 1);
  272. $resp = WechatRequestHelper::accessTokenAndToArray($request, $shareModel);
  273. // 写入
  274. if (!empty($resp['sharer_info_list'])) {
  275. $openIds = array_column($resp['sharer_info_list'], "openid");
  276. $unionids = array_column($resp['sharer_info_list'], "unionid", "openid");
  277. $local_sharers = WechatVideoShopSharer::find()
  278. ->where(['shop_id' => $this->shop_id])
  279. ->andWhere(['mall_id' => $this->mall_id])
  280. ->andWhere(['status' => StatusEnum::ENABLED])
  281. ->andWhere(['openid' => $openIds])->select('openid')->column();
  282. if (count($local_sharers) != count($resp['sharer_info_list'])) {
  283. // 所以需要处理
  284. foreach ($resp['sharer_info_list'] as $item) {
  285. if (!empty(!in_array($item['openid'], $local_sharers))) {
  286. if (!empty($unionids[$item['openid']])) { // 查找用户
  287. $userInfo = UserInfo::getOne([
  288. ['mall_id' => $this->mall_id],
  289. ['unionid' => $unionids[$item['openid']]]
  290. ]);
  291. if (!empty($userInfo)) {
  292. UserInfo::setData([
  293. 'openid' => $item['openid'],
  294. 'unionid' => $item['unionid'],
  295. 'platform' => User::PLATFORM_WECHAT_VIDEO_SHOP,
  296. 'mall_id' => $this->mall_id,
  297. 'user_id' => $userInfo->user_id
  298. ]);
  299. if (!empty(UserInfo::getStaticError())) throw new \Exception(UserInfo::getStaticError());
  300. }
  301. }
  302. // 这个需要写入
  303. $sharerModel = new WechatVideoShopSharer();
  304. $sharerModel->mall_id = $this->config['mall_id'];
  305. $sharerModel->shop_id = $this->shop_id;
  306. $sharerModel->openid = $item['openid'];
  307. $sharerModel->unionid = $item['unionid'];
  308. $sharerModel->invite_at = $item['bind_time'];
  309. $sharerModel->sharer_type = $item['sharer_type'];
  310. $sharerModel->nickname = $item['nickname'];
  311. $sharerModel->user_id = !empty($userInfo) ? $userInfo->user_id : 0; // 绑定用户
  312. $sharerModel->bind_at = $sharerModel->user_id > 0 ? time() : 0; // 绑定时间
  313. if (!$sharerModel->save()) {
  314. \Yii::error(__METHOD__ . " 同步分销员失败 " . $sharerModel->getErrorMessage());
  315. }
  316. // 触发条件升级
  317. if (!empty($sharerModel->user_id)) {
  318. $cond_upgrade = new ConditionUpgradeLogic();
  319. $cond_upgrade->execute(AddonsEnum::ADDONS_NAME_WECHAT_VIDEO_SHOP,
  320. (new WechatVideoShopSharer()), (new WechatVideoShopLevel()), [
  321. 'id' => 0,
  322. 'user_id' => $sharerModel->user_id,
  323. 'mall_id' => $this->config['mall_id']
  324. ]);
  325. }
  326. }
  327. }
  328. return true;
  329. } else {
  330. WechatVideoShopSharer::updateAll(['status' => StatusEnum::ENABLED], ['and', ['shop_id' => $this->shop_id],
  331. ['mall_id' => $this->config['mall_id']], ['in', 'openid', $openIds]]);
  332. }
  333. }
  334. return false;
  335. }
  336. /**
  337. * 异步同步
  338. * @return void
  339. * @throws \Exception
  340. */
  341. public function async()
  342. {
  343. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE,
  344. [], SyncSharerLogic::class, 'sharer');
  345. }
  346. /**
  347. * 客户列表
  348. * @param int $mall_id
  349. * @param array $params
  350. * @return array|false|mixed|string|null
  351. */
  352. public function customerList(int $mall_id, array $params)
  353. {
  354. $where = [
  355. ['mall_id' => $mall_id],
  356. ['status' => StatusEnum::ENABLED],
  357. ['parent_id' => $params['parent_id']]
  358. ];
  359. if (!empty($params['user_id'])) {
  360. $where[] = ['user_id' => $params['user_id']];
  361. } else if (!empty($params['keyword'])) {
  362. $uids = User::find()->where(['mall_id' => $mall_id])
  363. ->andWhere(['or', ['like', 'nickname', $params['keyword']], ['like', 'mobile', $params['keyword']]])
  364. ->select('id')->column();
  365. if (empty($uids)) return [];
  366. $where[] = ['user_id' => $uids];
  367. }
  368. if (!empty($params['start_date'])) $where[] = ['>=', 'created_at', strtotime($params['start_date'])];
  369. if (!empty($params['end_date'])) $where[] = ['<=', 'created_at', strtotime($params['end_date'])];
  370. $ret = WechatVideoShopOrder::listPage([
  371. 'where' => $where,
  372. 'limit' => $params['limit'] ?? 10,
  373. 'order' => 'id desc',
  374. 'group' => 'user_id',
  375. 'with' => ['user' => function($query) {
  376. $query->select('id, nickname, username, mobile, created_at, avatar_url');
  377. }]
  378. ]);
  379. if (!empty(WechatVideoShopOrder::getStaticError())) return WechatVideoShopOrder::getStaticError();
  380. if (!empty($ret['list'])) {
  381. $uids = array_column($ret['list'], 'user_id');
  382. // 订单数量,支付金额
  383. $cnt = Order::find()->where(['mall_id' => $mall_id])
  384. ->andWhere(['pay_status' => StatusEnum::ENABLED])
  385. ->andWhere(['user_id' => $uids])
  386. ->andWhere(['order_source' => WechatVideoShopEnums::ADDONS_NAME])
  387. ->select('COUNT(*) as cnt, user_id')->groupBy('user_id')->asArray()->all();
  388. $amount = Order::find()->where(['mall_id' => $mall_id])
  389. ->andWhere(['pay_status' => StatusEnum::ENABLED])
  390. ->andWhere(['user_id' => $uids])
  391. ->andWhere(['order_source' => WechatVideoShopEnums::ADDONS_NAME])
  392. ->select('SUM(pay_money) as amount, user_id')->groupBy('user_id')->asArray()->all();
  393. $cnt_map = array_column($cnt, 'cnt', 'user_id');
  394. $amount_map = array_column($amount, 'amount', 'user_id');
  395. foreach ($ret['list'] as &$item) {
  396. $item['order_num'] = $cnt_map[$item['user_id']] ?? 0;
  397. $item['pay_amount'] = $amount_map[$item['user_id']] ?? 0;
  398. }
  399. }
  400. return $ret;
  401. }
  402. }