package com.cyksj.service.relation.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.BetweenFormater; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Validator; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.common.util.Jsons; import com.cyksj.common.util.StringUtil; import com.cyksj.common.util.TicketCodeCommonUtil; import com.cyksj.enums.GatewayApiCode; import com.cyksj.mapper.*; import com.cyksj.mapper.manage.distribute.DistributeGeneralSkuRateMapper; import com.cyksj.mapper.manage.distribute.UserDistributeMapper; import com.cyksj.mapper.manage.distribute.UserPlatDistributeRateMapper; import com.cyksj.mapper.manage.distribute.UserPlatSkuDistributeRateMapper; import com.cyksj.mapper.sys.SysEmailMapper; import com.cyksj.model.entity.*; import com.cyksj.model.request.SpecialGoodsTicketReq; import com.cyksj.model.views.*; import com.cyksj.redis.RedisService; import com.cyksj.service.chatgpt.ChatGptAccountService; import com.cyksj.service.chatgpt.ChatGptAuthService; import com.cyksj.service.groups.GroupsFuncService; import com.cyksj.service.mail.CuiQiuMailService; import com.cyksj.service.mail.MailService; import com.cyksj.service.mange.coupon.CouponCommonService; import com.cyksj.service.midjourney.MidjourneyAccountService; import com.cyksj.service.relation.GroupRelationFrontService; import com.cyksj.service.relation.GroupsRelationNetflixService; import com.cyksj.service.user.UserBindRelationService; import com.cyksj.service.user.UserLoginRecordService; import com.ejlchina.searcher.BeanSearcher; import com.ejlchina.searcher.SearchResult; import com.ejlchina.searcher.param.Operator; import com.ejlchina.searcher.util.MapBuilder; import com.ejlchina.searcher.util.MapUtils; import com.github.rholder.retry.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER; import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND; /* *项目名: netflix *文件名: GroupRelationFrontServiceImpl *创建者: JavaZou *创建时间:2022/12/29 15:42 */ @Service @RequiredArgsConstructor @Slf4j public class GroupRelationFrontServiceImpl implements GroupRelationFrontService { private final UserBindRelationService userBindRelationService; private final UserMapper userMapper; private final BeanSearcher beanSearcher; private final CouponCommonService couponCommonService; private final GroupsRelationMapper groupsRelationMapper; private final GroupsMapper groupsMapper; private final ChatGptAuthService chatGptAuthService; private final RedisService redisService; private final MailService mailService; private final OrderDonMapper orderDonMapper; private final GroupsRelationExpiryNotifyRecordMapper groupsRelationExpiryNotifyRecordMapper; private final HttpServletRequest request; private final GroupsFuncService groupsFuncService; private final OrderDiscountPlusPurchaseSkuRelationMapper orderDiscountPlusPurchaseSkuRelationMapper; private final GroupsRelationLoginCodeRecordMapper groupsRelationLoginCodeRecordMapper; private final SysEmailMapper sysEmailMapper; private final GoodsDonSkuMapper goodsDonSkuMapper; private final UserFuncPropertyMapper userFuncPropertyMapper; private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance(); private final UserLoginRecordService userLoginRecordService; private final CuiQiuMailService cuiQiuMailService; private final UserCertRecordMapper userCertRecordMapper; private final MidjourneyAccountService midjourneyAccountService; private final ChatGptAccountService chatGptAccountService; //脆球邮箱后缀 private final static String CUI_QIU_EMAIL_SUFFIX = "@kindvd.com"; private final UpgradePackageMapper upgradePackageMapper; private final GoodsDonQaRelateMapper goodsDonQaRelateMapper; private final GroupsRelationNetflixService groupsRelationNetflixService; private final UserDistributeMapper userDistributeMapper; private final UserPlatDistributeRateMapper userPlatDistributeRateMapper; private final GoodsDonMapper goodsDonMapper; private final UserPlatSkuDistributeRateMapper userPlatSkuDistributeRateMapper; private final DistributeGeneralSkuRateMapper distributeGeneralSkuRateMapper; @Override public SearchResult getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account) { User u = userMapper.selectById(userId); if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID); if (u.getIsBlack()) { return new SearchResult<>(); } List userIds = userBindRelationService.getRelationUserIdList(userId, u); MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap()); //Long yhsId = yhShopFrontService.getYhsIdByCustomId(customId); DateTime now = DateTime.now(); if (StrUtil.isNotBlank(account)) { builder.field(RenewalView::getAccount, account).op(Operator.Contain); } SearchResult list = beanSearcher.search(RenewalView.class, builder .field(RenewalView::getUserId, 0).op(Operator.GreaterThan) .field(RenewalView::getUserId, userIds).op(Operator.InList) //.field(RenewalView::getYhsId, yhsId) .put("condition", String.format("(gr.expiry_time is null or gr.expiry_time > '%s')", now)) .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList) .orderBy(RenewalView::getExpiryTime).asc() .build()); //过滤邀请制、已失效的车位 Integer size = list.getTotalCount().intValue(); list.getDataList().forEach(ticket -> { if (ticket.getSkuId() == null || ticket.getGoodsId() == null) { return; } if (ticket.getGoodsId() == 18 && ticket.getSkuNum() > 1) { ticket.setPassword(null); } ticket.setIsMulti(false); if (ticket.getSkuNum() > 1) { ticket.setIsMulti(true); } //chatGPT直连 if (ticket.getGoodsId().equals(42l)) { if (StrUtil.isNotBlank(ticket.getAccount())) { String accessToken; try { accessToken = chatGptAuthService.getAccessToken(ticket.getAccount()); ticket.setGptRefreshToken(accessToken); } catch (Exception e) { redisService.set(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + ticket.getAccount(), ticket.getAccount()); } } ticket.setAccount(null); ticket.setPassword(null); } else { ticket.setGptRefreshToken(null); } if (ticket.getSecondType() == 1) { ticket.setAccount(null); ticket.setPassword(null); } if (isLoginPopularize != null && isLoginPopularize) { GoodsDonViews views = beanSearcher.searchFirst(GoodsDonViews.class, MapUtils.builder().field(GoodsDonViews::getId, ticket.getGoodsId()).build()); views.setSpecs(beanSearcher.searchFirst(GoodsDonSpecFrontView.class, MapUtils.builder().field(GoodsDonSpecFrontView::getGoodsId, views.getId()).build())); views.setSkuList(beanSearcher.searchAll(GoodsDonSkuFrontView.class, MapUtils.builder().field(GoodsDonSkuFrontView::getGoodsId, views.getId()).field(GoodsDonSkuFrontView::getStatus, true).build())); ticket.setGoodsDonViews(views); } if (ticket.getMonths() != null && ticket.getMonths() >= 300) { ticket.setExpiryTime(null); } if (ticket.getExpiryTime() != null && ticket.getGoodsType() == 1 && ticket.getSecondType() == 2) { String remainDays = DateUtil.formatBetween(now, ticket.getExpiryTime(), BetweenFormater.Level.DAY); if ("0天".equals(remainDays)) { remainDays = "小于1天"; } else { //当天也算 int days = Integer.parseInt(remainDays.substring(0, remainDays.indexOf("天"))); remainDays = days + 1 + "天"; } ticket.setRemainDays(remainDays); } OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class) .eq(OrderDon::getRelationId, ticket.getRelationId()) .eq(OrderDon::getUserId, ticket.getUserId()) .notIn(OrderDon::getStatus, Constant.noOrderAllStatus) .orderByDesc(OrderDon::getId) .last("limit 1")); if (orderDon != null) { ticket.setOrderNo(orderDon.getOrderNo()); ticket.setOrderId(orderDon.getId()); ticket.setTransactionId(orderDon.getTransactionId()); } if (size > 1 && ticket.getGoodsId() != 18) { Date payTime = null; if (orderDon != null) { payTime = Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime()); } //加购订单 if (orderDon == null) { List plusPurchaseSkuRelations = orderDiscountPlusPurchaseSkuRelationMapper.selectPlusRelationByIdAndUserId(ticket.getRelationId(), ticket.getUserId()); for (OrderDiscountPlusPurchaseSkuRelation data : plusPurchaseSkuRelations) { String relationIds = data.getRelationIds(); if (StrUtil.isEmpty(relationIds)) { return; } try { List relationList = Jsons.parseList(relationIds, Long.class); if (relationList.contains(ticket.getRelationId())) { OrderDon plusOrder = orderDonMapper.selectById(data.getOrderId()); if (plusOrder != null) { payTime = Optional.ofNullable(plusOrder.getPayTime()).orElse(plusOrder.getCreatedTime()); } break; } } catch (Exception e) { } } } ticket.setPayTime(payTime); } if (ticket.getGoodsId() == 26 && ticket.getIsMirror()){ List upgradePackages = upgradePackageMapper.selectList(Wrappers.lambdaQuery(UpgradePackage.class).apply("JSON_CONTAINS(sku_ids,'\"" + ticket.getSkuId() + "\"')").eq(UpgradePackage::getStatus, Boolean.TRUE).eq(UpgradePackage::getDeleted, Boolean.TRUE)); if (CollectionUtil.isNotEmpty(upgradePackages)){ upgradePackages.stream().map(e -> e.getPrice().divide(BigDecimal.valueOf(e.getNum()), 2, RoundingMode.HALF_UP)).min(BigDecimal::compareTo).ifPresent(ticket::setMjPackagePrice); } try { MidjourneyUserView search = beanSearcher.searchFirst(MidjourneyUserView.class, MapUtils.flatBuilder(request.getParameterMap()) .field(MidjourneyUserView::getUserId, ticket.getUserId()).field(MidjourneyUserView::getRelationId, ticket.getRelationId()) .onlySelect(MidjourneyUserView::getMjFastNum, MidjourneyUserView::getMjRelaxNum) .build()); if (search == null) { MidjourneyUser midjourneyUser = midjourneyAccountService.getMidjourneyUserToken(ticket.getUserId(), ticket.getRelationId()); ticket.setMjUserFastNum(midjourneyUser.getMjFastNum()); ticket.setMjUserRelaxNum(midjourneyUser.getMjRelaxNum()); } else { ticket.setMjUserFastNum(search.getMjFastNum()); ticket.setMjUserRelaxNum(search.getMjRelaxNum()); } } catch (Exception e) { } } if (ticket.getGoodsId() == 18 && ticket.getIsCar() && ticket.getExpiryTime() != null) { //gpt用户镜像 ChatGptUserView userInfo = chatGptAccountService.getUserInfo(userId, ticket.getRelationId()); ticket.setGptUserLimitNum(userInfo.getLimitNum()); ticket.setGptUserLimitTime(userInfo.getLimitTime()); ticket.setUse(userInfo.getUse()); Integer count = upgradePackageMapper.selectCount(Wrappers.lambdaQuery(UpgradePackage.class).apply("JSON_CONTAINS(sku_ids,'\"" + ticket.getSkuId() + "\"')") .gt(UpgradePackage::getNum, userInfo.getLimitNum()) .eq(UpgradePackage::getStatus, Boolean.TRUE) .eq(UpgradePackage::getGptType, 0) .eq(UpgradePackage::getDeleted, Boolean.TRUE)); ticket.setUpgrade(count > 0 ? true : false); ticket.setPackageId(userInfo.getPackageId()); if (userInfo.getPackageId() != 0) { UpgradePackage upgradePackage = upgradePackageMapper.selectById(userInfo.getPackageId()); ticket.setPackagePrice(upgradePackage.getPrice()); } } List relationUserViews = groupsRelationMapper.getUserRelationUserViews(ticket.getGroupId(), ticket.getRelationId(), ticket.getUserId(), List.of(GroupsRelation.Status.validity, GroupsRelation.Status.outside)); ticket.setRelationViews(relationUserViews); if (ticket.getExpiryTime() != null) { ticket.setExpiryTimeStr(DateUtil.format(ticket.getExpiryTime(), "yyyy-MM-dd")); } //查看双重验证码 if (StrUtil.isNotEmpty(ticket.getApiSecret())) { Boolean isHasVerifyCode = StrUtil.isNotBlank(ticket.getVerifyCode()) ? true : false; Integer codeNum = getUserCodeNumBySkuId(ticket.getUserId(), ticket.getSkuId(), isHasVerifyCode); ticket.setCodeNum(codeNum); } Long qaId = groupsRelationMapper.selectGoodsDonQaByGoodsId(ticket.getGoodsId()); ticket.setQa(qaId > 0 ? true : false); //是否存在海报 ticket.setPosterInfo(setGoodsPoster(ticket, u)); }); userLoginRecordService.saveUserLoginDayRecord(userId); return list; } @Override public Boolean isJoinCorpWx(Long userId, Boolean isJoin, Boolean noCoupon) { if (!isJoin) { User user = userMapper.selectById(userId); if (user == null || StrUtil.isEmpty(user.getUnionid())) { return true; } // CorpUser corpUser = corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class) // .ne(CorpUser::getUnionid, "") // .eq(CorpUser::getUnionid, user.getUnionid()) // .last("limit 1") // .select(CorpUser::getId) // ); CorpUserFollowView corpUserFollowView = beanSearcher.searchFirst(CorpUserFollowView.class, MapUtils.builder() .field(CorpUserFollowView::getUnionId, user.getUnionid()) .field(CorpUserFollowView::getStatus, 1).build()); if (corpUserFollowView == null) { return false; } } //用户是否买了奈飞车票 Number number = beanSearcher.searchCount(RenewalView.class, MapUtils.builder() .field(RenewalView::getUserId, userId) .field(RenewalView::getGoodsId, 1) .field(RenewalView::getStatus, List.of("validity", "overdue")).op(Operator.InList) .build()); if (number.intValue() > 0 && !noCoupon) { couponCommonService.sendCouponToUser(userId, 34l, 0l, 0l, 0l, CouponUser.Channel.wxCorp); } return true; } @Override public GroupsRelation getSimilarExpiredGroupRelation(GoodsDonSku sku, List errorsRelationIds, String ip) { Long skuId = sku.getId(); Integer days = sku.getDays(); Integer months = sku.getMonths(); Integer maxNum = sku.getNum(); DateTime expiryTime = null; if (days != null && days > 0) { expiryTime = DateUtil.offsetDay(DateTime.now(), days); } else { expiryTime = DateUtil.offsetMonth(DateTime.now(), months); } Integer extraNum = 5; if (sku.getId() == 178l) { extraNum = 2; } maxNum += extraNum; DateTime minExpiryTime = DateUtil.offsetDay(expiryTime, -5); Long groupsId = groupsRelationMapper.selectSimilarExpiredRelation(skuId, minExpiryTime, maxNum, ip); if (groupsId == null) { log.info("暂无相似过期时间车队"); return null; } GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class) .notIn(errorsRelationIds != null && errorsRelationIds.size() > 0, GroupsRelation::getId, errorsRelationIds) .eq(GroupsRelation::getGroupsId, groupsId) .eq(GroupsRelation::getStatus, GroupsRelation.Status.none) .eq(GroupsRelation::getUserId, 0) .orderByAsc(GroupsRelation::getNum) .last("limit 1")); if (relation != null) { log.info("用户userId:{},获取相似车队的车位relationId:{}", relation.getId()); } return relation; } @Override public Page getRecommendGoodsViews(Boolean isPayNf, List filter_goods_id, Boolean filterCourseGoods, Integer start, Integer limit) { return groupsRelationMapper.getRecommendGoodsViews(new Page<>(start, limit), filter_goods_id, isPayNf, filterCourseGoods); } @Override @Transactional(rollbackFor = Throwable.class) public void sendCourseWare(SpecialGoodsTicketReq request) throws Exception { Long userId = request.getUserId(); Long relationId = request.getRelationId(); String email = request.getEmail(); List userIdList = userBindRelationService.getRelationUserIdList(userId, null); RenewalView relation = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getRelationId, relationId).build()); Assert.notNull(relation, "您的车票不存在"); Long relationUserId = relation.getUserId(); if (!userIdList.contains(relationUserId)) { throw BusinessRuntimeException.getInstance("您的车票不存在"); } if (relation.getSpecialType() != GoodsDon.SpecialType.courseware) { throw BusinessRuntimeException.getInstance(""); } //是否已发送 if (StrUtil.isNotBlank(relation.getGrAccount())) { throw BusinessRuntimeException.getInstance("已领取课件,请前往邮箱查看"); } if (!Validator.isEmail(email)) { throw BusinessRuntimeException.getInstance("请输入正确的邮箱"); } int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getAccount, email) .and(qr -> qr.isNull(GroupsRelation::getAccount).or().eq(GroupsRelation::getAccount, StrUtil.EMPTY)) .eq(GroupsRelation::getId, relationId)); if (update > 0) { orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class) .set(OrderDon::getStatus, OrderDon.Status.complete) .eq(OrderDon::getRelationId, relationId) .eq(OrderDon::getUserId, userId) .eq(OrderDon::getStatus, OrderDon.Status.hasPayment)); mailService.sendCoursewareByGoodsId(relation.getGoodsId(), relation.getRelationId(), relation.getUserId(), relation.getTitle(), email); } } @Override public GroupsRelation getRelation(Long payRelationId, Long userId, GoodsDonSku sku, String ip) { GroupsRelation relation = null; Integer maxNum = sku.getNum(); if (payRelationId != null && payRelationId > 0) { relation = groupsRelationMapper.selectById(payRelationId); if (relation == null) { throw new BusinessRuntimeException(GROUP_INDEX_NOT_FIND.getCode(), GROUP_INDEX_NOT_FIND.getMsg()); } if (relation.getUserId() != null && relation.getUserId() > 0L) { throw new BusinessRuntimeException(GROUP_INDEX_ALREADY_BE_USER.getCode(), GROUP_INDEX_ALREADY_BE_USER.getMsg()); } } else { GroupsTrips groups = null; //ChatGpt Plus、Midjourney非独立规格 上车先获取硬塞座位 硬塞5个座位 //主账号过期时间25天以外 //23-12-06 MidJourney 不硬塞 if (sku.getNum() > 1 && Constant.AI_goodsIds.get(0) == sku.getGoodsId()) { Integer extraNum = 5; if (sku.getId() == 178l || sku.getId() == 423l) { extraNum = 2; } maxNum += extraNum; DateTime time = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 25); //不塞存在该用户的车队 Long groupsId = groupsRelationMapper.getOutSideGroupsTripsRelationByGoodsId(sku.getId(), time, extraNum, userId, sku.getNum(), maxNum); if (groupsId != null) { relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGroupsId, groupsId) .eq(GroupsRelation::getUserId, 0) .eq(GroupsRelation::getStatus, GroupsRelation.Status.outside) .last("limit 1")); if (relation == null) { relation = new GroupsRelation(); relation.setStatus(GroupsRelation.Status.outside); relation.setUserId(userId); relation.setGroupsId(groupsId); GroupsRelation maxNumRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1")); Integer nextNum = maxNumRelation.getNum() + 1; if (redisService.setNx(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getNameFormat(groupsId, nextNum), nextNum, RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getTimeout())) { relation.setNum(nextNum); groupsRelationMapper.insert(relation); } else { throw BusinessRuntimeException.getInstance("系统繁忙,请重试..."); } } groups = groupsMapper.selectById(groupsId); } } if (groups == null) { //寻找差不多过期时间规格的车位 relation = getSimilarExpiredGroupRelation(sku, null, ip); if (relation == null) { //TODO 如果没指定座位,等待逻辑确认 groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.validity, maxNum, ip); if (groups == null) { //待发车 groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.waiting, maxNum, ip); } //新增空车队 if (groups == null) { relation = groupsFuncService.createNewGroupsTrips(sku); } //获取车位 if (relation == null) { //寻找快满编车队进行占座 relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId()); if (relation == null) { Long groupsId = groups.getId(); TASK_EXECUTOR.execute(() -> groupsMapper.updateAvailableNum(groupsId)); throw BusinessRuntimeException.getInstance("系统繁忙,请重试..."); } } } } if (groups == null) { groups = groupsMapper.selectById(relation.getGroupsId()); } //车队目前可用停车数 relation.setGroupsAvailParkingNum(groups.getAvailableParkingNum()); relation.setMaxNum(maxNum); } return relation; } @Override public String getAiVerifyCode(Long userId, Long relationId, Integer type, Boolean sync) throws Exception { List relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null); RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getUserId, relationUserIdList).op(Operator.InList) .field(RenewalView::getRelationId, relationId).build()); if (renewalView == null) { throw BusinessRuntimeException.getInstance("您的车票不存在..."); } if (StrUtil.isEmpty(renewalView.getAccount())) { throw BusinessRuntimeException.getInstance("车票未配置账号"); } String account = renewalView.getAccount(); String password = renewalView.getPassword(); if (StrUtil.hasEmpty(account, password)) { throw BusinessRuntimeException.getInstance("您的车票账号密码异常,请联系客服..."); } if (renewalView.getAccount().contains(CUI_QIU_EMAIL_SUFFIX)) { return cuiQiuMailService.getVerifyCode(renewalView.getAccount(), renewalView.getGoodsId(), type, sync); } //获取邮箱密码 SysEmail sysEmail = sysEmailMapper.selectOne(Wrappers.lambdaQuery(SysEmail.class) .eq(SysEmail::getEmail, account) .last("limit 1")); if (sysEmail == null) { log.info("获取账号:{}验证码异常,未配置对应系统邮箱", account); throw BusinessRuntimeException.getInstance("获取账号验证码异常,请联系客服..."); } String url = "http://yinhelx.com/api/controller.php"; Map params = new HashMap<>(); params.put("imap_key", "imap_56568niua@@"); params.put("fun", "imap_read"); params.put("imap_ip", "yinhelx.com"); params.put("port", "143"); params.put("username", account); params.put("password", sysEmail.getPassword()); params.put("mbox_id", "0"); params.put("delete", "0"); HttpRequest post = HttpUtil.createPost(url); post.form(params); cn.hutool.http.HttpResponse execute = post.execute(); if (execute.getStatus() != HttpStatus.HTTP_OK) { throw BusinessRuntimeException.getInstance("获取验证码异常,请联系客服..."); } String code = getDifferentGoodsCode(renewalView.getGoodsId(), execute.body(), type, sync); GroupsRelationLoginCodeRecord record = new GroupsRelationLoginCodeRecord(); record.setUserId(userId); record.setRelationId(relationId); record.setAccount(renewalView.getAccount()); record.setGoodsId(renewalView.getGoodsId()); record.setSkuId(renewalView.getSkuId()); groupsRelationLoginCodeRecordMapper.insert(record); return code; } @Override public void checkGroupsAvailParkingNum(Long skuId, Long groupsId, Integer availableParkingNum, Integer maxNum) { //GPT10人月付、4人月付 if (skuId == 161l || skuId == 178l) { //为0时,不参与限制 if (availableParkingNum == 0) { return; } //目前车队可用停车数 //目前上车人数 Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGroupsId, groupsId) .ne(GroupsRelation::getUserId, 0) .le(GroupsRelation::getNum, maxNum)); if (currentParkingNum > availableParkingNum) { throw BusinessRuntimeException.getInstance("系统繁忙,请重试..."); } } } @Override public void adjustGroupsParkingTime(Long relationId, GoodsDonSku sku) { Long skuId = sku.getId(); //更新GPT Plus10人、4人月付车队状态 待优化 if (skuId == 161l || skuId == 178l || skuId == 422l || skuId == 423l) { GroupsRelation relation = groupsRelationMapper.selectById(relationId); Long groupsId = relation.getGroupsId(); GroupsTrips groupsTrips = groupsMapper.selectById(groupsId); Integer availableParkingNum = groupsTrips.getAvailableParkingNum(); //为0时 不参与限制 if (availableParkingNum == 0) { return; } Integer extraNum = 5; if (skuId == 178l || skuId == 423l) { extraNum = 2; } Integer maxNum = sku.getNum() + extraNum; if (availableParkingNum >= maxNum) { return; } //目前上车人数 Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGroupsId, groupsId) .ne(GroupsRelation::getUserId, 0) .le(GroupsRelation::getNum, maxNum)); if (currentParkingNum >= availableParkingNum) { //锁住 DateTime parkingTime = DateUtil.offsetDay(DateTime.now(), 1); groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class) .eq(GroupsTrips::getId, groupsTrips.getId()) .set(GroupsTrips::getParkingTime, parkingTime) .isNull(GroupsTrips::getParkingTime)); } } } @Override public void setGroupsTripsParkingTimeEmpty(GoodsDonSku sku, Long relationId) { Long skuId = sku.getId(); if (skuId == 161l || skuId == 178l) { GroupsRelation relation = groupsRelationMapper.selectById(relationId); Long groupsId = relation.getGroupsId(); GroupsTrips groupsTrips = groupsMapper.selectById(groupsId); Integer availableParkingNum = groupsTrips.getAvailableParkingNum(); if (groupsTrips.getParkingTime() == null || availableParkingNum == 0) { return; } Integer extraNum = 5; if (skuId == 178l) { extraNum = 2; } Integer skuNum = sku.getNum(); if (availableParkingNum >= skuNum + extraNum) { return; } //目前上车人数 Integer currentParkingNum = groupsRelationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGroupsId, groupsId) .ne(GroupsRelation::getUserId, 0)); if (currentParkingNum < availableParkingNum) { groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class) .eq(GroupsTrips::getId, groupsTrips.getId()) .set(GroupsTrips::getParkingTime, null) .isNotNull(GroupsTrips::getParkingTime)); } } } @Override public Integer getUserCodeNumBySkuId(Long userId, Long skuId, Boolean isHasVerifyCode) { //查看双重验证码 UserFuncProperty userFuncProperty = userFuncPropertyMapper.selectOne(Wrappers.lambdaQuery(UserFuncProperty.class).eq(UserFuncProperty::getUserId, userId).last("limit 1")); //默认2次 int num = 2; //有安全码查看次数 置为0 if (isHasVerifyCode) { num = 0; //存在身份实名认证有两次机会 List userIdList = userBindRelationService.getRelationUserIdList(userId, null); Integer selectCount = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class) .in(UserCertRecord::getUserId, userIdList)); if (selectCount > 0) { num = 2; } return num; } //查看双重验证码次数 GoodsDonSku sku = goodsDonSkuMapper.selectById(skuId); if (sku.getCodeNum() > 0) { num = sku.getCodeNum(); } if (userFuncProperty != null) num = userFuncProperty.getVerifyCheckNum(); return num; } @Override public List getHasPayGoods(long userId) { User user = userMapper.selectById(userId); List userIds = userBindRelationService.getRelationUserIdList(userId, user); DateTime now = DateTime.now(); List list = groupsRelationMapper.getUserHasPayGoods(userIds, now); return list; } @Override public List getExpiryRenewalNotify(Long userId) { DateTime now = DateTime.now(); DateTime thisZero = DateUtil.beginOfDay(now); String thisDate = thisZero.toDateStr(); Object exists = redisService.get(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId)); if (exists != null) { return null; } User u = userMapper.selectById(userId); if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID); if (u.getIsBlack()) { redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout()); return null; } List userIds = userBindRelationService.getRelationUserIdList(userId, u); MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap()); List list = beanSearcher.searchAll(RenewalView.class, builder .field(RenewalView::getUserId, 0).op(Operator.GreaterThan) .field(RenewalView::getUserId, userIds).op(Operator.InList) .field(RenewalView::getExpiryTime, now).op(Operator.GreaterThan) .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList) .field(RenewalView::getAqType, 1) .orderBy(RenewalView::getExpiryTime).asc() .onlySelect(RenewalView::getMonths, RenewalView::getExpiryTime, RenewalView::getRelationId, RenewalView::getAccount, RenewalView::getGoodsId, RenewalView::getTitle, RenewalView::getLogo, RenewalView::getImg, RenewalView::getGroupId, RenewalView::getSkuId, RenewalView::getSpecVal, RenewalView::getGoodsStatus, RenewalView::getSkuStatus) .build()); if (list.size() > 5) { redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout()); return null; } //提前7天 AtomicInteger day = new AtomicInteger(7); List expiryTickets = list.stream().filter(ticket -> { //下架 if (ticket.getGoodsStatus() == null || ticket.getSkuStatus() == null || !ticket.getGoodsStatus() || !ticket.getSkuStatus()) { return false; } Integer skuMonths = ticket.getMonths(); Date expiryTime = ticket.getExpiryTime(); //年付 提前一个月 if (skuMonths >= 12) { day.set(30); } else { day.set(7); } if (DateUtil.beginOfDay(expiryTime).compareTo(DateUtil.offsetDay(thisZero, day.get())) <= 0) { ticket.setExpiryTimeStr(DateUtil.format(ticket.getExpiryTime(), "yyyy-MM-dd")); ticket.setExpiryTime(null); return true; } return false; }).collect(Collectors.toList()); redisService.setNx(RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getNameFormat(thisDate, userId), userId, RedisService.key.TICKET_EXPIRY_NOTIFY_DAY.getTimeout()); if (CollUtil.isNotEmpty(expiryTickets)) { groupsRelationExpiryNotifyRecordMapper.batchInsert(userId, expiryTickets); } return expiryTickets; } public String getDifferentGoodsCode(Long goodsId, String body, Integer type, Boolean sync) { String code = null; //奈飞 if (goodsId == 1) { if (type != null && type == 1) { if (body.contains("輸入此代碼登入") || body.contains("输入此代码登录")) { code = StrUtil.subBetween(body, "輸入此代碼登入", "請在裝置上輸入上"); if (StrUtil.isEmpty(code)) { code = StrUtil.subAfter(body, "输入此代码登录", true); } } if (StrUtil.isEmpty(code)) { throw BusinessRuntimeException.getInstance("查询失败,请检查是否发送了登陆码.."); } } else { String urlPref = "https://www.netflix.com/account/update-primary-location"; code = StrUtil.subBetween(body, "[" + urlPref, "]"); if (StrUtil.isEmpty(code)) { urlPref = "https://www.netflix.com/account/travel/verify"; code = StrUtil.subBetween(body, "[" + urlPref, "]"); if (StrUtil.isEmpty(code)) { throw BusinessRuntimeException.getInstance("获取认证链接失败,请重新获取"); } } String url = urlPref + code; //非点击装置同步更新按钮 直接返回链接 if (!sync) return url; //失败返回验证链接 if (!groupsRelationNetflixService.confirmUpdate(url)) { return url; } return StrUtil.EMPTY; } } //除奈飞 if (StrUtil.isEmpty(code)) { code = TicketCodeCommonUtil.getTicketCodeStr(body, goodsId); } int length = 4; if (goodsId == 33l) { length = 6; } code = StringUtil.getVerifyCodePattern(code, length); if (!Validator.isNumber(code)) { log.error("获取账号验证码失败:{}", StrUtil.subSufByLength(code, 512)); throw BusinessRuntimeException.getInstance("获取验证码失败,请重新获取.."); } return code.trim(); } @Override public void getCollegeStudentUserGptTicket(Long userId) { Retryer build = RetryerBuilder.newBuilder() .retryIfException() //运行时异常重试 .retryIfRuntimeException() //false重试 .retryIfResult(res -> Objects.equals(res, false)) //1s 间隔 .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS)) //停止策略 : 尝试请求3次 .withStopStrategy(StopStrategies.stopAfterAttempt(3)).build(); try { build.call(() -> { //体验规格 Long gptMirrorSkuId = Constant.GPT_MIRROR_SKU_ID; GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(gptMirrorSkuId); GroupsRelation relation = null; if (groups != null) { relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId()); } if (relation == null) { //生成空车队 GoodsDonSku sku = goodsDonSkuMapper.selectById(gptMirrorSkuId); relation = groupsFuncService.createNewGroupsTrips(sku); } DateTime startTime = DateTime.now(); DateTime expiryTime = DateUtil.offsetDay(startTime, 1); int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getUserId, userId) .set(GroupsRelation::getStartTime, startTime) .set(GroupsRelation::getExpiryTime, expiryTime) .set(GroupsRelation::getStatus, GroupsRelation.Status.validity) .set(GroupsRelation::getAqType, 2) .eq(GroupsRelation::getId, relation.getId()) .eq(GroupsRelation::getUserId, 0)); if (update > 0) { groupsMapper.decrAvailableNum(groups.getId()); return true; } log.error("发送用户:{} GPT镜像车票体验失败,进行重试", userId); return false; }); } catch (ExecutionException | RetryException e) { log.error("发送用户GPT镜像体验失败:{}", StringUtil.getErrorText(e)); } } @Override public RenewalView getTicketDetail(long userId, Long relationId) { User u = userMapper.selectById(userId); List userIds = userBindRelationService.getRelationUserIdList(userId, u); MapBuilder builder = MapUtils.builder(); RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, builder .field(RenewalView::getRelationId, relationId) .field(RenewalView::getUserId, 0).op(Operator.GreaterThan) .field(RenewalView::getUserId, userIds).op(Operator.InList) .field("condition", String.format("(gr.expiry_time is null or gr.expiry_time > '%s')", DateTime.now())) .field(RenewalView::getStatus, List.of("validity", "outside")).op(Operator.InList) .orderBy(RenewalView::getExpiryTime).asc() .onlySelect(RenewalView::getRelationId, RenewalView::getExpiryTime, RenewalView::getTitle, RenewalView::getSpecVal, RenewalView::getGoodsId, RenewalView::getSkuId, RenewalView::getSkuNum, RenewalView::getSkuStatus, RenewalView::getGoodsStatus) .build()); if (renewalView != null) { renewalView.setExpiryTimeStr(DateUtil.format(renewalView.getExpiryTime(), "yyyy-MM-dd")); } return renewalView; } private DistributePosterGoodsDetailView setGoodsPoster(RenewalView ticket, User user) { DistributePosterGoodsDetailView distributePosterGoodsDetailView = beanSearcher.searchFirst(DistributePosterGoodsDetailView.class, MapUtils.flatBuilder(request.getParameterMap()) .field(DistributePosterGoodsFrontView::getGoodsId, ticket.getGoodsId()).build()); if (distributePosterGoodsDetailView == null) { return null; } distributePosterGoodsDetailView.setNickname(user.getNickname()); UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class) .eq(UserDistribute::getUserId, user.getId()) .eq(UserDistribute::getDeleted, 1) .last("limit 1")); if (userDistribute != null) { UserPlatDistributeRate userPlatDistributeRate = userPlatDistributeRateMapper.selectOne(Wrappers.lambdaQuery(UserPlatDistributeRate.class) .eq(UserPlatDistributeRate::getDistributeId, userDistribute.getId()) .eq(UserPlatDistributeRate::getGoodsId, ticket.getGoodsId()) .last("limit 1")); if (userPlatDistributeRate != null) { distributePosterGoodsDetailView.setRate(userPlatDistributeRate.getRate()); } } GoodsDon goodsDon = goodsDonMapper.selectById(ticket.getGoodsId()); if (goodsDon.getIsSkuDistribute()) { if (userDistribute != null) { UserPlatSkuDistributeRate userPlatSkuDistributeRate = userPlatSkuDistributeRateMapper.selectOne(Wrappers.lambdaQuery(UserPlatSkuDistributeRate.class) .eq(UserPlatSkuDistributeRate::getDistributeId, userDistribute.getId()) .eq(UserPlatSkuDistributeRate::getSkuId, ticket.getSkuId()) .last("limit 1")); if (userPlatSkuDistributeRate != null) { distributePosterGoodsDetailView.setRate(userPlatSkuDistributeRate.getRate()); } } else { DistributeGeneralSkuRate distributeGeneralSkuRate = distributeGeneralSkuRateMapper.selectOne(Wrappers.lambdaQuery(DistributeGeneralSkuRate.class) .eq(DistributeGeneralSkuRate::getSkuId, ticket.getSkuId()) .last("limit 1")); if (distributeGeneralSkuRate != null) { distributePosterGoodsDetailView.setRate(distributeGeneralSkuRate.getRate()); } } } return distributePosterGoodsDetailView; } }