UserClass.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. <?php
  2. namespace bizMall\user\classes;
  3. use biz\shop\classes\ShopClass;
  4. use bizHd\custom\classes\CustomClass;
  5. use bizMall\merchant\classes\MerchantAssetClass;
  6. use bizMall\merchant\classes\MerchantClass;
  7. use bizMall\merchant\services\MerchantService;
  8. use bizMall\message\classes\ChatClass;
  9. use bizMall\user\services\UserIntegralService;
  10. use common\components\business;
  11. use common\components\dict;
  12. use common\components\stringUtil;
  13. use common\components\util;
  14. use common\components\wxUtil;
  15. use common\services\ImageService;
  16. use common\services\xhMerchantExtendService;
  17. use common\services\xhUserCapitalService;
  18. use common\services\xhUserIntegralService;
  19. use common\services\xhUserMergeService;
  20. use Yii;
  21. use bizMall\base\classes\BaseClass;
  22. class UserClass extends BaseClass
  23. {
  24. public static $baseFile = '\bizMall\user\models\User';
  25. //用户和收入的来源
  26. public static $sourceType = [
  27. 2 => '朋友圈',
  28. 1 => '门店',
  29. 0 => '公众号',
  30. 3 => '淘宝',
  31. ];
  32. //用户来源分类
  33. public static $userSource = [
  34. 0 => ['name' => 'official', 'title' => '公众号'],
  35. 1 => ['name' => 'alipay', 'title' => '支付宝'],
  36. 2 => ['name' => 'mini', 'title' => '小程序'],
  37. 3 => ['name' => 'friend', 'title' => '朋友圈'],
  38. 4 => ['name' => 'meituan', 'title' => '美团'],
  39. 5 => ['name' => 'system', 'title' => '系统'],
  40. ];
  41. //用户来源分类ID
  42. public static $userSourceId = [
  43. 'official' => ['id' => 0, 'name' => 'official'],
  44. 'alipay' => ['id' => 1, 'name' => 'alipay'],
  45. 'mini' => ['id' => 2, 'name' => 'mini'],
  46. 'friend' => ['id' => 3, 'name' => 'friend'],
  47. 'meituan' => ['id' => 4, 'name' => 'meituan'],
  48. 'system' => ['id' => 5, 'name' => 'system'],
  49. ];
  50. //最近访问的门店 ssh 2021.4.10
  51. public static function getRecentShop($user)
  52. {
  53. $recent = $user['recentShop'];
  54. $list = [];
  55. if (!empty($recent)) {
  56. $ids = json_decode($recent, true);
  57. $list = ShopClass::getShopByIds($ids);
  58. foreach ($list as $key => $val) {
  59. $shopName = $val['shopName'] ?? '';
  60. $sjName = $val['merchantName'] ?? '';
  61. $default = $val['default'] ?? 0;
  62. $showName = $sjName . ' ' . $shopName;
  63. if ($default == 1) {
  64. $showName = $sjName;
  65. }
  66. $list[$key]['showName'] = $showName;
  67. }
  68. }
  69. return $list;
  70. }
  71. //添加最近访问的门店 ssh 2021.4.10
  72. public static function addRecentShop($lookShopId, $user)
  73. {
  74. if (empty($lookShopId)) {
  75. return false;
  76. }
  77. $hasRecentShop = $user['recentShop'];
  78. $userId = $user['id'];
  79. $newShopIds = [];
  80. if (!empty($hasRecentShop)) {
  81. $newShopIds = json_decode($hasRecentShop, true);
  82. }
  83. $newShopIds = array_merge($newShopIds, [$lookShopId]);
  84. $newShopIds = array_unique(array_filter($newShopIds));
  85. self::updateById($userId, ['recentShop' => json_encode($newShopIds)]);
  86. }
  87. //组合客户基本和资产信息
  88. public static function groupUserBaseInfo($list)
  89. {
  90. //取客户资产
  91. $ids = array_column($list, 'id');
  92. $ids = array_unique($ids);
  93. $asset = UserAssetClass::getByUserIds($ids, 'userId');
  94. foreach ($list as $key => $val) {
  95. $userId = $val['id'];
  96. //访问时间
  97. $visitTime = date("m-d H:i", $val['visitTime']);
  98. if (date("m-d") == date("m-d", $val['visitTime'])) {
  99. $visitTime = '今天 ' . date("H:i", $val['visitTime']);
  100. }
  101. $list[$key]['visitTimeFormat'] = $visitTime;
  102. $list[$key]['userAsset'] = isset($asset[$userId]) ? $asset[$userId] : [];
  103. }
  104. return $list;
  105. }
  106. //获取客户基本和资产信息 ssh 2019.11.30
  107. public static function getUserInfo($id)
  108. {
  109. $list = self::getByIds([$id]);
  110. $data = self::groupUserBaseInfo($list);
  111. return current($data);
  112. }
  113. //根据手机号查询客户 ssh 2019.12.1
  114. public static function getByMobile($mobile, $sjId)
  115. {
  116. return self::getByCondition(['sjId' => $sjId, 'mobile' => $mobile]);
  117. }
  118. public static function generateUser($getUserInfo)
  119. {
  120. $date = date("Y-m-d H:i:s");
  121. $time = time();
  122. //替换掉微信名称不支持的图片
  123. $userName = isset($getUserInfo['userName']) ? preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $getUserInfo['userName']) : '';
  124. $getUserInfo['name'] = $userName;
  125. $getUserInfo['sex'] = isset($getUserInfo['sex']) ? $getUserInfo['sex'] : 0;//未知
  126. $getUserInfo['identity'] = 0;
  127. $subscribe = isset($getUserInfo['subscribe']) ? $getUserInfo['subscribe'] : 0;
  128. $getUserInfo['subscribe'] = $subscribe;
  129. $getUserInfo['status'] = 0;
  130. //默认没有完整用户信息
  131. $isFull = isset($getUserInfo['headImgUrl']) && !empty($getUserInfo['headImgUrl']) ? 1 : 0;
  132. $getUserInfo['isFull'] = $isFull;
  133. $getUserInfo['createTime'] = $date;
  134. $getUserInfo['avatar'] = '';
  135. $getUserInfo['password'] = '';
  136. $getUserInfo['payPassword'] = '';
  137. $getUserInfo['mobile'] = isset($getUserInfo['mobile']) ? $getUserInfo['mobile'] : '';
  138. $getUserInfo['addTime'] = $time;
  139. $getUserInfo['visitTime'] = $time;
  140. $getUserInfo['source'] = isset($getUserInfo['source']) ? $getUserInfo['source'] : 0;
  141. $getUserInfo['hasSubscribe'] = 0;
  142. //生成用户基础信息
  143. $user = self::add($getUserInfo, true);
  144. $userId = $user->id;
  145. if (empty($userName)) {
  146. $user->name = '游客';
  147. $user->save();
  148. }
  149. //保存头像
  150. if (isset($getUserInfo['headImgUrl']) && !empty($getUserInfo['headImgUrl'])) {
  151. if (empty($preUser) || (isset($preUser['avatar']) && empty($preUser['avatar']))) {
  152. $imgUrl = $getUserInfo['headImgUrl'];
  153. $currentImg = ImageService::generateAvatar(0, $imgUrl);
  154. if (!empty($currentImg)) {
  155. $user->avatar = $currentImg;
  156. $user->save();
  157. }
  158. }
  159. }
  160. return $user->attributes;
  161. }
  162. public static function updateUser($originalUser, $getUserInfo)
  163. {
  164. $data = [];
  165. $userId = $originalUser['id'];
  166. //替换掉微信不支持的图片
  167. $userName = isset($getUserInfo['userName']) ? preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $getUserInfo['userName']) : '';
  168. if (!empty($userName)) {
  169. $data['name'] = $userName;
  170. }
  171. if (isset($getUserInfo['openId']) && !empty($getUserInfo['openId'])) {
  172. $openId = $getUserInfo['openId'];
  173. $data['openId'] = $openId;
  174. }
  175. if (isset($getUserInfo['miniOpenId']) && !empty($getUserInfo['miniOpenId'])) {
  176. $data['miniOpenId'] = $getUserInfo['miniOpenId'];
  177. }
  178. if (isset($getUserInfo['unionId']) && !empty($getUserInfo['unionId'])) {
  179. $data['unionId'] = $getUserInfo['unionId'];
  180. }
  181. if (isset($getUserInfo['sex'])) {
  182. $data['sex'] = $getUserInfo['sex'];
  183. }
  184. if (isset($getUserInfo['subscribe'])) {
  185. $data['subscribe'] = $getUserInfo['subscribe'];
  186. }
  187. if (isset($getUserInfo['subscribeTime'])) {
  188. $data['subscribeTime'] = $getUserInfo['subscribeTime'];
  189. }
  190. if (isset($getUserInfo['alipayId']) && !empty($getUserInfo['alipayId'])) {
  191. $data['alipayId'] = $getUserInfo['alipayId'];
  192. }
  193. if (isset($getUserInfo['isFull'])) {
  194. $data['isFull'] = $getUserInfo['isFull'];
  195. }
  196. if (isset($getUserInfo['headImgUrl']) && !empty($getUserInfo['headImgUrl'])) {
  197. $data['isFull'] = 1;
  198. }
  199. self::updateById($userId, $data);
  200. $user = self::getById($userId);
  201. return $user;
  202. }
  203. public static function getByMiniOpenId($miniOpenId)
  204. {
  205. return self::getByCondition(['miniOpenId' => $miniOpenId]);
  206. }
  207. public static function getByOpenId($openId)
  208. {
  209. return self::getByCondition(['openId' => $openId]);
  210. }
  211. public static function getByUnionId($unionId)
  212. {
  213. return self::getByCondition(['unionId' => $unionId]);
  214. }
  215. //合并用户
  216. public static function mergeUser($delUser, $retainUser)
  217. {
  218. $connection = Yii::$app->db;//事务处理
  219. $transaction = $connection->beginTransaction();
  220. try {
  221. $delUserId = $delUser['id'];
  222. $retainUserId = $retainUser['id'];
  223. $userName = $retainUser['userName'];
  224. $sjId = $retainUser['sjId'];
  225. //合并记录
  226. $return = UserMergeClass::add([
  227. 'delUserId' => $delUserId,
  228. 'sjId' => $sjId,
  229. 'retainUserId' => $retainUserId,
  230. 'addTime' => time(),
  231. 'createTime' => date("Y-m-d H:i:s")
  232. ]);
  233. $targetId = $return['id'];
  234. $capitalType = dict::getDict('capitalType', 'xhMergeUser', 'id');
  235. $now = time();
  236. $date = date("Y-m-d H:i:s");
  237. //数据迁移
  238. $updateData = [];
  239. $updateKey = [
  240. 'mobile',
  241. 'password',
  242. 'payPassword',
  243. 'subscribe',
  244. 'hasSubscribe',
  245. 'subscribeTime',
  246. 'alipayId',
  247. 'openId',
  248. 'miniOpenId',
  249. 'unionId',
  250. ];
  251. foreach ($updateKey as $key) {
  252. if (isset($delUser[$key]) && !empty($delUser[$key])) {
  253. $updateData[$key] = $delUser[$key];
  254. }
  255. }
  256. if (!empty($updateData)) {
  257. $updateData['visitTime'] = time();
  258. self::updateById($retainUserId, $updateData);
  259. }
  260. //资产累加
  261. $addData = [];
  262. $delUserAsset = UserAssetClass::getByUserId($delUserId);
  263. $retainUserAsset = UserAssetClass::getByUserId($retainUserId);
  264. if (!empty($delUserAsset)) {
  265. //累计消费
  266. $delTotalExpend = isset($delUserAsset['totalExpend']) ? $delUserAsset['totalExpend'] : 0;
  267. if (!empty($delTotalExpend)) {
  268. $addData['totalExpend'] = $retainUserAsset['totalExpend'] + $delTotalExpend;
  269. //变化记录要增加
  270. }
  271. //累计收入
  272. $delTotalIncome = isset($delUserAsset['totalIncome']) ? $delUserAsset['totalIncome'] : 0;
  273. if (!empty($delTotalIncome)) {
  274. $addData['totalIncome'] = $retainUserAsset['totalIncome'] + $delTotalIncome;
  275. //变化记录要增加
  276. }
  277. //累计充值
  278. $delTotalRecharge = isset($delUserAsset['totalRecharge']) ? $delUserAsset['totalRecharge'] : 0;
  279. if (!empty($delTotalRecharge)) {
  280. $addData['totalRecharge'] = $retainUserAsset['totalRecharge'] + $delTotalRecharge;
  281. //变化记录要增加
  282. }
  283. //累计购买数量
  284. $delTotalBuyNum = isset($delUserAsset['totalBuyNum']) ? $delUserAsset['totalBuyNum'] : 0;
  285. if (!empty($delTotalBuyNum)) {
  286. $addData['totalBuyNum'] = $retainUserAsset['totalBuyNum'] + $delTotalBuyNum;
  287. //变化记录要增加
  288. }
  289. //余额
  290. $delBalance = isset($delUserAsset['balance']) ? $delUserAsset['balance'] : 0;
  291. if (!empty($delBalance)) {
  292. $addData['balance'] = $retainUserAsset['balance'] + $delBalance;
  293. //变化记录要增加
  294. $userCapitalData = [
  295. 'relateId' => $targetId,
  296. 'balance' => $addData['balance'],
  297. 'totalIncome' => $retainUserAsset['totalIncome'] + $delBalance,
  298. 'totalExpend' => $retainUserAsset['totalExpend'],
  299. 'amount' => $delBalance,
  300. 'io' => 1,
  301. 'payWay' => 0,
  302. 'event' => '帐号合并',
  303. 'sjId' => $sjId,
  304. 'userId' => $retainUserId,
  305. 'alipayId' => '',
  306. 'userName' => $userName,
  307. 'operateId' => 0,
  308. 'createTime' => $date,
  309. 'addTime' => $now,
  310. 'capitalType' => $capitalType,
  311. ];
  312. xhUserCapitalService::add($userCapitalData);//用户资金流水增加
  313. }
  314. //成长值
  315. $delGrowth = isset($delUserAsset['growth']) ? $delUserAsset['growth'] : 0;
  316. if (!empty($delGrowth)) {
  317. $addData['growth'] = $retainUserAsset['growth'] + $delGrowth;
  318. //注意会员等级要进行重新计算!!!!!还有积分变化记录要增加
  319. $growthData = [
  320. 'userId' => $retainUserId,
  321. 'userName' => $userName,
  322. 'sjId' => $sjId,
  323. 'relateId' => $targetId,
  324. 'integral' => $addData['growth'],
  325. 'num' => $delGrowth,
  326. 'io' => 1,
  327. 'payWay' => 0,
  328. 'alipayId' => '',
  329. 'event' => '帐号合并',
  330. 'operatorId' => 0,
  331. 'createTime' => $date,
  332. 'capitalType' => $capitalType,
  333. 'addTime' => $now,
  334. ];
  335. UserGrowthClass::add($growthData);
  336. //成长值增加升级
  337. $preLevel = $retainUserAsset['member'];
  338. $preGrowth = $retainUserAsset['growth'];
  339. $merchantExtend = xhMerchantExtendService::getBySjId($sjId);
  340. UserIntegralService::increaseToUpgrade($preGrowth, $addData['growth'], $preLevel, $retainUserId, $sjId, $merchantExtend);
  341. }
  342. if (!empty($addData)) {
  343. UserAssetClass::updateByUserId($retainUserId, $addData);
  344. }
  345. }
  346. //删除用户
  347. $clearData = ['openId' => '', 'miniOpenId' => '', 'unionId' => '', 'alipayId' => '', 'sjId' => 0, 'mobile' => ''];
  348. self::updateById($delUserId, $clearData);
  349. UserAssetClass::updateByUserId($delUserId, ['sjId' => 0]);
  350. //如果有支付宝信息则清除支付宝用户
  351. UserAlipayClass::updateByUserId($delUserId, ['alipayId' => '', 'alipayAccount' => '', 'sjId' => 0]);
  352. //合并帐号减少客户数 ssh 2020.5.13
  353. MerchantAssetClass::mergeToReduceUser($sjId);
  354. $transaction->commit();
  355. return self::getById($retainUserId);
  356. } catch (Exception $e) {
  357. $transaction->rollBack();
  358. Yii::info("合并userid $delUserId $retainUserId 时事务回滚,原因:" . $e->getMessage());
  359. return [];
  360. }
  361. }
  362. //找出相同unionId的用户
  363. public static function getSameUnionId($unionId)
  364. {
  365. return self::getAllByCondition(['unionId' => $unionId], 'addTime desc', '*', 'id');
  366. }
  367. public static function valid($info, $sjId)
  368. {
  369. if (empty($info)) {
  370. util::fail('找不到客户');
  371. }
  372. if ($info['sjId'] != $sjId) {
  373. util::fail('这个客户您没有权限操作');
  374. }
  375. }
  376. //根据消费次数和有没领优惠券来判断是不是新人
  377. public static function newUser($userInfo)
  378. {
  379. $asset = isset($userInfo['userAsset']) ? $userInfo['userAsset'] : [];
  380. $totalBuyNum = isset($asset['totalBuyNum']) ? $asset['totalBuyNum'] : 0;
  381. if ($totalBuyNum > 0) {
  382. return false;
  383. }
  384. $getCouponNum = isset($asset['getCouponNum']) ? $asset['getCouponNum'] : 0;
  385. if ($getCouponNum) {
  386. return false;
  387. }
  388. return true;
  389. }
  390. public static function getUserByIds($ids)
  391. {
  392. $info = self::getByIds($ids, null, 'id');
  393. if (empty($info)) {
  394. return [];
  395. }
  396. $data = self::groupUserBaseInfo($info);
  397. return $data;
  398. }
  399. //将微信和小程序获取的用户信息转成可以保存的用户信息
  400. public static function switchUserInfo($info, $source)
  401. {
  402. $openId = '';
  403. if (isset($info['openid']) && !empty($info['openid'])) {
  404. $openId = $info['openid'];
  405. unset($info['openid']);
  406. }
  407. if (isset($info['openId']) && !empty($info['openId'])) {
  408. $openId = $info['openId'];
  409. unset($info['openId']);
  410. }
  411. if (!empty($openId)) {
  412. $userSource = self::$userSourceId;
  413. switch ($source) {
  414. case $userSource['mini']['name']:
  415. $info['miniOpenId'] = $openId;
  416. break;
  417. case $userSource['official']['name']:
  418. $info['openId'] = $openId;
  419. break;
  420. default:
  421. }
  422. }
  423. if (isset($info['miniOpenId'])) {
  424. $info['miniOpenId'] = $info['miniOpenId'];
  425. }
  426. if (isset($info['nickName'])) {
  427. $info['userName'] = $info['nickName'];
  428. $info['nickName'] = $info['nickName'];
  429. }
  430. if (isset($info['unionid'])) {
  431. $info['unionId'] = $info['unionid'];
  432. }
  433. if (isset($info['unionId'])) {
  434. $info['unionId'] = $info['unionId'];
  435. }
  436. if (isset($info['headimgurl'])) {
  437. $info['headImgUrl'] = $info['headimgurl'];
  438. }
  439. if (isset($info['avatarUrl'])) {
  440. $info['headImgUrl'] = $info['avatarUrl'];
  441. }
  442. if (isset($info['subscribe_time'])) {
  443. $info['subscribeTime'] = $info['subscribe_time'];
  444. }
  445. if (isset($info['subscribe'])) {
  446. $info['subscribe'] = $info['subscribe'];
  447. }
  448. return $info;
  449. }
  450. //创建以及更新用户 ssh 2020.2.7
  451. public static function replaceUser($info)
  452. {
  453. $mobile = $info['mobile'] ?? '';
  454. $name = $info['name'] ?? '';
  455. $miniOpenId = $info['miniOpenId'] ?? '';
  456. if (stringUtil::isMobile($mobile) == false) {
  457. util::fail('手机号错误');
  458. }
  459. $user = self::getByCondition(['mobile' => $mobile], true);
  460. if (empty($user)) {
  461. $user = self::add(['mobile' => $mobile, 'name' => $name, 'miniOpenId' => $miniOpenId], true);
  462. }
  463. return $user;
  464. }
  465. //拉取粉丝 ssh 2020.2.7
  466. public static function syncWxUser($sjId, $nextOpenId = '')
  467. {
  468. $merchant = MerchantClass::getMerchantById($sjId);
  469. //一次拉取调用最多拉取10000个关注者的OpenID
  470. $result = wxUtil::getSubscribeUserList($merchant, $nextOpenId);
  471. $total = isset($result['total']) ? $result['total'] : 0;
  472. $next_openid = isset($result['next_openid']) ? $result['next_openid'] : '';
  473. $count = isset($result['count']) ? $result['count'] : 0;
  474. $openIdList = isset($result['data']['openid']) ? $result['data']['openid'] : [];
  475. $currentTotal = count($openIdList);
  476. if ($count == 0 || $currentTotal == 0) {
  477. return ['total' => $total, 'count' => $count, 'nextOpenId' => $next_openid];
  478. }
  479. $currentTotalPage = $currentTotal > 100 ? ceil($currentTotal / 100) : 1;
  480. $userSource = Yii::$app->dict->getValue('userSourceGetId', 'official');
  481. $source = $userSource['name'];
  482. for ($m = 1; $m <= $currentTotalPage; $m++) {
  483. $offset = ($m - 1) * 100;
  484. $subIdList = array_slice($openIdList, $offset, 100);
  485. $info = wxUtil::batchGetUserInfo($merchant, $subIdList);
  486. if (empty($info) || isset($info['user_info_list']) == false || empty($info['user_info_list'])) {
  487. continue;
  488. }
  489. $user_info_list = $info['user_info_list'];
  490. foreach ($user_info_list as $val) {
  491. $val['isFull'] = 1;
  492. $val['unionId'] = $val['unionid'];
  493. $val['headImgUrl'] = $val['headimgurl'];
  494. $val['openId'] = $val['openid'];
  495. //去掉不支持的字符
  496. $val['nickName'] = isset($val['nickname']) ? preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $val['nickname']) : '';
  497. $val['sjId'] = $sjId;
  498. self::replaceUser($val, $source, $sjId);
  499. }
  500. }
  501. return ['total' => $total, 'count' => $count, 'nextOpenId' => $next_openid];
  502. }
  503. }