GoodsService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: lts
  5. * Date: 2019-07-08
  6. * Time: 13:48
  7. */
  8. namespace app\main\service;
  9. use app\main\constants\CacheConstants;
  10. use app\main\constants\GoodsConstants;
  11. use app\main\constants\PayConstants;
  12. use app\main\model\object\UserObject;
  13. use think\Config;
  14. use think\Exception;
  15. use app\common\library\Redis;
  16. class GoodsService extends BaseService
  17. {
  18. const CUSTOM_GOODS_KEY = 'CGN:';//渠道商自定义商品列表key前缀
  19. const TEST_CATEGORY_ID_KEY = 'TCID';//测试类商品id
  20. const ACTIVITY_CATEGORY_ID_KEY = 'ACIK';//活动类商品id
  21. protected static $self = null;
  22. public static function instance()
  23. {
  24. if (self::$self == null) {
  25. self::$self = new self();
  26. }
  27. return self::$self;
  28. }
  29. /**
  30. * @return \app\common\model\GoodsChannelRel
  31. */
  32. public function getGoodsChannelRelModel()
  33. {
  34. return model('GoodsChannelRel');
  35. }
  36. public function getGoodsModel()
  37. {
  38. return model('Goods');
  39. }
  40. /**
  41. * 获取默认商品列表
  42. * @return array|false|\PDOStatement|string|\think\Collection
  43. */
  44. public function getDefaultGoodsList()
  45. {
  46. $channelId = 0;
  47. $redis = Redis::instance();
  48. $rKey = $this->getCustomGoodsKey($channelId);
  49. if ($redis->exists($rKey)) {
  50. $strGoodsList = $redis->get($rKey);
  51. $goodsList = json_decode($strGoodsList, true);
  52. return $goodsList;
  53. } else {
  54. $goodsList = $this->getChannelGoodsListFromDB($channelId);
  55. Redis::instance()->set($rKey, json_encode($goodsList));
  56. return $goodsList;
  57. }
  58. }
  59. /**
  60. * 从数据库获取渠道商自定义商品列表
  61. * @param $channelId
  62. * @return array|false|\PDOStatement|string|\think\Collection
  63. */
  64. private function getChannelGoodsListFromDB($channelId)
  65. {
  66. $customGoodsList = $this->getGoodsChannelRelModel()->join(['goods' => 'g'], 'g.id = goods_channel_rel.goods_id')
  67. ->field([
  68. 'g.id',
  69. 'category_id',
  70. 'title',
  71. 'money',
  72. 'first_description',
  73. 'second_description',
  74. 'kandian',
  75. 'free_kandian',
  76. 'icon',
  77. 'show_type',
  78. 'group_ids',
  79. 'g.type',
  80. 'goods_channel_rel.business_line',
  81. 'goods_channel_rel.default',
  82. ])
  83. ->where(['goods_channel_rel.admin_id' => $channelId])
  84. ->order('goods_channel_rel.position_index')
  85. ->select();
  86. foreach ($customGoodsList as $item) {
  87. $item['show_type_text'] = PayConstants::$goodsShowTypeList[$item['show_type']];
  88. }
  89. return $customGoodsList;
  90. }
  91. /**
  92. * 获取自定义商品列表
  93. * @param $channelId int 渠道商id,超管id为0
  94. * @return array|false|mixed|\PDOStatement|string|\think\Collection
  95. */
  96. public function getCustomGoodsList($channelId, $isVip = false)
  97. {
  98. if (!empty($channelId)) {
  99. $isTest = AdminService::instance()->checkIsTestChannel(null, $channelId);
  100. $redis = Redis::instance();
  101. $goodsList = $this->getChannelGoodsList($channelId, $isVip);
  102. if (!$isTest) {//当前渠道商不是测试渠道商,需要剔除测试商品
  103. if ($redis->exists(self::TEST_CATEGORY_ID_KEY)) {
  104. $testCategoryId = $redis->get(self::TEST_CATEGORY_ID_KEY);
  105. } else {
  106. $testCategoryIds = $this->getGoodsModel()->getGoodsCategoryIds([PayConstants::GOODS_CATEGORY_TEST]);
  107. $testCategoryId = current($testCategoryIds);
  108. $redis->set(self::TEST_CATEGORY_ID_KEY, $testCategoryId);
  109. }
  110. foreach ($goodsList as $key => $item) {
  111. $tempCategoryIds = explode(',', $item['category_id']);
  112. if (in_array($testCategoryId, $tempCategoryIds)) {
  113. unset($goodsList[$key]);
  114. }
  115. }
  116. }
  117. return $goodsList;
  118. } else {
  119. return $this->getDefaultGoodsList();
  120. }
  121. }
  122. /**
  123. * 获取活动商品的分类id
  124. * @return bool|mixed|string
  125. */
  126. public function getActivityGoodsCategoryId()
  127. {
  128. $redis = Redis::instance();
  129. if ($redis->exists(self::ACTIVITY_CATEGORY_ID_KEY)) {
  130. $categoryId = $redis->get(self::ACTIVITY_CATEGORY_ID_KEY);
  131. } else {
  132. $testCategoryIds = $this->getGoodsModel()->getGoodsCategoryIds([PayConstants::GOODS_CATEGORY_ACTIVITY]);
  133. $categoryId = current($testCategoryIds);
  134. $redis->set(self::ACTIVITY_CATEGORY_ID_KEY, $categoryId);
  135. }
  136. return $categoryId;
  137. }
  138. /**
  139. * 获取自定义商品的redis-key
  140. * @param $channelId
  141. * @return string
  142. */
  143. private function getCustomGoodsKey($channelId)
  144. {
  145. return self::CUSTOM_GOODS_KEY . $channelId;
  146. }
  147. /**
  148. * 获取渠道商自定义商品列表
  149. * @param $channelId
  150. * @return array|false|mixed|\PDOStatement|string|\think\Collection
  151. */
  152. public function getChannelGoodsList($channelId,$isVip = false)
  153. {
  154. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($channelId);
  155. $redis = Redis::instance();
  156. $rKey = $this->getCustomGoodsKey($channelId);
  157. if (($adminConfig && $adminConfig['custom_goods'] == 1) || $isVip) {
  158. if ($redis->exists($rKey)) {
  159. $strGoodsList = $redis->get($rKey);
  160. $goodsList = json_decode($strGoodsList, true);
  161. return $goodsList;
  162. } else {
  163. $goodsList = $this->getChannelGoodsListFromDB($channelId);
  164. if (empty($goodsList)) {
  165. $goodsList = $this->getDefaultGoodsList();
  166. }
  167. Redis::instance()->set($rKey, json_encode($goodsList));
  168. return $goodsList;
  169. }
  170. } else {
  171. $goodsList = $this->getDefaultGoodsList();
  172. return $goodsList;
  173. }
  174. }
  175. /**
  176. * 保存自定义商品信息
  177. * @param $goodsIds
  178. * @param $channelId
  179. * @throws Exception
  180. */
  181. public function saveChannelGoodsList($goodsIds, $channelId, $businessLine = '0', $default = false, $groupIds='')
  182. {
  183. if (!is_array($goodsIds)) {
  184. throw new Exception('goodsIds必须为数组');
  185. }
  186. if (empty($goodsIds)) {
  187. throw new Exception('至少选择一个商品');
  188. }
  189. if (!$default) {
  190. $default = $goodsIds[0];
  191. }
  192. $goodsList = $this->getGoodsModel()->whereIn('id', $goodsIds)->select();
  193. $showTypeList = [];
  194. foreach ($goodsList as $item) {
  195. $showTypeList[$item['show_type']][] = $item['id'];
  196. }
  197. if (empty($showTypeList[PayConstants::GOODS_SHOW_TYPE_ALL])) {
  198. if (empty($showTypeList[PayConstants::GOODS_SHOW_TYPE_RECHARGED])) {
  199. throw new Exception('必须配置一个已充值用户的商品');
  200. } elseif (empty($showTypeList[PayConstants::GOODS_SHOW_TYPE_UN_RECHARGED])) {
  201. throw new Exception('必须配置一个未充值用户的商品');
  202. }
  203. }
  204. $relList = [];
  205. try {
  206. $goodsOrderList = [];
  207. foreach ($goodsIds as $key => $goodId) {
  208. $relList[] = [
  209. 'admin_id' => $channelId,
  210. 'goods_id' => $goodId,
  211. 'group_ids' => $groupIds,
  212. 'position_index' => $key + 1,
  213. 'createtime' => time(),
  214. 'business_line' => $businessLine,
  215. 'default' => (int)($goodId == $default)
  216. ];
  217. foreach ($goodsList as $item) {
  218. if ($item['id'] == $goodId) {
  219. $goodsOrderList[] = $item;
  220. break;
  221. }
  222. }
  223. }
  224. $goodsChannelRel = $this->getGoodsChannelRelModel();
  225. $goodsChannelRel->where('admin_id', $channelId)->where('business_line', $businessLine)->delete();
  226. $goodsChannelRel->insertAll($relList);
  227. $goodsChannelRelHistory = model('GoodsChannelRelHistory');
  228. $goodsChannelRelHistory->insert([
  229. 'admin_id' => $channelId,
  230. 'goods_ids' => implode(',', $goodsIds),
  231. 'createtime' => time(),
  232. ]);
  233. $rKey = $this->getCustomGoodsKey($channelId);
  234. $rKeyApp = CacheConstants::getGoodsListAppKey($businessLine);
  235. Redis::instance()->del($rKey);
  236. Redis::instance()->del($rKeyApp);
  237. } catch (Exception $e) {
  238. LogService::error($e->getMessage());
  239. throw $e;
  240. }
  241. }
  242. /**
  243. * 删除渠道商自定义商品列表
  244. * @param $channelId
  245. * @throws Exception
  246. */
  247. public function delChannelGoodsList($channelId)
  248. {
  249. $rKey = $this->getCustomGoodsKey($channelId);
  250. try {
  251. $goodsChannelRel = $this->getGoodsChannelRelModel();
  252. $goodsChannelRel->where('admin_id', $channelId)->delete();
  253. $goodsChannelRelHistory = model('GoodsChannelRelHistory');
  254. $goodsChannelRelHistory->insert([
  255. 'admin_id' => $channelId,
  256. 'goods_ids' => '',
  257. 'createtime' => time(),
  258. ]);
  259. Redis::instance()->del($rKey);
  260. } catch (Exception $e) {
  261. LogService::error($e->getMessage());
  262. throw $e;
  263. }
  264. }
  265. /**
  266. * 选择商品页面,获取商品列表
  267. * @param $channelId
  268. * @param $selectedIds
  269. * @param $where
  270. * @param $offset
  271. * @param $limit
  272. * @param $goodsCategory
  273. * @return array
  274. */
  275. public function getSelectGoodsList($channelId, $selectedIds, $where, $offset, $limit, $goodsCategory, $goodsTypes, $maps = [])
  276. {
  277. // if (empty($goodsCategory)) {
  278. // $goodsCategory = [PayConstants::GOODS_CATEGORY_RECHARGE];
  279. // }
  280. $listFetchObj = $this->getSelectGoodsObj($channelId, $selectedIds, $where, $offset, $limit, $goodsCategory,
  281. $goodsTypes, $maps);
  282. $list = $listFetchObj->select();
  283. $countFetchObj = $this->getSelectGoodsObj($channelId, $selectedIds, $where, $offset, $limit, $goodsCategory,
  284. $goodsTypes, $maps);
  285. $total = $countFetchObj->count();
  286. return [$list, $total];
  287. }
  288. /**
  289. * 构造查询自定义商品的model对象
  290. * @param $channelId 渠道商id
  291. * @param $selectedIds 已选商品id
  292. * @param $where
  293. * @param $offset
  294. * @param $limit
  295. * @param $goodsCategory
  296. * @return \app\common\model\Goods
  297. */
  298. private function getSelectGoodsObj($channelId, $selectedIds, $where, $offset, $limit, $goodsCategory, $goodsTypes, $maps = [])
  299. {
  300. $goodsModel = $this->getGoodsModel();
  301. $isTest = AdminService::instance()->checkIsTestChannel(0, $channelId);
  302. $goodsCategory = (array)$goodsCategory;
  303. $obj = $goodsModel->where($where)
  304. ->where($maps)
  305. ->whereIn('type', $goodsTypes)
  306. ->limit($offset, $limit);
  307. if ($isTest) {
  308. $goodsCategory[] = PayConstants::GOODS_CATEGORY_TEST;
  309. }
  310. if ($categoryIds = $goodsModel->getGoodsCategoryIds($goodsCategory)) {
  311. $categoryMap = [];
  312. foreach ($categoryIds as $categoryId) {
  313. array_push($categoryMap, "find_in_set({$categoryId},category_id)");
  314. }
  315. }
  316. //分类不为空时
  317. if (!empty($categoryMap)) {
  318. if (count($categoryMap) > 1) {
  319. $obj->where("(" . implode(' or ', $categoryMap) . ")");
  320. } else {
  321. $obj->where(current($categoryMap));
  322. }
  323. }
  324. if (!empty($selectedIds)) {
  325. $obj->whereNotIn('id', $selectedIds);
  326. }
  327. return $obj;
  328. }
  329. /**
  330. * 删除配置此商品的渠道商自定义商品
  331. * @param $goodsId
  332. */
  333. public function delCustomGoodsId($goodsId)
  334. {
  335. $ids = $this->removeCacheCustomGoods($goodsId);
  336. if (!empty($ids)) {
  337. $this->getGoodsChannelRelModel()->whereIn('id', $ids)->delete();
  338. }
  339. }
  340. /**
  341. * 删除配置此商品的自定义商品缓存
  342. * @param $goodsId
  343. * @return array
  344. */
  345. public function removeCacheCustomGoods($goodsId)
  346. {
  347. $key = CacheConstants::getGoodsInfoKey($goodsId);
  348. Redis::instance()->del($key);
  349. $goodsChannelRelList = $this->getGoodsChannelRelModel()->where('goods_id', $goodsId)->field([
  350. 'id',
  351. 'admin_id'
  352. ])->select();
  353. $ids = [];
  354. $keys = [];
  355. foreach ($goodsChannelRelList as $item) {
  356. $ids[] = $item['id'];
  357. $keys[] = $this->getCustomGoodsKey($item['admin_id']);
  358. }
  359. $delCustomGoodsRedisIndex = Redis::splitKeysByRule($keys);
  360. foreach ($delCustomGoodsRedisIndex as $k => $v) {
  361. $redis = Redis::getRedisConnect($k);
  362. $redis->del(...$v);
  363. }
  364. return $ids;
  365. }
  366. /**
  367. * 获取前台用户使用的商品列表
  368. * @param $channelId 渠道商id
  369. * @param $isPay 用户是否支付过订单。0未充值 1已充值
  370. * @return array|false|mixed|\PDOStatement|string|\think\Collection
  371. */
  372. public function getCustomGoodsForFront($channelId, $isPay, $isNew, $businessLine = PayConstants::BUSINESS_WECHAT)
  373. {
  374. $goodsList = $this->getCustomGoodsList($channelId);
  375. $goodsResultList = [];
  376. foreach ($goodsList as $item) {
  377. if ($item['business_line'] != $businessLine) {
  378. continue;
  379. }
  380. if (intval($isPay) == 0) {//未充值用户
  381. if (in_array($item['show_type'],
  382. [PayConstants::GOODS_SHOW_TYPE_UN_RECHARGED, PayConstants::GOODS_SHOW_TYPE_ALL])) {
  383. $goodsResultList[] = $item;
  384. }
  385. } else {//已充值用户
  386. if (in_array($item['show_type'],
  387. [PayConstants::GOODS_SHOW_TYPE_RECHARGED, PayConstants::GOODS_SHOW_TYPE_ALL])) {
  388. $goodsResultList[] = $item;
  389. }
  390. }
  391. if ($isNew && $item['show_type'] == PayConstants::GOODS_SHOW_TYPE_NEW) {
  392. $goodsResultList[] = $item;
  393. } else if(!$isNew && $item['show_type'] == PayConstants::GOODS_SHOW_TYPE_OLD){
  394. $goodsResultList[] = $item;
  395. }
  396. }
  397. return $goodsResultList;
  398. }
  399. public function checkGoodsTypeValid($showType, UserObject $user)
  400. {
  401. if (Config::get('site.goods_type_new_user') == GoodsConstants::GOODS_TYPE_NEW_DAY) {
  402. $isNew = date('Ymd', $user->createtime) == date('Ymd');
  403. } else {
  404. $isNew = time() - $user->createtime < 86400;
  405. }
  406. $return = true;
  407. switch ($showType) {
  408. case PayConstants::GOODS_SHOW_TYPE_RECHARGED:
  409. $return = $user->is_pay;
  410. break;
  411. case PayConstants::GOODS_SHOW_TYPE_UN_RECHARGED:
  412. $return = !$user->is_pay;
  413. break;
  414. case PayConstants::GOODS_SHOW_TYPE_NEW:
  415. $return = $isNew;
  416. break;
  417. case PayConstants::GOODS_SHOW_TYPE_OLD:
  418. $return = !$isNew;
  419. break;
  420. }
  421. return $this->setData($return)->getReturn();
  422. }
  423. }