Pārlūkot izejas kodu

luma、nano、mj会员抵扣金额

zoujiajian 11 mēneši atpakaļ
vecāks
revīzija
5319405ad8

+ 5 - 0
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -413,6 +413,11 @@ public interface Constant {
 
 	Long HBO_GO_GOODS_ID = 8L;
 
+	/**
+	 * midjourney
+	 */
+	Long MIDJOURNEY_GOODS_ID = 26l;
+
 	/**
 	 * 批发押金配置key
 	 */

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GoodsDonCategoryRelateMapper.java

@@ -18,4 +18,6 @@ public interface GoodsDonCategoryRelateMapper extends BaseMapper<GoodsDonCategor
 	List<GoodsDonCategory> getCateGoryViewByGoodsId(Long goodsId);
 
 	void saveBatchGoodsRelate(@Param("goodsId") Long goodsId, @Param("list") List<Long> categoryList);
+
+	List<Long> selectCategoryIdsByGid(Long goodsId);
 }

+ 8 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java

@@ -169,6 +169,14 @@ public class GroupsRelation extends BaseEntity {
      */
     private Boolean isVip;
 
+
+    /**
+     * 是否是claude code 续费
+     */
+    @DbIgnore
+    @TableField(exist = false)
+    private Boolean isClaudeCodeRenew;
+
     /**
      * 是否是claude code 续费升级
      */

+ 2 - 2
netflix-dao/src/main/java/com/cyksj/model/manage/views/GroupsRelationView.java

@@ -18,8 +18,8 @@ import java.util.Date;
 @Setter
 @SearchBean(tables = "groups_relation gr left join groups_trips gt on gr.groups_id = gt.id " +
         "left join account a on a.id = gt.account_id left join user u on gr.user_id = u.id " +
-        "left join goods_don g on a.goods_id = g.id " +
-        "left join goods_don_sku sku on sku.id = gt.sku_id")
+        "left join goods_don_sku sku on sku.id = gt.sku_id " +
+        "left join goods_don g on g.id = sku.goods_id")
 public class GroupsRelationView {
 
     @DbField("gr.id")

+ 12 - 0
netflix-dao/src/main/java/com/cyksj/model/views/RenewalView.java

@@ -262,6 +262,12 @@ public class RenewalView {
     @DbIgnore
     private Integer codeNum;
 
+    /**
+     * nano次数
+     */
+    @DbField("sku.nano_quota")
+    private Boolean skuNanoQuota;
+
     /**
      * 是否为镜像服务
      */
@@ -345,6 +351,12 @@ public class RenewalView {
     @DbField("a.act_code")
     private String actCode;
 
+    /**
+     * 分类id
+     */
+    @DbIgnore
+    private List<Long> categoryIdList;
+
     /**
      * mj 套餐包最低单价
      */

+ 4 - 0
netflix-dao/src/main/resources/mapper/GoodsDonCategoryRelateMapper.xml

@@ -16,4 +16,8 @@
         select gc.* from goods_don_category gc left join goods_don_category_relate gcr on gcr.category = gc.id
         where gcr.goods_id = #{goodsId}
     </select>
+
+    <select id="selectCategoryIdsByGid" resultType="java.lang.Long">
+        select distinct category from goods_don_category_relate where goods_id = #{goodsId}
+    </select>
 </mapper>

+ 27 - 16
netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java

@@ -391,11 +391,14 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 			orderDonMapper.insert(orderDon);
 			log.info("用户{}兑换规格:{}车位成功", user.getId(), orderDon.getSkuId());
 
-			if (relation.getIsClaudeCodeUpgrade() != null && relation.getIsClaudeCodeUpgrade()) {
-				//claude code 是否升级
+			if (relation.getIsClaudeCodeRenew() != null && relation.getIsClaudeCodeRenew()) {
+				//claude code续费
 				orderDon.setOrderType(2);
 				orderDonMapper.updateById(orderDon);
-				claudeCodeService.handleClaudeCodeUserPackageSku(relation, sku, orderDon.getId());
+				//续费且升级
+				if (relation.getIsClaudeCodeUpgrade() != null && relation.getIsClaudeCodeUpgrade()) {
+					claudeCodeService.handleClaudeCodeUserPackageSku(relation, sku, orderDon.getId());
+				}
 			}
 		}
 		if (orderDonTye == OrderDon.Type.EX_CODE) {
@@ -424,23 +427,31 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 
 	@Override
 	public GroupsRelation getRelationNoOrder(GoodsDonSku sku, Long userId, Long yhsId) {
-		//claude code商品兑换 只能兑换一次 后续兑换增加车票时长
+		//claude code商品兑换
 		if (sku.getGoodsId() == Constant.CLAUDE_CODE_GOODS_ID) {
 			List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
 			GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getUserId, userIdList).op(Operator.InList).field(GroupsRelationView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan).build());
 			if (groupsRelationView != null) {
-//				Date expiryTime = groupsRelationView.getExpiryTime();
-//				if (sku.getDays() != null) {
-//					expiryTime = DateUtil.offsetDay(expiryTime, sku.getDays());
-//				} else {
-//					expiryTime = DateUtil.offsetMonth(expiryTime, sku.getMonths());
-//				}
-//				GroupsRelation relation = groupsRelationMapper.selectById(groupsRelationView.getId());
-//				relation.setExpiryTime(expiryTime);
-//				groupsRelationMapper.updateById(relation);
-//				relation.setIsClaudeCodeUpgrade(true);
-//				return relation;
-				throw BusinessRuntimeException.getInstance("您当前已有车票,暂时无法兑换");
+				GoodsDonSku relationSku = goodsDonSkuMapper.selectById(groupsRelationView.getSkuId());
+				//兑换的规格 低于当前规格 不让兑换
+				if (relationSku.getCodePoints() > sku.getCodePoints()) {
+					throw BusinessRuntimeException.getInstance("请在claude code当前版本过期后再兑换");
+				}
+				Date expiryTime = groupsRelationView.getExpiryTime();
+				if (sku.getDays() != null) {
+					expiryTime = DateUtil.offsetDay(expiryTime, sku.getDays());
+				} else {
+					expiryTime = DateUtil.offsetMonth(expiryTime, sku.getMonths());
+				}
+				GroupsRelation relation = groupsRelationMapper.selectById(groupsRelationView.getId());
+				relation.setExpiryTime(expiryTime);
+				groupsRelationMapper.updateById(relation);
+				//同规格只加时长
+				relation.setIsClaudeCodeRenew(Boolean.TRUE);
+				if (relationSku.getCodePoints() != sku.getCodePoints()) {
+					relation.setIsClaudeCodeUpgrade(true);
+				}
+				return relation;
 			}
 		}
 		Integer retryNum = 1;

+ 4 - 1
netflix-service/src/main/java/com/cyksj/service/mange/impl/MirrorUserCleatServiceImpl.java

@@ -183,7 +183,10 @@ public class MirrorUserCleatServiceImpl implements MirrorUserCleatService {
 						renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), otherRenewSku.getMonths());
 					}
 					//相差多少天
-					Long betDay = DateUtil.betweenDay(otherRenewRecord.getCreatedTime(), presentRenewOrderDon.getCreatedTime(), false);
+					Long betDay = 0l;
+					if (presentRenewOrderDon != null && presentRenewOrderDon.getCreatedTime().compareTo(otherRenewRecord.getCreatedTime()) > 0) {
+						betDay = DateUtil.betweenDay(otherRenewRecord.getCreatedTime(), presentRenewOrderDon.getCreatedTime(), false);
+					}
 					renewExpiryTime = DateUtil.offsetDay(renewExpiryTime, -betDay.intValue());
 
 					claudeCodeUser.setRenewOrderId(otherRenewRecord.getOrderId());

+ 19 - 15
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -2097,22 +2097,26 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 //							}
 						}
 					}
