UserClass.php 20 KB

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