SchedulerServiceImpl.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package com.cyksj.service.scheduler.impl;
  2. import cn.hutool.core.date.DateTime;
  3. import cn.hutool.core.date.DateUnit;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.StrUtil;
  6. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  7. import com.cyksj.common.constant.Constant;
  8. import com.cyksj.common.util.StringUtil;
  9. import com.cyksj.dto.RedisKey;
  10. import com.cyksj.mapper.*;
  11. import com.cyksj.model.entity.*;
  12. import com.cyksj.model.manage.views.GroupsRelationView;
  13. import com.cyksj.model.request.ChangeRelationReq;
  14. import com.cyksj.redis.RedisService;
  15. import com.cyksj.service.error.UserRelationChangeErrorRecordService;
  16. import com.cyksj.service.groups.GroupsFuncService;
  17. import com.cyksj.service.mange.CmsOrderDonService;
  18. import com.cyksj.service.order.OrderRefundService;
  19. import com.cyksj.service.relation.GroupRelationClearService;
  20. import com.cyksj.service.scheduler.SchedulerService;
  21. import com.cyksj.service.user.UserBenefitsService;
  22. import com.ejlchina.searcher.BeanSearcher;
  23. import com.ejlchina.searcher.param.Operator;
  24. import com.ejlchina.searcher.util.MapUtils;
  25. import lombok.RequiredArgsConstructor;
  26. import lombok.extern.slf4j.Slf4j;
  27. import org.springframework.stereotype.Service;
  28. import java.math.BigDecimal;
  29. import java.math.RoundingMode;
  30. import java.util.Date;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.concurrent.ConcurrentHashMap;
  34. /*
  35. *项目名: netflix
  36. *文件名: SchedulerServiceImpl
  37. *创建者: JavaZou
  38. *创建时间:2023/6/8 16:48
  39. */
  40. @Service
  41. @RequiredArgsConstructor
  42. @Slf4j
  43. public class SchedulerServiceImpl implements SchedulerService {
  44. private final GoodsDonSkuMapper skuMapper;
  45. private final GroupsMapper groupsMapper;
  46. private final BeanSearcher beanSearcher;
  47. private final OrderDonMapper orderDonMapper;
  48. private final GroupsRelationMapper groupsRelationMapper;
  49. private final GroupRelationClearService groupRelationClearService;
  50. private final UserBenefitsService userBenefitsService;
  51. private final GroupsFuncService groupsFuncService;
  52. private final OrderRefundService orderRefundService;
  53. private final CmsOrderDonService cmsOrderDonService;
  54. private final UserRelationChangeErrorRecordService changeErrorRecordService;
  55. private final UserRelationChangeErrorRecordMapper userRelationChangeErrorRecordMapper;
  56. private final GoodsDonMapper goodsDonMapper;
  57. private final RedisService redisService;
  58. @Override
  59. public void transExpiryAccountValidRelation() {
  60. DateTime now = new DateTime();
  61. DateTime nextBeginDay = DateUtil.offsetDay(DateUtil.beginOfDay(now), 1);
  62. //针对AI类 CHAT PLUS、MidJourney 月付
  63. List<Long> aiSkuIds = skuMapper.selectAIMonthSkuIds(Constant.AI_goodsIds);
  64. List<GroupsTrips> expiryAccountGroups = groupsMapper.getExpiryAccountGroups(nextBeginDay, aiSkuIds);
  65. expiryAccountGroups.forEach(expiry_groups -> {
  66. if (expiry_groups.getStatus() != GroupsTrips.Status.down) {
  67. expiry_groups.setStatus(GroupsTrips.Status.down);
  68. groupsMapper.updateById(expiry_groups);
  69. }
  70. Long g_groupsId = expiry_groups.getId();
  71. Date a_expiryTime = expiry_groups.getExpiryTime();
  72. //未过期用户 只分配有效的用户车票 outside状态过滤
  73. List<GroupsRelationView> groupsRelations = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
  74. .field(GroupsRelationView::getGroupsId, g_groupsId)
  75. .field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name())
  76. .field(GroupsRelationView::getExpiryTime, nextBeginDay).op(Operator.GreaterEqual)
  77. .build());
  78. reAssign(g_groupsId, now, groupsRelations, UserTicketClearedRecord.Source.timing_change_ticket);
  79. });
  80. }
  81. @Override
  82. public void assignUserGroupsRelation(Long groupsId) {
  83. GroupsTrips groupsTrips = groupsMapper.selectById(groupsId);
  84. if (groupsTrips == null || groupsTrips.getAccountId() == null) return;
  85. String key = RedisKey.DISABLE_ACCOUNT_ASSIGN + groupsId;
  86. if (!redisService.setNx(key, groupsId, 60 * 3l)) {
  87. return;
  88. }
  89. if (groupsTrips.getStatus() != GroupsTrips.Status.down) {
  90. groupsTrips.setStatus(GroupsTrips.Status.down);
  91. groupsMapper.updateById(groupsTrips);
  92. }
  93. DateTime now = DateTime.now();
  94. //迁移用户
  95. List<GroupsRelationView> groupsRelations = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
  96. .field(GroupsRelationView::getGroupsId, groupsId)
  97. .field(GroupsRelationView::getStatus, List.of(GroupsRelation.Status.validity.name(), GroupsRelation.Status.outside.name())).op(Operator.InList)
  98. .field(GroupsRelationView::getExpiryTime, now).op(Operator.GreaterEqual)
  99. .build());
  100. reAssign(groupsId, now, groupsRelations, UserTicketClearedRecord.Source.disable);
  101. redisService.del(key);
  102. }
  103. /**
  104. * 重新分配车位
  105. */
  106. public void reAssign(Long g_groupsId, DateTime now, List<GroupsRelationView> groupsRelations, UserTicketClearedRecord.Source source) {
  107. log.info("迁移groupsId:{}未过期用户数量:{}", g_groupsId, groupsRelations.size());
  108. Map<Long, GoodsDon> goodsMap = new ConcurrentHashMap<>();
  109. Map<Long, GoodsDonSku> skuMap = new ConcurrentHashMap<>();
  110. groupsRelations.forEach(relationView -> {
  111. Long change_relationId = relationView.getId();
  112. Long userId = relationView.getUserId();
  113. UserRelationChangeErrorRecord exists = userRelationChangeErrorRecordMapper.selectOne(Wrappers.lambdaQuery(UserRelationChangeErrorRecord.class)
  114. .eq(UserRelationChangeErrorRecord::getRelationId, change_relationId)
  115. .eq(UserRelationChangeErrorRecord::getUserId, userId)
  116. .eq(UserRelationChangeErrorRecord::getDeleted, true)
  117. .last("limit 1"));
  118. if (exists != null) {
  119. log.info("存在userId:{}无法转移的车票relationId:{}", userId, change_relationId);
  120. return;
  121. }
  122. Date expiryTime = DateUtil.beginOfDay(relationView.getExpiryTime());
  123. Long skuId = relationView.getSkuId();
  124. //仅针对chatGPT
  125. if (Constant.AI_goodsIds.contains(relationView.getGoodsId())) {
  126. Long bet_day = DateUtil.between(now, expiryTime, DateUnit.DAY);
  127. //10人月付 10天内硬塞20个 10天外硬塞10个
  128. //4人月付 硬塞5个
  129. Integer extra_num = 5;
  130. //10天以内
  131. if (bet_day <= 10) {
  132. if (skuId.equals(161l)) {
  133. extra_num = 20;
  134. }
  135. //分配到过期账号5天内误差的相同规格车队里
  136. DateTime five_day = DateUtil.offsetDay(expiryTime, 5);
  137. Long item_groupsId = groupsMapper.selectSameSpecItemGroupsByTime(g_groupsId, skuId, expiryTime, five_day, extra_num);
  138. if (item_groupsId == null) {
  139. //无对应车队 退款
  140. //退款至余额
  141. OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
  142. .eq(OrderDon::getRelationId, change_relationId)
  143. .eq(OrderDon::getUserId, userId)
  144. .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
  145. .orderByDesc(OrderDon::getId)
  146. .last("limit 1"));
  147. if (orderDon == null) {
  148. //更换过车票
  149. orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
  150. .eq(OrderDon::getSkuId, skuId)
  151. .eq(OrderDon::getUserId, userId)
  152. .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
  153. .orderByDesc(OrderDon::getId)
  154. .last("limit 1"));
  155. }
  156. if (orderDon == null) {
  157. log.error("用户userId:{}的车票relationId:{}账号过期后转移错误", userId, change_relationId);
  158. changeErrorRecordService.changeTicketErrorRecord(relationView, UserRelationChangeErrorRecord.Source.change);
  159. return;
  160. }
  161. //清除车票
  162. GroupsRelation relation = groupsRelationMapper.selectById(change_relationId);
  163. groupRelationClearService.clearTicket(relation, UserTicketClearedRecord.Source.refund_balance);
  164. //退款至余额
  165. //实付金额 + 余额
  166. BigDecimal money = orderDon.getMoney().add(orderDon.getBalance());
  167. //当月天数
  168. Date payTime = orderDon.getPayTime();
  169. if (payTime == null) {
  170. payTime = orderDon.getCreatedTime();
  171. }
  172. if (money.compareTo(BigDecimal.ZERO) == 0) {
  173. GoodsDonSku sku = skuMapper.selectById(skuId);
  174. if (sku != null) {
  175. money = sku.getPrice();
  176. }
  177. }
  178. int dayNum = DateUtil.dayOfMonth(DateUtil.endOfMonth(payTime));
  179. BigDecimal re_balance = money.divide(BigDecimal.valueOf(dayNum), 0, RoundingMode.DOWN).multiply(BigDecimal.valueOf(bet_day));
  180. if (re_balance.compareTo(BigDecimal.ZERO) <= 0) {
  181. log.info("user_id:{},relationId:{}返回余额为0", userId, change_relationId);
  182. return;
  183. }
  184. GoodsDon goodsDon = goodsMap.get(relationView.getGoodsId());
  185. if (goodsDon == null) {
  186. goodsDon = goodsDonMapper.selectById(relationView.getGoodsId());
  187. if (goodsDon == null) return;
  188. goodsMap.putIfAbsent(relationView.getGoodsId(), goodsDon);
  189. }
  190. userBenefitsService.addUserBalance(userId, re_balance, UserBalanceSourceRecord.Source.clear_valid, relationView.getYhsId(), orderDon.getId(), goodsDon.getTitle() + UserBalanceSourceRecord.Source.clear_valid.getDesc(), true);
  191. log.info("车票未到期清除,退款至用户user_id:{}余额:{}成功", userId, re_balance);
  192. //修改订单状态 为退款
  193. orderDon.setStatus(OrderDon.Status.refund);
  194. orderDon.setRefundBalance(re_balance);
  195. orderDon.setRefundMoney(BigDecimal.ZERO);
  196. orderDonMapper.updateById(orderDon);
  197. GoodsDonSku sku = skuMap.get(orderDon.getSkuId());
  198. if (sku == null) {
  199. sku = skuMapper.selectById(orderDon.getSkuId());
  200. if (sku == null) return;
  201. skuMap.putIfAbsent(orderDon.getSkuId(), sku);
  202. }
  203. orderRefundService.refundRecord(orderDon, orderDon.getRefundMoney(), null, goodsDon, sku, StrUtil.EMPTY, "balance");
  204. return;
  205. }
  206. changeTickerRelation(item_groupsId, relationView, source, relationView.getYhsId());
  207. return;
  208. }
  209. //大于10天
  210. //分配到过期账号10天内误差的相同规格车队里
  211. if (skuId.equals(161l)) {
  212. extra_num = 10;
  213. }
  214. DateTime ten_day = DateUtil.offsetDay(expiryTime, 10);
  215. Long item_groupsId = groupsMapper.selectSameSpecItemGroupsByTime(g_groupsId, skuId, expiryTime, ten_day, extra_num);
  216. if (item_groupsId == null) {
  217. //无对应车队 生成空车队
  218. //寻找空车队
  219. item_groupsId = groupsMapper.selectSameSpecEmptyGroups(skuId);
  220. if (item_groupsId == null) {
  221. //新增空车队
  222. GoodsDonSku sku = skuMapper.selectById(skuId);
  223. GroupsRelation new_relation = groupsFuncService.createNewGroupsTrips(sku);
  224. item_groupsId = new_relation.getGroupsId();
  225. }
  226. //新车队
  227. changeTickerRelation(item_groupsId, relationView, UserTicketClearedRecord.Source.new_groups_ticket, relationView.getYhsId());
  228. return;
  229. }
  230. changeTickerRelation(item_groupsId, relationView, source, relationView.getYhsId());
  231. return;
  232. }
  233. });
  234. }
  235. public void changeTickerRelation(Long item_groupsId, GroupsRelationView relationView, UserTicketClearedRecord.Source source, Long yhsId) {
  236. Long change_relationId = relationView.getId();
  237. try {
  238. ChangeRelationReq req = new ChangeRelationReq();
  239. req.setGroupsId(item_groupsId);
  240. req.setRelationId(change_relationId);
  241. req.setSource(source);
  242. req.setIsOutside(true);
  243. req.setYhsId(yhsId);
  244. cmsOrderDonService.changeRelation(req);
  245. } catch (Exception e) {
  246. log.error("更换用户relationId:{}错误:{}", change_relationId, StringUtil.getErrorText(e));
  247. relationView.setErrorMsg(StringUtil.getErrorMsg(e));
  248. changeErrorRecordService.changeTicketErrorRecord(relationView, UserRelationChangeErrorRecord.Source.change);
  249. }
  250. }
  251. }