-					distributeWaitingSendPointsMapper.insert(distributeWaitingSendPoints);
-					//暂定虚物 商务可首单提成
-					if (businessId != null) {
-						//给商务人员 分配提成权益
-						userBusinessFrontService.taskDistributeRateBenefits(userDistributeShared.getSharedId(), businessId, goodsDon.getType(), order, rate);
-					}
-					//是否是cc普通推广
-					//并且购买claude code作为首单
-					if (userDistribute == null && Constant.CC_DISTRIBUTE_MARK.equals(userDistributeShared.getRemark()) && order.getGoodsId() == Constant.CLAUDE_CODE_GOODS_ID) {
-						//普通推广用户首单,给上级渠道发放 claude code 积分卡
-						try {
-							claudeCodeService.adjUserRestNum(order.getId(), userDistributeShared.getSharedId(), 1, "新用户下单");
-							log.info("用户{}邀请新用户{}首单,发放claude code积分卡成功", userDistributeShared.getSharedId(), order.getUserId());
-						} catch (Exception e) {
-							log.error("给用户{}发放claude code积分卡失败:{}", userDistributeShared.getSharedId(), e.getMessage());
+					try {
+						distributeWaitingSendPointsMapper.insert(distributeWaitingSendPoints);
+						//暂定虚物 商务可首单提成
+						if (businessId != null) {
+							//给商务人员 分配提成权益
+							userBusinessFrontService.taskDistributeRateBenefits(userDistributeShared.getSharedId(), businessId, goodsDon.getType(), order, rate);
 						}
+						//是否是cc普通推广
+						//并且购买claude code作为首单
+						if (userDistribute == null && Constant.CC_DISTRIBUTE_MARK.equals(userDistributeShared.getRemark()) && order.getGoodsId() == Constant.CLAUDE_CODE_GOODS_ID) {
+							//普通推广用户首单,给上级渠道发放 claude code 积分卡
+							try {
+								claudeCodeService.adjUserRestNum(order.getId(), userDistributeShared.getSharedId(), 1, "新用户下单");
+								log.info("用户{}邀请新用户{}首单,发放claude code积分卡成功", userDistributeShared.getSharedId(), order.getUserId());
+							} catch (Exception e) {
+								log.error("给用户{}发放claude code积分卡失败:{}", userDistributeShared.getSharedId(), e.getMessage());
+							}
+						}
+					} catch (DuplicateKeyException e) {
+
 					}
 				}
 			}

