GroupRelationFrontServiceImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. package com.cyksj.service.relation.impl;
  2. import cn.hutool.core.date.BetweenFormater;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.lang.Assert;
  6. import cn.hutool.core.lang.Validator;
  7. import cn.hutool.core.util.StrUtil;
  8. import cn.hutool.http.HttpStatus;
  9. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  10. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  11. import com.cyksj.common.constant.Constant;
  12. import com.cyksj.common.exception.BusinessRuntimeException;
  13. import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
  14. import com.cyksj.common.util.J11HttpC;
  15. import com.cyksj.common.util.Jsons;
  16. import com.cyksj.enums.GatewayApiCode;
  17. import com.cyksj.mapper.*;
  18. import com.cyksj.model.entity.*;
  19. import com.cyksj.model.request.SpecialGoodsTicketReq;
  20. import com.cyksj.model.views.*;
  21. import com.cyksj.redis.RedisService;
  22. import com.cyksj.service.chatgpt.ChatGptAuthService;
  23. import com.cyksj.service.groups.GroupsFuncService;
  24. import com.cyksj.service.mail.MailService;
  25. import com.cyksj.service.mange.coupon.CouponCommonService;
  26. import com.cyksj.service.relation.GroupRelationFrontService;
  27. import com.cyksj.service.shop.YhShopFrontService;
  28. import com.cyksj.service.user.UserBindRelationService;
  29. import com.ejlchina.searcher.BeanSearcher;
  30. import com.ejlchina.searcher.param.Operator;
  31. import com.ejlchina.searcher.util.MapBuilder;
  32. import com.ejlchina.searcher.util.MapUtils;
  33. import lombok.RequiredArgsConstructor;
  34. import lombok.extern.slf4j.Slf4j;
  35. import org.springframework.stereotype.Service;
  36. import org.springframework.transaction.annotation.Transactional;
  37. import javax.servlet.http.HttpServletRequest;
  38. import java.net.http.HttpResponse;
  39. import java.util.ArrayList;
  40. import java.util.Date;
  41. import java.util.List;
  42. import java.util.Optional;
  43. import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER;
  44. import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND;
  45. /*
  46. *项目名: netflix
  47. *文件名: GroupRelationFrontServiceImpl
  48. *创建者: JavaZou
  49. *创建时间:2022/12/29 15:42
  50. */
  51. @Service
  52. @RequiredArgsConstructor
  53. @Slf4j
  54. public class GroupRelationFrontServiceImpl implements GroupRelationFrontService {
  55. private final UserBindRelationService userBindRelationService;
  56. private final UserMapper userMapper;
  57. private final BeanSearcher beanSearcher;
  58. private final CouponCommonService couponCommonService;
  59. private final GroupsRelationMapper groupsRelationMapper;
  60. private final GroupsMapper groupsMapper;
  61. private final ChatGptAuthService chatGptAuthService;
  62. private final RedisService redisService;
  63. private final MailService mailService;
  64. private final OrderDonMapper orderDonMapper;
  65. private final YhShopFrontService yhShopFrontService;
  66. private final HttpServletRequest request;
  67. private final GroupsFuncService groupsFuncService;
  68. private final OrderDiscountPlusPurchaseSkuRelationMapper orderDiscountPlusPurchaseSkuRelationMapper;
  69. private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
  70. private final static String VERIFY_CODE_SECRET = "q1w2e3";
  71. @Override
  72. public List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId) {
  73. User u = userMapper.selectById(userId);
  74. if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
  75. if (u.getIsBlack()) {
  76. return new ArrayList<>();
  77. }
  78. List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, u);
  79. MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
  80. Long yhsId = yhShopFrontService.getYhsIdByCustomId(customId);
  81. List<RenewalView> list = beanSearcher.searchAll(RenewalView.class, builder
  82. .field(RenewalView::getUserId, 0).op(Operator.GreaterThan)
  83. .field(RenewalView::getUserId, userIds).op(Operator.InList)
  84. .field(RenewalView::getYhsId, yhsId)
  85. .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
  86. .orderBy(RenewalView::getExpiryTime).asc()
  87. .build());
  88. //过滤邀请制、已失效的车位
  89. DateTime now = DateTime.now();
  90. list.stream().forEach(ticket -> {
  91. if (ticket.getGoodsId() == 18 && ticket.getSkuNum() > 1) {
  92. ticket.setPassword(null);
  93. }
  94. ticket.setIsMulti(false);
  95. if (ticket.getSkuNum() > 1) {
  96. ticket.setIsMulti(true);
  97. }
  98. //chatGPT直连
  99. if (ticket.getGoodsId().equals(42l)) {
  100. if (StrUtil.isNotBlank(ticket.getAccount())) {
  101. String accessToken;
  102. try {
  103. accessToken = chatGptAuthService.getAccessToken(ticket.getAccount());
  104. ticket.setGptRefreshToken(accessToken);
  105. } catch (Exception e) {
  106. redisService.set(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + ticket.getAccount(), ticket.getAccount());
  107. }
  108. }
  109. ticket.setAccount(null);
  110. ticket.setPassword(null);
  111. } else {
  112. ticket.setGptRefreshToken(null);
  113. }
  114. if (ticket.getSecondType() == 1) {
  115. ticket.setAccount(null);
  116. ticket.setPassword(null);
  117. }
  118. if (isLoginPopularize != null && isLoginPopularize) {
  119. GoodsDonViews views = beanSearcher.searchFirst(GoodsDonViews.class, MapUtils.builder().field(GoodsDonViews::getId, ticket.getGoodsId()).build());
  120. views.setSpecs(beanSearcher.searchFirst(GoodsDonSpecFrontView.class, MapUtils.builder().field(GoodsDonSpecFrontView::getGoodsId, views.getId()).build()));
  121. views.setSkuList(beanSearcher.searchAll(GoodsDonSkuFrontView.class, MapUtils.builder().field(GoodsDonSkuFrontView::getGoodsId, views.getId()).field(GoodsDonSkuFrontView::getStatus, true).build()));
  122. ticket.setGoodsDonViews(views);
  123. }
  124. if (ticket.getMonths() != null && ticket.getMonths() >= 300) {
  125. ticket.setExpiryTime(null);
  126. }
  127. if (ticket.getExpiryTime() != null && ticket.getGoodsType() == 1 && ticket.getSecondType() == 2) {
  128. String remainDays = DateUtil.formatBetween(now, ticket.getExpiryTime(), BetweenFormater.Level.DAY);
  129. if ("0天".equals(remainDays)) {
  130. remainDays = "小于1天";
  131. } else {
  132. //当天也算
  133. int days = Integer.parseInt(remainDays.substring(0, remainDays.indexOf("天")));
  134. remainDays = days + 1 + "天";
  135. }
  136. ticket.setRemainDays(remainDays);
  137. }
  138. if (list.size() > 1 && ticket.getGoodsId() != 18) {
  139. OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
  140. .eq(OrderDon::getRelationId, ticket.getRelationId())
  141. .eq(OrderDon::getUserId, ticket.getUserId())
  142. .orderByDesc(OrderDon::getId)
  143. .last("limit 1"));
  144. Date payTime = null;
  145. if (orderDon != null) {
  146. payTime = Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime());
  147. }
  148. //加购订单
  149. if (orderDon == null) {
  150. List<OrderDiscountPlusPurchaseSkuRelation> plusPurchaseSkuRelations = orderDiscountPlusPurchaseSkuRelationMapper.selectPlusRelationByIdAndUserId(ticket.getRelationId(), ticket.getUserId());
  151. for (OrderDiscountPlusPurchaseSkuRelation data : plusPurchaseSkuRelations) {
  152. String relationIds = data.getRelationIds();
  153. if (StrUtil.isEmpty(relationIds)) {
  154. return;
  155. }
  156. try {
  157. List<Long> relationList = Jsons.parseList(relationIds, Long.class);
  158. if (relationList.contains(ticket.getRelationId())) {
  159. OrderDon plusOrder = orderDonMapper.selectById(data.getOrderId());
  160. if (plusOrder != null) {
  161. payTime = Optional.ofNullable(plusOrder.getPayTime()).orElse(plusOrder.getCreatedTime());
  162. }
  163. break;
  164. }
  165. } catch (Exception e) {
  166. }
  167. }
  168. }
  169. ticket.setPayTime(payTime);
  170. }
  171. List<GroupsRelationUserView> relationUserViews = groupsRelationMapper.getUserRelationUserViews(ticket.getGroupId(), ticket.getRelationId(), ticket.getUserId(), List.of(GroupsRelation.Status.validity, GroupsRelation.Status.outside));
  172. ticket.setRelationViews(relationUserViews);
  173. if (ticket.getExpiryTime() != null) {
  174. ticket.setExpiryTimeStr(DateUtil.format(ticket.getExpiryTime(), "yyyy-MM-dd"));
  175. }
  176. });
  177. return list;
  178. }
  179. @Override
  180. public Boolean isJoinCorpWx(Long userId, Boolean isJoin, Boolean noCoupon) {
  181. if (!isJoin) {
  182. User user = userMapper.selectById(userId);
  183. if (user == null || StrUtil.isEmpty(user.getUnionid())) {
  184. return true;
  185. }
  186. // CorpUser corpUser = corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
  187. // .ne(CorpUser::getUnionid, "")
  188. // .eq(CorpUser::getUnionid, user.getUnionid())
  189. // .last("limit 1")
  190. // .select(CorpUser::getId)
  191. // );
  192. CorpUserFollowView corpUserFollowView = beanSearcher.searchFirst(CorpUserFollowView.class, MapUtils.builder()
  193. .field(CorpUserFollowView::getUnionId, user.getUnionid())
  194. .field(CorpUserFollowView::getStatus, 1).build());
  195. if (corpUserFollowView == null) {
  196. return false;
  197. }
  198. }
  199. //用户是否买了奈飞车票
  200. Number number = beanSearcher.searchCount(RenewalView.class, MapUtils.builder()
  201. .field(RenewalView::getUserId, userId)
  202. .field(RenewalView::getGoodsId, 1)
  203. .field(RenewalView::getStatus, List.of("validity", "overdue")).op(Operator.InList)
  204. .build());
  205. if (number.intValue() > 0 && !noCoupon) {
  206. couponCommonService.sendCouponToUser(userId, 34l, 0l, 0l, 0l, CouponUser.Channel.wxCorp);
  207. }
  208. return true;
  209. }
  210. @Override
  211. public GroupsRelation getSimilarExpiredGroupRelation(Long skuId, Integer days, Integer months, List<Long> errorsRelationIds) {
  212. DateTime expiryTime = null;
  213. if (days != null && days > 0) {
  214. expiryTime = DateUtil.offsetDay(DateTime.now(), days);
  215. } else {
  216. expiryTime = DateUtil.offsetMonth(DateTime.now(), months);
  217. }
  218. DateTime minExpiryTime = DateUtil.offsetDay(expiryTime, -5);
  219. Long groupsId = groupsRelationMapper.selectSimilarExpiredRelation(skuId, minExpiryTime);
  220. if (groupsId == null) {
  221. log.info("暂无相似过期时间车队");
  222. return null;
  223. }
  224. GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
  225. .notIn(errorsRelationIds != null && errorsRelationIds.size() > 0, GroupsRelation::getId, errorsRelationIds)
  226. .eq(GroupsRelation::getGroupsId, groupsId)
  227. .eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
  228. .eq(GroupsRelation::getUserId, 0)
  229. .orderByAsc(GroupsRelation::getNum)
  230. .last("limit 1"));
  231. if (relation != null) {
  232. log.info("用户userId:{},获取相似车队的车位relationId:{}", relation.getId());
  233. }
  234. return relation;
  235. }
  236. @Override
  237. public Page<UserRecommendGoodsFrontView> getRecommendGoodsViews(Boolean isPayNf, List<Long> filter_goods_id, Integer start, Integer limit) {
  238. return groupsRelationMapper.getRecommendGoodsViews(new Page<>(start, limit),filter_goods_id, isPayNf);
  239. }
  240. @Override
  241. @Transactional(rollbackFor = Throwable.class)
  242. public void sendCourseWare(SpecialGoodsTicketReq request) throws Exception {
  243. Long userId = request.getUserId();
  244. Long relationId = request.getRelationId();
  245. String email = request.getEmail();
  246. List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
  247. RenewalView relation = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getRelationId, relationId).build());
  248. Assert.notNull(relation, "您的车票不存在");
  249. Long relationUserId = relation.getUserId();
  250. if (!userIdList.contains(relationUserId)) {
  251. throw BusinessRuntimeException.getInstance("您的车票不存在");
  252. }
  253. if (relation.getSpecialType() != GoodsDon.SpecialType.courseware) {
  254. throw BusinessRuntimeException.getInstance("");
  255. }
  256. //是否已发送
  257. if (StrUtil.isNotBlank(relation.getGrAccount())) {
  258. throw BusinessRuntimeException.getInstance("已领取课件,请前往邮箱查看");
  259. }
  260. if (!Validator.isEmail(email)) {
  261. throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
  262. }
  263. int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
  264. .set(GroupsRelation::getAccount, email)
  265. .and(qr -> qr.isNull(GroupsRelation::getAccount).or().eq(GroupsRelation::getAccount, StrUtil.EMPTY))
  266. .eq(GroupsRelation::getId, relationId));
  267. if (update > 0) {
  268. orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
  269. .set(OrderDon::getStatus, OrderDon.Status.complete)
  270. .eq(OrderDon::getRelationId, relationId)
  271. .eq(OrderDon::getUserId, userId)
  272. .eq(OrderDon::getStatus, OrderDon.Status.hasPayment));
  273. mailService.sendCoursewareByGoodsId(relation.getGoodsId(), relation.getRelationId(), relation.getUserId(), relation.getTitle(), email);
  274. }
  275. }
  276. @Override
  277. public GroupsRelation getRelation(Long payRelationId, Long userId, GoodsDonSku sku) {
  278. GroupsRelation relation = null;
  279. if (payRelationId != null && payRelationId > 0) {
  280. relation = groupsRelationMapper.selectById(payRelationId);
  281. if (relation == null) {
  282. throw new BusinessRuntimeException(GROUP_INDEX_NOT_FIND.getCode(), GROUP_INDEX_NOT_FIND.getMsg());
  283. }
  284. if (relation.getUserId() != null && relation.getUserId() > 0L) {
  285. throw new BusinessRuntimeException(GROUP_INDEX_ALREADY_BE_USER.getCode(), GROUP_INDEX_ALREADY_BE_USER.getMsg());
  286. }
  287. } else {
  288. GroupsTrips groups = null;
  289. //ChatGpt Plus、Midjourney非独立规格 上车先获取硬塞座位 硬塞5个座位
  290. //主账号过期时间25天以外
  291. if (sku.getNum() > 1 && Constant.AI_goodsIds.contains(sku.getGoodsId())) {
  292. DateTime time = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 25);
  293. //不塞存在该用户的车队
  294. Long groupsId = groupsRelationMapper.getOutSideGroupsTripsRelationByGoodsId(sku.getId(), time, 5, userId, sku.getNum());
  295. if (groupsId != null) {
  296. relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
  297. .eq(GroupsRelation::getGroupsId, groupsId)
  298. .eq(GroupsRelation::getUserId, 0)
  299. .eq(GroupsRelation::getStatus, GroupsRelation.Status.outside)
  300. .last("limit 1"));
  301. if (relation == null) {
  302. relation = new GroupsRelation();
  303. relation.setStatus(GroupsRelation.Status.outside);
  304. relation.setUserId(userId);
  305. relation.setGroupsId(groupsId);
  306. GroupsRelation maxNumRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1"));
  307. Integer nextNum = maxNumRelation.getNum() + 1;
  308. if (redisService.setNx(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getNameFormat(groupsId, nextNum), nextNum, RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getTimeout())) {
  309. relation.setNum(nextNum);
  310. groupsRelationMapper.insert(relation);
  311. } else {
  312. throw BusinessRuntimeException.getInstance("系统繁忙,请重试...");
  313. }
  314. }
  315. groups = groupsMapper.selectById(groupsId);
  316. }
  317. }
  318. if (groups == null) {
  319. //寻找差不多过期时间规格的车位
  320. relation = getSimilarExpiredGroupRelation(sku.getId(), sku.getDays(), sku.getMonths(), null);
  321. if (relation == null) {
  322. //TODO 如果没指定座位,等待逻辑确认
  323. groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
  324. .eq(GroupsTrips::getSkuId, sku.getId())
  325. .gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
  326. .eq(GroupsTrips::getStatus, GroupsTrips.Status.validity)
  327. .orderByAsc(GroupsTrips::getAvailableNum));
  328. if (groups == null) {
  329. //待发车
  330. groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
  331. .eq(GroupsTrips::getSkuId, sku.getId())
  332. .gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
  333. .eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting)
  334. .orderByAsc(GroupsTrips::getAvailableNum));
  335. }
  336. //新增空车队
  337. if (groups == null) {
  338. relation = groupsFuncService.createNewGroupsTrips(sku);
  339. }
  340. //获取车位
  341. if (relation == null) {
  342. //寻找快满编车队进行占座
  343. relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
  344. if (relation == null) {
  345. Long groupsId = groups.getId();
  346. TASK_EXECUTOR.execute(() -> groupsMapper.updateAvailableNum(groupsId));
  347. throw BusinessRuntimeException.getInstance("系统繁忙,请重试...");
  348. }
  349. }
  350. }
  351. }
  352. }
  353. return relation;
  354. }
  355. @Override
  356. public String getAiVerifyCode(Long userId, Long relationId) throws Exception {
  357. List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
  358. RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getUserId, relationUserIdList).op(Operator.InList)
  359. .field(RenewalView::getRelationId, relationId).build());
  360. if (renewalView == null) {
  361. throw BusinessRuntimeException.getInstance("您的车票不存在...");
  362. }
  363. String account = renewalView.getAccount();
  364. String password = renewalView.getPassword();
  365. if (StrUtil.hasEmpty(account, password)) {
  366. throw BusinessRuntimeException.getInstance("您的车票账号密码异常,请联系客服...");
  367. }
  368. String url = String.format("http://yinhelx.com/api/imap_yhcz.php?sc=&id=&yhm=%s&mm=%s&duan_kou=143&ip=127.0.0.1&mi_yao=%s", account, password, VERIFY_CODE_SECRET);
  369. HttpResponse<String> send = J11HttpC.custom()
  370. .ofGet()
  371. .url(url)
  372. .send(HttpResponse.BodyHandlers.ofString());
  373. if (send.statusCode() != HttpStatus.HTTP_OK) {
  374. throw BusinessRuntimeException.getInstance("获取验证码失败...");
  375. }
  376. String code = StrUtil.subBetween(send.body(), "Doğrulama kodunuz:", "Bu istek sizin");
  377. if (StrUtil.isEmpty(code)) {
  378. throw BusinessRuntimeException.getInstance("获取验证码失败...");
  379. }
  380. return code.trim();
  381. }
  382. }