VipFrontServiceImpl.java 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. package com.cyksj.service.vip.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.ObjectUtil;
  6. import cn.hutool.core.util.StrUtil;
  7. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  8. import com.cyksj.common.constant.Constant;
  9. import com.cyksj.common.exception.BusinessRuntimeException;
  10. import com.cyksj.mapper.*;
  11. import com.cyksj.mapper.sys.SysConfigMapper;
  12. import com.cyksj.mapper.vip.VipGoodsSkuMapper;
  13. import com.cyksj.model.dto.VipDeductDto;
  14. import com.cyksj.model.entity.*;
  15. import com.cyksj.model.manage.views.GroupsRelationView;
  16. import com.cyksj.model.response.VipUserPageResp;
  17. import com.cyksj.model.views.RenewalView;
  18. import com.cyksj.service.chatgpt.ChatGptAccountService;
  19. import com.cyksj.service.claude.ClaudeService;
  20. import com.cyksj.service.user.UserBindRelationService;
  21. import com.cyksj.service.vip.VipFrontService;
  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.*;
  31. import java.util.stream.Collectors;
  32. /**
  33. * 项目名: yhlxj2
  34. * 文件名: VipFrontServiceImpl
  35. * 创建者: JavaZou
  36. * 创建时间:2025/5/15 16:00
  37. */
  38. @Service
  39. @RequiredArgsConstructor
  40. @Slf4j
  41. public class VipFrontServiceImpl implements VipFrontService {
  42. private final SysConfigMapper sysConfigMapper;
  43. private final VipGoodsSkuMapper vipGoodsSkuMapper;
  44. private final UserBindRelationService userBindRelationService;
  45. private final BeanSearcher beanSearcher;
  46. private final GoodsDonSkuMapper skuMapper;
  47. private final ChatgptUserMapper chatgptUserMapper;
  48. private final OrderDonRenewRecordMapper orderDonRenewRecordMapper;
  49. private final ClaudeUserMapper claudeUserMapper;
  50. private final OrderDonMapper orderDonMapper;
  51. private final GoodsDonSkuMapper goodsDonSkuMapper;
  52. private final ChatGptAccountService chatGptAccountService;
  53. private final ClaudeService claudeService;
  54. private final LumaUserMapper lumaUserMapper;
  55. private final UpgradeOrderDonMapper upgradeOrderDonMapper;
  56. private final NanoUserQuotaMapper nanoUserQuotaMapper;
  57. private final MidjourneyUserMapper midjourneyUserMapper;
  58. @Override
  59. public void fillVipInfo(Long userId, VipUserPageResp vipUserPageResp) {
  60. SysConfig sysConfig = sysConfigMapper.selectOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, Constant.VIP_FEE_KEY).last("limit 1"));
  61. if (sysConfig != null && StrUtil.isNotBlank(sysConfig.getSysValue())) {
  62. vipUserPageResp.setVipFee(BigDecimal.valueOf(Integer.parseInt(sysConfig.getSysValue())));
  63. }
  64. if (userId == null) {
  65. return;
  66. }
  67. //可抵扣价格
  68. BigDecimal deductMoney = BigDecimal.ZERO;
  69. List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
  70. List<Long> vipSkuIds = vipGoodsSkuMapper.selectList(null).stream().map(VipGoodsSku::getSkuId).collect(Collectors.toList());
  71. //可有抵扣车票
  72. DateTime now = DateTime.now();
  73. //会员规格
  74. Set<Long> goodsIds = goodsDonSkuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class)
  75. .in(GoodsDonSku::getId, vipSkuIds)).stream().map(GoodsDonSku::getGoodsId).collect(Collectors.toSet());
  76. Number count = beanSearcher.searchCount(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getUserId, userIdList).op(Operator.InList).field(GroupsRelationView::getGoodsId, goodsIds).op(Operator.InList).field(GroupsRelationView::getIsMirror, Boolean.TRUE).field(GroupsRelationView::getExpiryTime, now).op(Operator.GreaterThan).build());
  77. //可抵扣车票
  78. if (count.intValue() > 0) {
  79. Integer months = vipUserPageResp.getMonths();
  80. //处理vip抵扣金额
  81. VipDeductDto vipDeductDto = commonHandleVipDeductMoney(userIdList, goodsIds, months);
  82. vipUserPageResp.setRelationUserViews(vipDeductDto.getRelationUserViews());
  83. vipUserPageResp.setExtendsDays(vipDeductDto.getExtendsDays());
  84. if (months != 12) {
  85. //取出最大可抵扣info
  86. vipDeductDto = commonHandleVipDeductMoney(userIdList, goodsIds, 12);
  87. }
  88. deductMoney = vipDeductDto.getDeductMoney();
  89. }
  90. vipUserPageResp.setDeductMoney(deductMoney);
  91. }
  92. /**
  93. * 检查用户并获取订单抵扣金额
  94. */
  95. @Override
  96. public VipDeductDto checkAndGetOrderDeductMoney(Long userId, Integer months) {
  97. List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
  98. List<Long> vipSkuIds = vipGoodsSkuMapper.selectList(null).stream().map(VipGoodsSku::getSkuId).collect(Collectors.toList());
  99. //会员规格
  100. Set<Long> goodsIds = goodsDonSkuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class)
  101. .in(GoodsDonSku::getId, vipSkuIds)).stream().map(GoodsDonSku::getGoodsId).collect(Collectors.toSet());
  102. Number count = beanSearcher.searchCount(GroupsRelationView.class, MapUtils.builder()
  103. .field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
  104. .field(GroupsRelationView::getGoodsId, goodsIds).op(Operator.InList)
  105. .field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
  106. .field(GroupsRelationView::getIsVip, false)
  107. .build());
  108. if (count.intValue() == 0) {
  109. throw BusinessRuntimeException.getInstance("暂无可抵扣AI车票");
  110. }
  111. VipDeductDto vipDeductDto = commonHandleVipDeductMoney(userIdList, goodsIds, months);
  112. return vipDeductDto;
  113. }
  114. private BigDecimal getVipMoney(Integer months) {
  115. SysConfig sysConfig = sysConfigMapper.selectOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, Constant.VIP_FEE_KEY).last("limit 1"));
  116. if (sysConfig == null || StrUtil.isEmpty(sysConfig.getSysValue())) {
  117. throw BusinessRuntimeException.getInstance("系统异常");
  118. }
  119. BigDecimal vipFee = BigDecimal.valueOf(Long.valueOf(sysConfig.getSysValue()));
  120. return vipFee.multiply(BigDecimal.valueOf(months));
  121. }
  122. /**
  123. * 统一处理vip抵扣金额
  124. */
  125. public VipDeductDto commonHandleVipDeductMoney(List<Long> userIdList, Set<Long> goodsIds, Integer months) {
  126. VipDeductDto vipDeductDto = new VipDeductDto();
  127. DateTime now = DateTime.now();
  128. List<Long> deductRelationIds = new ArrayList<>();
  129. BigDecimal deductMoney = BigDecimal.ZERO;
  130. BigDecimal vipMoney = getVipMoney(months);
  131. List<GroupsRelationView> relations = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
  132. .field(GroupsRelationView::getGoodsId, goodsIds).op(Operator.InList)
  133. .field(GroupsRelationView::getIsMirror, Boolean.TRUE)
  134. .field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
  135. .field(GroupsRelationView::getIsVip, false)
  136. .field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
  137. .field(GroupsRelationView::getAqType, 1)
  138. .orderBy(GroupsRelationView::getExpiryTime).desc()
  139. .build());
  140. Set<Long> deductGoodsIds = null;
  141. List<GroupsRelationView> deductRelations = null;
  142. for (GroupsRelationView relation : relations) {
  143. if (deductGoodsIds == null) {
  144. deductGoodsIds = new HashSet<>();
  145. }
  146. if (deductRelations == null) {
  147. deductRelations = new ArrayList<>();
  148. }
  149. Long goodsId = relation.getGoodsId();
  150. if (deductGoodsIds.contains(goodsId)) {
  151. continue;
  152. }
  153. if (goodsId == Constant.NANO_GOODS_ID) {
  154. NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class).in(NanoUserQuota::getUid, userIdList).orderByDesc(NanoUserQuota::getRemainingQuota).last("limit 1"));
  155. if (nanoUserQuota != null) {
  156. if (!ObjectUtil.equal(nanoUserQuota.getRelationId(), relation.getId())) {
  157. continue;
  158. }
  159. } else {
  160. //规格最高
  161. RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder()
  162. .field(RenewalView::getGoodsId, goodsId)
  163. .field(RenewalView::getUserId, userIdList).op(Operator.InList)
  164. .orderBy(RenewalView::getSkuNanoQuota).desc()
  165. .onlySelect(RenewalView::getRelationId)
  166. .build());
  167. if (renewalView != null && !ObjectUtil.equal(renewalView.getRelationId(), relation.getId())) {
  168. continue;
  169. }
  170. }
  171. }
  172. Long skuId = relation.getSkuId();
  173. deductGoodsIds.add(goodsId);
  174. Long relationId = relation.getId();
  175. Date relationExpiryTime = relation.getExpiryTime();
  176. //GPT
  177. if (goodsId == Constant.GPT_PLUS_GID) {
  178. ChatgptUser chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId).last("limit 1"));
  179. if (chatgptUser == null) {
  180. chatGptAccountService.getUserInfo(relation.getUserId(), relation.getId());
  181. chatgptUser = chatgptUserMapper.selectOne(Wrappers.lambdaQuery(ChatgptUser.class).eq(ChatgptUser::getRelationId, relationId).last("limit 1"));
  182. }
  183. if (chatgptUser != null) {
  184. //获取抵扣金额
  185. deductMoney = deductMoney.add(getFinalDeductMoney(relationId, relation.getSkuId(), chatgptUser.getRenewSkuId(), chatgptUser.getRenewOrderId(), chatgptUser.getRenewExpiryTime(), relation.getStartTime(), relationExpiryTime, now, userIdList));
  186. }
  187. } else if (goodsId == Constant.CLAUDE_PRO_GID) {
  188. ClaudeUser claudeUser = claudeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeUser.class).eq(ClaudeUser::getRelationId, relationId).last("limit 1"));
  189. if (claudeUser == null) {
  190. claudeService.getUserInfo(relation.getUserId(), relation.getId());
  191. claudeUser = claudeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeUser.class).eq(ClaudeUser::getRelationId, relationId).last("limit 1"));
  192. }
  193. if (claudeUser != null) {
  194. //获取抵扣金额
  195. deductMoney = deductMoney.add(getFinalDeductMoney(relationId, relation.getSkuId(), claudeUser.getRenewSkuId(), claudeUser.getRenewOrderId(), claudeUser.getRenewExpiryTime(), relation.getStartTime(), relationExpiryTime, now, userIdList));
  196. }
  197. } else if (goodsId == Constant.LUMA_GOODS_ID || goodsId == Constant.NANO_GOODS_ID) {
  198. //luma、nano
  199. deductMoney = deductMoney.add(getGeneralRemainNumDeductMoney(relationId, goodsId, skuId, userIdList, relation.getStartTime()));
  200. } else if (goodsId == Constant.MIDJOURNEY_GOODS_ID) {
  201. //mj
  202. deductMoney = deductMoney.add(getMjRemainNumDeductMoney(relationId, skuId, userIdList, relation.getStartTime(), relation.getExpiryTime()));
  203. } else {
  204. //该车票抵扣金额
  205. deductMoney = deductMoney.add(getDeductMoneyFromTicket(relationId, userIdList, skuId, now, relation.getStartTime(), relationExpiryTime));
  206. }
  207. deductRelationIds.add(relationId);
  208. //可抵扣车票
  209. deductRelations.add(relation);
  210. }
  211. //实际可抵扣金额
  212. vipDeductDto.setActuallyDeDuctMoney(deductMoney);
  213. vipDeductDto.setDeductMoney(deductMoney);
  214. //超出可抵扣的金额 直接返回
  215. if (deductMoney.compareTo(vipMoney) >= 0) {
  216. BigDecimal overMoney = deductMoney.subtract(vipMoney);
  217. //超过抵扣金额可换延长会员多少天
  218. //每天单价
  219. BigDecimal daySingle = vipMoney.divide(BigDecimal.valueOf(months)).divide(BigDecimal.valueOf(30), 0, RoundingMode.DOWN);
  220. //超出部分可换取多少天 低于每天单价为0天
  221. BigDecimal extendsDays = overMoney.divide(daySingle, 0, RoundingMode.UP);
  222. vipDeductDto.setExtendsDays(extendsDays.intValue());
  223. vipDeductDto.setDeductMoney(vipMoney);
  224. }
  225. vipDeductDto.setDeductRelationIds(deductRelationIds);
  226. vipDeductDto.setRelationUserViews(deductRelations);
  227. return vipDeductDto;
  228. }
  229. /**
  230. * 获取最终抵扣金额
  231. */
  232. public BigDecimal getFinalDeductMoney(Long relationId, Long relationSkuId, Long renewSkuId, Long renewOrderId, Date renewExpiryTime, Date relationStartTime, Date relationExpiryTime, DateTime now, List<Long> userIdList) {
  233. BigDecimal deductMoney = BigDecimal.ZERO;
  234. //一个月当30天算单价 往上取整
  235. //续费规格
  236. if (renewSkuId != null && renewExpiryTime.compareTo(now) > 0) {
  237. OrderDon renewOrderDon = orderDonMapper.selectById(renewOrderId);
  238. BigDecimal orderMoney = renewOrderDon.getMoney().add(Optional.ofNullable(renewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
  239. GoodsDonSku presentSku = skuMapper.selectById(renewSkuId);
  240. if (orderMoney.compareTo(BigDecimal.ZERO) == 0) {
  241. orderMoney = presentSku.getPrice();
  242. }
  243. Long betweenDay = DateUtil.betweenDay(now, renewExpiryTime, false) + 1;
  244. //当天购买的按规格原价抵扣
  245. BigDecimal renewDeductMoney;
  246. if (now.toDateStr().equals(DateUtil.format(renewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
  247. renewDeductMoney = orderMoney;
  248. deductMoney = deductMoney.add(renewDeductMoney);
  249. if (presentSku.getDays() != null) {
  250. relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -presentSku.getDays());
  251. } else {
  252. relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -presentSku.getMonths());
  253. }
  254. } else {
  255. //此次续费规格单价
  256. BigDecimal single = getPayOrderSingle(orderMoney, presentSku);
  257. //该车票抵扣金额
  258. renewDeductMoney = single.multiply(BigDecimal.valueOf(betweenDay));
  259. log.info("车票id:{}目前续费升级规格可抵扣的金额为:{}", relationId, renewDeductMoney);
  260. deductMoney = deductMoney.add(renewDeductMoney);
  261. relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -betweenDay.intValue());
  262. }
  263. //上一个续费升级规格
  264. List<OrderDon> orderDOns = orderDonRenewRecordMapper.getOtherRenewSkus(renewOrderId, relationId, userIdList);
  265. OrderDon presentRenewOrderDon = renewOrderDon;
  266. for (OrderDon thisRenewOrderDon : orderDOns) {
  267. Long skuId = thisRenewOrderDon.getSkuId();
  268. GoodsDonSku thisRenewSku = skuMapper.selectById(skuId);
  269. BigDecimal thisOrderMoney = thisRenewOrderDon.getMoney().add(Optional.ofNullable(thisRenewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
  270. if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
  271. thisOrderMoney = thisRenewSku.getPrice();
  272. }
  273. //当天购买的按规格原价抵扣
  274. BigDecimal thisRenewDeductMoney = BigDecimal.ZERO;
  275. if (now.toDateStr().equals(DateUtil.format(thisRenewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
  276. thisRenewDeductMoney = thisOrderMoney;
  277. deductMoney = deductMoney.add(thisRenewDeductMoney);
  278. if (thisRenewSku.getDays() != null) {
  279. relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisRenewSku.getDays());
  280. } else {
  281. relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -thisRenewSku.getMonths());
  282. }
  283. } else {
  284. //此次续费订单过期时间
  285. Date thisOrderExpiryTime;
  286. if (thisRenewSku.getDays() != null) {
  287. thisOrderExpiryTime = DateUtil.offsetDay(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getDays());
  288. } else {
  289. thisOrderExpiryTime = DateUtil.offsetMonth(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getMonths());
  290. }
  291. //续费同规格不处理
  292. if (!ObjectUtil.equal(thisRenewOrderDon.getSkuId(), presentRenewOrderDon.getSkuId())) {
  293. //先扣除已使用的天数
  294. //相差多少天
  295. Long thisRenewBetDay = DateUtil.betweenDay(thisRenewOrderDon.getCreatedTime(), presentRenewOrderDon.getCreatedTime(), false);
  296. //扣除已使用的
  297. thisOrderExpiryTime = DateUtil.offsetDay(thisOrderExpiryTime, -thisRenewBetDay.intValue());
  298. }
  299. //此订单过期时间
  300. if (thisOrderExpiryTime.compareTo(now) > 0) {
  301. //距离过期还剩多少天
  302. Long thisDeductBetweenDay = DateUtil.betweenDay(now, thisOrderExpiryTime, false) + 1;
  303. if (thisDeductBetweenDay != 0) {
  304. //此次续费规格单价
  305. BigDecimal single = getPayOrderSingle(thisOrderMoney, thisRenewSku);
  306. //该车票抵扣金额
  307. thisRenewDeductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
  308. deductMoney = deductMoney.add(thisRenewDeductMoney);
  309. }
  310. //目前级别续费订单
  311. presentRenewOrderDon = thisRenewOrderDon;
  312. relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisDeductBetweenDay.intValue());
  313. }
  314. }
  315. log.info("车票id:{}目前次一级规格:{}可抵扣的金额为:{}", relationId, thisRenewSku.getSpecVal(), thisRenewDeductMoney);
  316. }
  317. }
  318. if (relationExpiryTime.after(now)) {
  319. //该车票抵扣金额
  320. BigDecimal deductMoneyFromTicket = getDeductMoneyFromTicket(relationId, userIdList, relationSkuId, now, relationStartTime, relationExpiryTime);
  321. deductMoney = deductMoney.add(deductMoneyFromTicket);
  322. }
  323. log.info("车票id:{}最终到期时间为:{}车票可返回 抵扣金额:{}", relationId, DateUtil.format(relationExpiryTime, "yyyy-MM-dd HH:mm:ss"), deductMoney);
  324. return deductMoney;
  325. }
  326. /**
  327. * 获取车票可抵扣金额
  328. */
  329. public BigDecimal getDeductMoneyFromTicket(Long relationId, List<Long> userIdList, Long skuId, DateTime now, Date relationStartTime, Date relationExpiryTime) {
  330. List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
  331. .eq(OrderDon::getRelationId, relationId)
  332. .in(OrderDon::getUserId, userIdList)
  333. .eq(OrderDon::getSkuId, skuId)
  334. .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
  335. .orderByDesc(OrderDon::getId));
  336. //部分退款
  337. if (orderDonList.isEmpty()) {
  338. orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
  339. .eq(OrderDon::getRelationId, relationId)
  340. .in(OrderDon::getUserId, userIdList)
  341. .eq(OrderDon::getSkuId, skuId)
  342. .notIn(OrderDon::getStatus, Constant.noOrderStatus)
  343. .orderByDesc(OrderDon::getId));
  344. }
  345. //原车票订单总实付金额
  346. BigDecimal totalOrderMoney = BigDecimal.ZERO;
  347. //原车票订单总天数
  348. Integer totalDays = 0;
  349. for (OrderDon orderDon : orderDonList) {
  350. GoodsDonSku sku = skuMapper.selectById(skuId);
  351. BigDecimal thisOrderMoney = orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)).subtract(Optional.ofNullable(orderDon.getRefundMoney()).orElse(BigDecimal.ZERO));
  352. if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
  353. thisOrderMoney = sku.getPrice();
  354. }
  355. totalOrderMoney = totalOrderMoney.add(thisOrderMoney);
  356. //总时间
  357. if (sku.getDays() != null) {
  358. totalDays += sku.getDays();
  359. } else {
  360. totalDays += sku.getMonths() * 30;
  361. }
  362. //原订单数
  363. if (orderDonList.size() == 1) {
  364. //此次订单过期时间
  365. Date thisOrderExpiryTime;
  366. if (sku.getDays() != null) {
  367. thisOrderExpiryTime = DateUtil.offsetDay(orderDon.getCreatedTime(), sku.getDays());
  368. } else {
  369. thisOrderExpiryTime = DateUtil.offsetMonth(orderDon.getCreatedTime(), sku.getMonths());
  370. }
  371. //当天购买的按规格原价抵扣
  372. if (now.toDateStr().equals(DateUtil.format(relationStartTime, "yyyy-MM-dd")) && (DateUtil.betweenDay(thisOrderExpiryTime, relationExpiryTime, true) == 0)) {
  373. return thisOrderMoney;
  374. }
  375. }
  376. }
  377. Long thisDeductBetweenDay = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
  378. BigDecimal single = totalOrderMoney.divide(BigDecimal.valueOf(totalDays), 0, RoundingMode.HALF_UP);
  379. //该车票抵扣金额
  380. BigDecimal deductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
  381. return deductMoney;
  382. }
  383. /**
  384. * 获取订单单价
  385. */
  386. public BigDecimal getPayOrderSingle(BigDecimal orderMoney, GoodsDonSku sku) {
  387. //此次续费规格单价
  388. BigDecimal single;
  389. //区分天/月
  390. if (sku.getDays() != null) {
  391. single = orderMoney.divide(BigDecimal.valueOf(sku.getDays()), 0, RoundingMode.HALF_UP);
  392. } else {
  393. single = orderMoney.divide(BigDecimal.valueOf(sku.getMonths()).multiply(BigDecimal.valueOf(30)), 0, RoundingMode.HALF_UP);
  394. }
  395. return single;
  396. }
  397. /**
  398. * 获取普通剩余次数可抵扣金额
  399. */
  400. private BigDecimal getGeneralRemainNumDeductMoney(Long relationId, Long goodsId, Long skuId, List<Long> userIdList, Date relationStartTime) {
  401. BigDecimal deductMoney = BigDecimal.ZERO;
  402. BigDecimal orderTotalMoney = BigDecimal.ZERO;
  403. //总次数
  404. Integer totalNum = 0;
  405. DateTime now = DateTime.now();
  406. List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getRelationId, relationId).in(OrderDon::getUserId, userIdList).notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
  407. for (OrderDon orderDon : orderDonList) {
  408. GoodsDonSku sku = skuMapper.selectById(skuId);
  409. Date orderCreatedTime = orderDon.getCreatedTime();
  410. Integer months = sku.getMonths();
  411. Integer days = sku.getDays();
  412. Date orderExpiryTime;
  413. if (days != null) {
  414. orderExpiryTime = DateUtil.offsetDay(orderCreatedTime, days);
  415. } else {
  416. orderExpiryTime = DateUtil.offsetMonth(orderCreatedTime, months);
  417. }
  418. //过期的订单不算入
  419. if (orderExpiryTime.before(now)) {
  420. continue;
  421. }
  422. if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) {
  423. orderTotalMoney = orderTotalMoney.add(orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)));
  424. } else {
  425. //兑换码订单使用规格价格
  426. orderTotalMoney = orderTotalMoney.add(sku.getPrice());
  427. }
  428. if (goodsId == Constant.LUMA_GOODS_ID) {
  429. totalNum += sku.getLumaNum();
  430. } else {
  431. totalNum += sku.getNanoQuota();
  432. }
  433. }
  434. //加量包订单
  435. List<UpgradeOrderDon> upgradeOrderDons = upgradeOrderDonMapper.selectList(Wrappers.lambdaQuery(UpgradeOrderDon.class).eq(UpgradeOrderDon::getRelationId, relationId).in(UpgradeOrderDon::getUserId, userIdList).notIn(UpgradeOrderDon::getStatus, Constant.noOrderAllStatus).gt(UpgradeOrderDon::getCreatedTime, relationStartTime));
  436. for (UpgradeOrderDon upgradeOrderDon : upgradeOrderDons) {
  437. orderTotalMoney = orderTotalMoney.add(upgradeOrderDon.getMoney().add(Optional.ofNullable(upgradeOrderDon.getBalance()).orElse(BigDecimal.ZERO)));
  438. totalNum = totalNum + upgradeOrderDon.getNum();
  439. }
  440. Integer remainNum = null;
  441. if (goodsId == Constant.LUMA_GOODS_ID) {
  442. LumaUser lumaUser = lumaUserMapper.selectOne(Wrappers.lambdaQuery(LumaUser.class).eq(LumaUser::getRelationId, relationId).last("limit 1"));
  443. if (lumaUser != null) {
  444. remainNum = lumaUser.getNum();
  445. }
  446. } else {
  447. NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class).eq(NanoUserQuota::getRelationId, relationId).last("limit 1"));
  448. if (nanoUserQuota != null) {
  449. remainNum = nanoUserQuota.getRemainingQuota();
  450. }
  451. }
  452. //若未使用
  453. if (remainNum == null) {
  454. deductMoney = deductMoney.add(orderTotalMoney);
  455. } else {
  456. BigDecimal remainMoney = BigDecimal.valueOf(remainNum).divide(BigDecimal.valueOf(totalNum), 2, RoundingMode.DOWN).multiply(orderTotalMoney);
  457. deductMoney = deductMoney.add(remainMoney);
  458. }
  459. return deductMoney;
  460. }
  461. /**
  462. * 获取mj剩余次数可抵扣金额
  463. */
  464. private BigDecimal getMjRemainNumDeductMoney(Long relationId, Long skuId, List<Long> userIdList, Date relationStartTime, Date relationExpiryTime) {
  465. BigDecimal deductMoney = BigDecimal.ZERO;
  466. BigDecimal orderTotalMoney = BigDecimal.ZERO;
  467. //总次数
  468. Integer totalNum = null;
  469. //原车票订单总天数
  470. Integer totalDays = 0;
  471. DateTime now = DateTime.now();
  472. List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getRelationId, relationId).in(OrderDon::getUserId, userIdList).notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
  473. for (OrderDon orderDon : orderDonList) {
  474. GoodsDonSku sku = skuMapper.selectById(skuId);
  475. Date orderCreatedTime = orderDon.getCreatedTime();
  476. Integer months = sku.getMonths();
  477. Integer days = sku.getDays();
  478. //订单过期时间
  479. Date orderExpiryTime;
  480. if (days != null) {
  481. orderExpiryTime = DateUtil.offsetDay(orderCreatedTime, days);
  482. } else {
  483. orderExpiryTime = DateUtil.offsetMonth(orderCreatedTime, months);
  484. }
  485. //总时间
  486. totalDays += sku.getMonths() * 30;
  487. //过期的订单不算入
  488. if (orderExpiryTime.before(now)) {
  489. continue;
  490. }
  491. if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) {
  492. orderTotalMoney = orderTotalMoney.add(orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)));
  493. } else {
  494. //兑换码订单使用规格价格
  495. orderTotalMoney = orderTotalMoney.add(sku.getPrice());
  496. }
  497. if (totalNum == null) {
  498. totalNum = sku.getMjFastNum() + sku.getMjRelaxNum();
  499. }
  500. }
  501. Integer upgradeNum = 0;
  502. BigDecimal upgradeOrderMoney = BigDecimal.ZERO;
  503. //加量包订单
  504. List<UpgradeOrderDon> upgradeOrderDons = upgradeOrderDonMapper.selectList(Wrappers.lambdaQuery(UpgradeOrderDon.class).eq(UpgradeOrderDon::getRelationId, relationId).in(UpgradeOrderDon::getUserId, userIdList).notIn(UpgradeOrderDon::getStatus, Constant.noOrderAllStatus).gt(UpgradeOrderDon::getCreatedTime, relationStartTime));
  505. for (UpgradeOrderDon upgradeOrderDon : upgradeOrderDons) {
  506. upgradeNum += upgradeOrderDon.getNum();
  507. upgradeOrderMoney = upgradeOrderMoney.add(upgradeOrderDon.getMoney().add(Optional.ofNullable(upgradeOrderDon.getBalance()).orElse(BigDecimal.ZERO)));
  508. }
  509. MidjourneyUser midjourneyUser = midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class).eq(MidjourneyUser::getRelationId, relationId).last("limit 1"));
  510. if (midjourneyUser == null) {
  511. deductMoney = deductMoney.add(orderTotalMoney).add(upgradeOrderMoney);
  512. } else {
  513. if (CollUtil.isNotEmpty(orderDonList)) {
  514. Integer remainFastNum = midjourneyUser.getMjFastNum();
  515. Integer remainRelaxNum = midjourneyUser.getMjRelaxNum();
  516. Integer usedNum = totalNum - remainFastNum - remainRelaxNum;
  517. if (usedNum == 0 && now.toDateStr().equals(DateUtil.format(relationStartTime, "yyyy-MM-dd"))) {
  518. deductMoney = deductMoney.add(orderTotalMoney);
  519. } else {
  520. //每天单价
  521. BigDecimal single = orderTotalMoney.divide(BigDecimal.valueOf(totalDays), 0, RoundingMode.HALF_UP);
  522. BigDecimal consumeRate = BigDecimal.valueOf(usedNum).divide(BigDecimal.valueOf(totalNum), 2, RoundingMode.DOWN);
  523. //消耗的次数当月 值多少钱
  524. BigDecimal consumeMoney = consumeRate.multiply(single.multiply(BigDecimal.valueOf(30)));
  525. //该车票多长时间
  526. Long thisDeductBetweenDay = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
  527. //该车票抵扣金额
  528. BigDecimal orderRemainMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
  529. //最终可抵扣
  530. deductMoney = deductMoney.add(orderRemainMoney.subtract(consumeMoney));
  531. }
  532. }
  533. //加量包
  534. Integer remainUpgradeNum = midjourneyUser.getMjUpgradeNum();
  535. if (CollUtil.isNotEmpty(upgradeOrderDons)) {
  536. BigDecimal upgradeMoney = BigDecimal.valueOf(remainUpgradeNum).divide(BigDecimal.valueOf(upgradeNum), 2, RoundingMode.DOWN).multiply(upgradeOrderMoney);
  537. deductMoney = deductMoney.add(upgradeMoney);
  538. }
  539. }
  540. return deductMoney;
  541. }
  542. }