+ 18 - 2
netflix-service/src/main/java/com/cyksj/service/order/impl/VipOrderDonServiceImpl.java

@@ -536,7 +536,7 @@ public class VipOrderDonServiceImpl extends ServiceImpl<VipOrderDonMapper, VipOr
 				//抵扣规格
 				deductSkuIds.add(vipSkuId);
 				//重置镜像user
-				resetMirrorUser(goodsId, vipSkuId, relationId, newRelationId, vipExpiryTime);
+				resetMirrorUser(goodsId, vipSkuId, relationId, newRelationId, vipExpiryTime, num);
 			}
 		}
 		for (VipGoodsSku sku : skus) {
@@ -733,7 +733,7 @@ public class VipOrderDonServiceImpl extends ServiceImpl<VipOrderDonMapper, VipOr
 	/**
 	 * 重置镜像user
 	 */
-	private void resetMirrorUser(Long goodsId, Long skuId, Long oldRelationId, Long newRelationId, Date vipExpiryTime) {
+	private void resetMirrorUser(Long goodsId, Long skuId, Long oldRelationId, Long newRelationId, Date vipExpiryTime, Integer payNum) {
 		GoodsDonSku sku = skuMapper.selectById(skuId);
 		if (goodsId == Constant.MJ_GID) {
 			MidjourneyUser user = midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class)
@@ -823,6 +823,22 @@ public class VipOrderDonServiceImpl extends ServiceImpl<VipOrderDonMapper, VipOr
 				redisService.del(RedisService.key.LUMA_NUM_LIMIT.getName() + lumaUser.getId());
 			}
 		}
+
+		//nano 抵扣
+		if (goodsId == Constant.NANO_GOODS_ID) {
+			NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class)
+					.eq(NanoUserQuota::getRelationId, oldRelationId)
+					.last("limit 1"));
+			if (nanoUserQuota != null) {
+				//payNum 会员月数
+				nanoUserQuota.setTotalQuota(sku.getNanoQuota() * payNum);
+				nanoUserQuota.setRemainingQuota(nanoUserQuota.getTotalQuota());
+				nanoUserQuota.setUsedQuota(0);
+				nanoUserQuota.setPurchaseDate(DateTime.now());
+				nanoUserQuota.setRelationId(newRelationId);
+				nanoUserQuotaMapper.updateById(nanoUserQuota);
+			}
+		}
 	}
 
 	/**

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java

@@ -148,7 +148,7 @@ public class GroupRelationClearServiceImpl implements GroupRelationClearService
 					oAuthTokenMapper.delete(Wrappers.lambdaQuery(OAuthToken.class).eq(OAuthToken::getUserId, userId));
 				}
 				//nano
-				if (groupsRelation.getGoodsId() != null && groupsRelation.getGoodsId() == Constant.NANO_GOODS_ID) {
+				if (source != UserTicketClearedRecord.Source.vip_deduct && groupsRelation.getGoodsId() != null && groupsRelation.getGoodsId() == Constant.NANO_GOODS_ID) {
 					nanoUserQuotaMapper.delete(Wrappers.lambdaQuery(NanoUserQuota.class).eq(NanoUserQuota::getRelationId, relationId));
 				}
 			}

+ 25 - 2
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -207,8 +207,12 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 
 	private final ClaudeCodeUserRenewExpiryRecordMapper claudeCodeUserRenewExpiryRecordMapper;
 
+	private final GoodsDonCategoryRelateMapper goodsDonCategoryRelateMapper;
+
 	private final ClaudeCodeService claudeCodeService;
 
+	private final NanoUserQuotaMapper nanoUserQuotaMapper;
+
 	@Override
 	public SearchResult<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account, String orderNo, Integer cmt) {
 		User u = userMapper.selectById(userId);
@@ -295,6 +299,8 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 				if (ticket.getSkuNum() > 1) {
 					ticket.setIsMulti(true);
 				}
+				//分类ids
+				ticket.setCategoryIdList(goodsDonCategoryRelateMapper.selectCategoryIdsByGid(ticket.getGoodsId()));
 				//chatGPT直连
 				if (ticket.getGoodsId().equals(42l)) {
 					if (StrUtil.isNotBlank(ticket.getAccount())) {
@@ -2155,8 +2161,6 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 	 * 标记是否可抵扣会员车票
 	 */
 	private void markVipDeductTicket(List<Long> userIds, RenewalView ticket, Set<Long> vipGoodsIds, Boolean isVip) {
-		//nano 先不参与抵扣
-		vipGoodsIds.remove(Constant.NANO_GOODS_ID);
 		if (CollUtil.isNotEmpty(vipGoodsIds) && ticket.getIsMirror() != null && ticket.getIsMirror() && !isVip) {
 			Long goodsId = ticket.getGoodsId();
 			//只购买
@@ -2164,6 +2168,25 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 				return;
 			}
 			if (vipGoodsIds.contains(goodsId)) {
+				if (goodsId == Constant.NANO_GOODS_ID) {
+					NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class).in(NanoUserQuota::getUid, userIds).orderByDesc(NanoUserQuota::getRemainingQuota).last("limit 1"));
+					if (nanoUserQuota != null) {
+						if (ObjectUtil.equal(nanoUserQuota.getRelationId(), ticket.getRelationId())) {
+							ticket.setIsVipDeduct(true);
+						}
+						return;
+					}
+					RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder()
+							.field(RenewalView::getGoodsId, goodsId)
+							.field(RenewalView::getUserId, userIds).op(Operator.InList)
+							.orderBy(RenewalView::getSkuNanoQuota).desc()
+							.onlySelect(RenewalView::getRelationId)
+							.build());
+					if (renewalView != null && ObjectUtil.equal(renewalView.getRelationId(), ticket.getRelationId())) {
+						ticket.setIsVipDeduct(true);
+					}
+					return;
+				}
 				//是否时长最长
 				Number number = beanSearcher.searchCount(RenewalView.class, MapUtils.builder()
 						.field(RenewalView::getRelationId, ticket.getRelationId()).op(Operator.NotEqual)

+ 184 - 2
netflix-service/src/main/java/com/cyksj/service/vip/impl/VipFrontServiceImpl.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.vip.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -14,6 +15,7 @@ import com.cyksj.model.dto.VipDeductDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.response.VipUserPageResp;
+import com.cyksj.model.views.RenewalView;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
 import com.cyksj.service.claude.ClaudeService;
 import com.cyksj.service.user.UserBindRelationService;
@@ -64,6 +66,14 @@ public class VipFrontServiceImpl implements VipFrontService {
 
 	private final ClaudeService claudeService;
 
+	private final LumaUserMapper lumaUserMapper;
+
+	private final UpgradeOrderDonMapper upgradeOrderDonMapper;
+
+	private final NanoUserQuotaMapper nanoUserQuotaMapper;
+
+	private final MidjourneyUserMapper midjourneyUserMapper;
+
 	@Override
 	public void fillVipInfo(Long userId, VipUserPageResp vipUserPageResp) {
 		SysConfig sysConfig = sysConfigMapper.selectOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, Constant.VIP_FEE_KEY).last("limit 1"));
@@ -82,8 +92,6 @@ public class VipFrontServiceImpl implements VipFrontService {
 		//会员规格
 		Set<Long> goodsIds = goodsDonSkuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class)
 				.in(GoodsDonSku::getId, vipSkuIds)).stream().map(GoodsDonSku::getGoodsId).collect(Collectors.toSet());
-		//todo 临时处理 nano先不参与抵扣
-		goodsIds.remove(Constant.NANO_GOODS_ID);
 		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());
 		//可抵扣车票
 		if (count.intValue() > 0) {
@@ -165,6 +173,25 @@ public class VipFrontServiceImpl implements VipFrontService {
 			if (deductGoodsIds.contains(goodsId)) {
 				continue;
 			}
+			if (goodsId == Constant.NANO_GOODS_ID) {
+				NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class).in(NanoUserQuota::getUid, userIdList).orderByDesc(NanoUserQuota::getRemainingQuota).last("limit 1"));
+				if (nanoUserQuota != null) {
+					if (!ObjectUtil.equal(nanoUserQuota.getRelationId(), relation.getId())) {
+						continue;
+					}
+				} else {
+					//规格最高
+					RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder()
+							.field(RenewalView::getGoodsId, goodsId)
+							.field(RenewalView::getUserId, userIdList).op(Operator.InList)
+							.orderBy(RenewalView::getSkuNanoQuota).desc()
+							.onlySelect(RenewalView::getRelationId)
+							.build());
+					if (renewalView != null && !ObjectUtil.equal(renewalView.getRelationId(), relation.getId())) {
+						continue;
+					}
+				}
+			}
 			Long skuId = relation.getSkuId();
 			deductGoodsIds.add(goodsId);
 			Long relationId = relation.getId();
@@ -190,6 +217,12 @@ public class VipFrontServiceImpl implements VipFrontService {
 					//获取抵扣金额
 					deductMoney = deductMoney.add(getFinalDeductMoney(relationId, relation.getSkuId(), claudeUser.getRenewSkuId(), claudeUser.getRenewOrderId(), claudeUser.getRenewExpiryTime(), relation.getStartTime(), relationExpiryTime, now, userIdList));
 				}
+			} else if (goodsId == Constant.LUMA_GOODS_ID || goodsId == Constant.NANO_GOODS_ID) {
+				//luma、nano
+				deductMoney = deductMoney.add(getGeneralRemainNumDeductMoney(relationId, goodsId, skuId, userIdList, relation.getStartTime()));
+			} else if (goodsId == Constant.MIDJOURNEY_GOODS_ID) {
+				//mj
+				deductMoney = deductMoney.add(getMjRemainNumDeductMoney(relationId, skuId, userIdList, relation.getStartTime(), relation.getExpiryTime()));
 			} else {
 				//该车票抵扣金额
 				deductMoney = deductMoney.add(getDeductMoneyFromTicket(relationId, userIdList, skuId, now, relation.getStartTime(), relationExpiryTime));
@@ -388,4 +421,153 @@ public class VipFrontServiceImpl implements VipFrontService {
 		}
 		return single;
 	}
+
+	/**
+	 * 获取普通剩余次数可抵扣金额
+	 */
+	private BigDecimal getGeneralRemainNumDeductMoney(Long relationId, Long goodsId, Long skuId, List<Long> userIdList, Date relationStartTime) {
+		BigDecimal deductMoney = BigDecimal.ZERO;
+		BigDecimal orderTotalMoney = BigDecimal.ZERO;
+		//总次数
+		Integer totalNum = 0;
+		DateTime now = DateTime.now();
+
+		List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getRelationId, relationId).in(OrderDon::getUserId, userIdList).notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
+		for (OrderDon orderDon : orderDonList) {
+			GoodsDonSku sku = skuMapper.selectById(skuId);
+			Date orderCreatedTime = orderDon.getCreatedTime();
+			Integer months = sku.getMonths();
+			Integer days = sku.getDays();
+			Date orderExpiryTime;
+			if (days != null) {
+				orderExpiryTime = DateUtil.offsetDay(orderCreatedTime, days);
+			} else {
+				orderExpiryTime = DateUtil.offsetMonth(orderCreatedTime, months);
+			}
+			//过期的订单不算入
+			if (orderExpiryTime.before(now)) {
+				continue;
+			}
+			if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) {
+				orderTotalMoney = orderTotalMoney.add(orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)));
+			} else {
+				//兑换码订单使用规格价格
+				orderTotalMoney = orderTotalMoney.add(sku.getPrice());
+			}
+			if (goodsId == Constant.LUMA_GOODS_ID) {
+				totalNum += sku.getLumaNum();
+			} else {
+				totalNum += sku.getNanoQuota();
+			}
+		}
+		//加量包订单
+		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));
+		for (UpgradeOrderDon upgradeOrderDon : upgradeOrderDons) {
+			orderTotalMoney = orderTotalMoney.add(upgradeOrderDon.getMoney().add(Optional.ofNullable(upgradeOrderDon.getBalance()).orElse(BigDecimal.ZERO)));
+			totalNum = totalNum + upgradeOrderDon.getNum();
+		}
+		Integer remainNum = null;
+		if (goodsId == Constant.LUMA_GOODS_ID) {
+			LumaUser lumaUser = lumaUserMapper.selectOne(Wrappers.lambdaQuery(LumaUser.class).eq(LumaUser::getRelationId, relationId).last("limit 1"));
+			if (lumaUser != null) {
+				remainNum = lumaUser.getNum();
+			}
+		} else {
+			NanoUserQuota nanoUserQuota = nanoUserQuotaMapper.selectOne(Wrappers.lambdaQuery(NanoUserQuota.class).eq(NanoUserQuota::getRelationId, relationId).last("limit 1"));
+			if (nanoUserQuota != null) {
+				remainNum = nanoUserQuota.getRemainingQuota();
+			}
+		}
+		//若未使用
+		if (remainNum == null) {
+			deductMoney = deductMoney.add(orderTotalMoney);
+		} else {
+			BigDecimal remainMoney = BigDecimal.valueOf(remainNum).divide(BigDecimal.valueOf(totalNum), 2, RoundingMode.DOWN).multiply(orderTotalMoney);
+			deductMoney = deductMoney.add(remainMoney);
+		}
+		return deductMoney;
+	}
+
+	/**
+	 * 获取mj剩余次数可抵扣金额
+	 */
+	private BigDecimal getMjRemainNumDeductMoney(Long relationId, Long skuId, List<Long> userIdList, Date relationStartTime, Date relationExpiryTime) {
+		BigDecimal deductMoney = BigDecimal.ZERO;
+		BigDecimal orderTotalMoney = BigDecimal.ZERO;
+		//总次数
+		Integer totalNum = null;
+		//原车票订单总天数
+		Integer totalDays = 0;
+		DateTime now = DateTime.now();
+
+		List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getRelationId, relationId).in(OrderDon::getUserId, userIdList).notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
+		for (OrderDon orderDon : orderDonList) {
+			GoodsDonSku sku = skuMapper.selectById(skuId);
+			Date orderCreatedTime = orderDon.getCreatedTime();
+			Integer months = sku.getMonths();
+			Integer days = sku.getDays();
+			//订单过期时间
+			Date orderExpiryTime;
+			if (days != null) {
+				orderExpiryTime = DateUtil.offsetDay(orderCreatedTime, days);
+			} else {
+				orderExpiryTime = DateUtil.offsetMonth(orderCreatedTime, months);
+			}
+			//总时间
+			totalDays += sku.getMonths() * 30;
+			//过期的订单不算入
+			if (orderExpiryTime.before(now)) {
+				continue;
+			}
+			if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) {
+				orderTotalMoney = orderTotalMoney.add(orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)));
+			} else {
+				//兑换码订单使用规格价格
+				orderTotalMoney = orderTotalMoney.add(sku.getPrice());
+			}
+			if (totalNum == null) {
+				totalNum = sku.getMjFastNum() + sku.getMjRelaxNum();
+			}
+		}
+		Integer upgradeNum = 0;
+		BigDecimal upgradeOrderMoney = BigDecimal.ZERO;
+		//加量包订单
+		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));
+		for (UpgradeOrderDon upgradeOrderDon : upgradeOrderDons) {
+			upgradeNum += upgradeOrderDon.getNum();
+			upgradeOrderMoney = upgradeOrderMoney.add(upgradeOrderDon.getMoney().add(Optional.ofNullable(upgradeOrderDon.getBalance()).orElse(BigDecimal.ZERO)));
+		}
+		MidjourneyUser midjourneyUser = midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class).eq(MidjourneyUser::getRelationId, relationId).last("limit 1"));
+		if (midjourneyUser == null) {
+			deductMoney = deductMoney.add(orderTotalMoney).add(upgradeOrderMoney);
+		} else {
+			if (CollUtil.isNotEmpty(orderDonList)) {
+				Integer remainFastNum = midjourneyUser.getMjFastNum();
+				Integer remainRelaxNum = midjourneyUser.getMjRelaxNum();
+				Integer usedNum = totalNum - remainFastNum - remainRelaxNum;
+				if (usedNum == 0 && now.toDateStr().equals(DateUtil.format(relationStartTime, "yyyy-MM-dd"))) {
+					deductMoney = deductMoney.add(orderTotalMoney);
+				} else {
+					//每天单价
+					BigDecimal single = orderTotalMoney.divide(BigDecimal.valueOf(totalDays), 0, RoundingMode.HALF_UP);
+					BigDecimal consumeRate = BigDecimal.valueOf(usedNum).divide(BigDecimal.valueOf(totalNum), 2, RoundingMode.DOWN);
+					//消耗的次数当月 值多少钱
+					BigDecimal consumeMoney = consumeRate.multiply(single.multiply(BigDecimal.valueOf(30)));
+					//该车票多长时间
+					Long thisDeductBetweenDay = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
+					//该车票抵扣金额
+					BigDecimal orderRemainMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
+					//最终可抵扣
+					deductMoney = deductMoney.add(orderRemainMoney.subtract(consumeMoney));
+				}
+			}
+			//加量包
+			Integer remainUpgradeNum = midjourneyUser.getMjUpgradeNum();
+			if (CollUtil.isNotEmpty(upgradeOrderDons)) {
+				BigDecimal upgradeMoney = BigDecimal.valueOf(remainUpgradeNum).divide(BigDecimal.valueOf(upgradeNum), 2, RoundingMode.DOWN).multiply(upgradeOrderMoney);
+				deductMoney = deductMoney.add(upgradeMoney);
+			}
+		}
+		return deductMoney;
+	}
 }