zoujiajian 11 meses atrás
pai
commit
7aa6e9fda3

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CodexUser.java

@@ -71,4 +71,9 @@ public class CodexUser extends BaseEntity {
      * 是否重试更新
      */
     private Boolean isRetry;
+
+    /**
+     * 是否购买 默认false
+     */
+    private Boolean isPay;
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/request/CodexUpgradePayReq.java

@@ -20,4 +20,9 @@ public class CodexUpgradePayReq {
 	 * 升级claude code规格id
 	 */
 	private Long skuId;
+
+	/**
+	 * 使用优惠券
+	 */
+	private Long couponId;
 }

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CcCodexInfoView.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.ClaudeCodeUser;
+import com.cyksj.model.entity.CodexUser;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: CcCodexInfoView
+ * 创建者: JavaZou
+ * 创建时间:2025/9/24 11:51
+ */
+@Getter
+@Setter
+public class CcCodexInfoView {
+	private ClaudeCodeUser claudeCodeUser;
+
+	private CodexUser codexUser;
+}

+ 2 - 4
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -335,7 +335,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).gt(CodexUser::getExpiryTime, DateTime.now()).last("limit 1"));
 			if (codexUser != null) {
 				updateCodexUserIfTry(codexUser);
-				codexUserInfoView = CodexUserInfoView.builder().isPay(Boolean.TRUE).planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).build();
+				codexUserInfoView = CodexUserInfoView.builder().isPay(codexUser.getIsPay()).planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).build();
 				return ClaudeCodeUserInfoView.builder()
 						.codexUserInfo(codexUserInfoView)
 						.build();
@@ -402,15 +402,13 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 				codexService.createOrUpdateUserPackage(codexPackageReq);
 			}
 		}
-		Boolean isPay = Boolean.FALSE;
 		//不存在赠送  查看是否有自购
 		if (codexUser == null) {
 			codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).gt(CodexUser::getExpiryTime, DateTime.now()).last("limit 1"));
-			isPay = Boolean.TRUE;
 		}
 		if (codexUser != null) {
 			updateCodexUserIfTry(codexUser);
-			codexUserInfoView = CodexUserInfoView.builder().isPay(isPay).planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).build();
+			codexUserInfoView = CodexUserInfoView.builder().isPay(codexUser.getIsPay()).planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).build();
 		}
 
 		return ClaudeCodeUserInfoView.builder()

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/codex/CodexService.java

@@ -68,5 +68,5 @@ public interface CodexService {
 
     CodexDeductResp getDeductMoney(Long userId, Long relationId);
 
-    OrderDon deductSubmitOrder(CodexUpgradePayReq payReq);
+    OrderDon deductSubmitOrder(CodexUpgradePayReq payReq) throws Exception;
 }

+ 243 - 4
netflix-service/src/main/java/com/cyksj/service/codex/impl/CodexServiceImpl.java

@@ -3,6 +3,7 @@ package com.cyksj.service.codex.impl;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.http.Method;
@@ -16,6 +17,12 @@ import com.cyksj.dto.RedisKey;
 import com.cyksj.mapper.*;
 import com.cyksj.mapper.codex.CodexDeductRecordMapper;
 import com.cyksj.mapper.codex.CodexUserRenewExpiryRecordMapper;
+import com.cyksj.mapper.manage.coupon.CouponMapper;
+import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
+import com.cyksj.mapper.manage.coupon.CouponUserMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeSharedMapper;
+import com.cyksj.model.dto.CouponPopularizeDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.request.CodexUpgradePayReq;
@@ -24,8 +31,11 @@ import com.cyksj.model.request.codex.CodexUserPackageReq;
 import com.cyksj.model.response.CodexDeductResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.CodexUserInfoView;
+import com.cyksj.model.views.CouponNewUserView;
+import com.cyksj.model.views.CouponUserView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.codex.CodexService;
+import com.cyksj.service.coupon.CouponFontService;
 import com.cyksj.service.groups.GroupsFuncService;
 import com.cyksj.service.user.UserBindRelationService;
 import com.ejlchina.searcher.BeanSearcher;
@@ -66,6 +76,10 @@ public class CodexServiceImpl implements CodexService {
 
 	private final GoodsDonSkuMapper skuMapper;
 
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final CouponMapper couponMapper;
+
 	private final GroupsRelationMapper relationMapper;
 
 	private final GroupsMapper groupsMapper;
@@ -82,6 +96,18 @@ public class CodexServiceImpl implements CodexService {
 
 	private final CodexDeductRecordMapper codexDeductRecordMapper;
 
+	private final CouponSkuMapper couponSkuMapper;
+
+	private final CouponUserMapper couponUserMapper;
+
+	private final UserDistributeMapper userDistributeMapper;
+
+	private final UserDistributeSharedMapper userDistributeSharedMapper;
+
+	private final UserMapper userMapper;
+
+	private final CouponFontService couponFontService;
+
 	private static final Sequence SEQUENCE = new Sequence(0);
 	@Override
 	public CodexUserInfoView getCodexUserInfo(Long userId) {
@@ -217,16 +243,17 @@ public class CodexServiceImpl implements CodexService {
 		BigDecimal deductMoney;
 		if (groupsRelationView == null || groupsRelationView.getExpiryTime().before(DateTime.now())) {
 			deductMoney = BigDecimal.ZERO;
+		} else {
+			CodexUser codexUser = codexUserMapper.selectById(relationId);
+			deductMoney = getFinalDeductMoney(relationId, groupsRelationView.getSkuId(), codexUser.getRenewSkuId(), codexUser.getRenewOrderId(), codexUser.getRenewExpiryTime(), groupsRelationView.getStartTime(), groupsRelationView.getExpiryTime(), DateTime.now(), userIdList);
 		}
-		CodexUser codexUser = codexUserMapper.selectById(relationId);
-		deductMoney = getFinalDeductMoney(relationId, groupsRelationView.getSkuId(), codexUser.getRenewSkuId(), codexUser.getRenewOrderId(), codexUser.getRenewExpiryTime(), groupsRelationView.getStartTime(), groupsRelationView.getExpiryTime(), DateTime.now(), userIdList);
 		codexDeductResp.setDeductMoney(deductMoney);
 		return codexDeductResp;
 	}
 
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
-	public OrderDon deductSubmitOrder(CodexUpgradePayReq payReq) {
+	public OrderDon deductSubmitOrder(CodexUpgradePayReq payReq) throws Exception {
 		Long userId = payReq.getUserId();
 		//codex 车票id
 		Long relationId = payReq.getRelationId();
@@ -236,8 +263,9 @@ public class CodexServiceImpl implements CodexService {
 		}
 		//抵扣金额
 		BigDecimal deductMoney = codexDeductResp.getDeductMoney();
+		Long skuId = payReq.getSkuId();
 
-		GoodsDonSku sku = skuMapper.selectById(payReq.getSkuId());
+		GoodsDonSku sku = skuMapper.selectById(skuId);
 		if (sku == null || sku.getGoodsId() != Constant.CLAUDE_CODE_GOODS_ID || !sku.getIsCodex()) {
 			throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
 		}
@@ -252,6 +280,12 @@ public class CodexServiceImpl implements CodexService {
 		if (!b) {
 			throw BusinessRuntimeException.getInstance("系统繁忙,请刷新页面重试");
 		}
+		CouponUser couponUser = null;
+		if (payReq.getCouponId() != null) {
+			CouponPopularizeDto couponPopularizeDto = checkCouponStatus(skuId, null, payReq.getCouponId(), userId, false);
+			//记录优惠券使用状态
+			couponUser = couponStatusRecord(null, payReq.getCouponId(), userId, couponPopularizeDto);
+		}
 
 		OrderDon orderDon;
 		try {
@@ -259,6 +293,8 @@ public class CodexServiceImpl implements CodexService {
 			orderDon.setGoodsId(sku.getGoodsId());
 			orderDon.setSkuId(sku.getId());
 			orderDon.setUserId(userId);
+			//优惠 --> 订单金额
+			deductOrderMoney(orderDon, couponUser);
 			orderDon.setMoney(sku.getPrice().subtract(deductMoney));
 
 			/* 生成订单 */
@@ -266,6 +302,8 @@ public class CodexServiceImpl implements CodexService {
 			orderDon.setOrderNo(donNo);
 
 			//锁一个cc的车票id
+			//是否存在无赠送的claude code 直接原规格上抵扣
+
 			GroupsRelation relation = getClaudeCodeRelation(userId, sku);
 			orderDon.setRelationId(relation.getId());
 			orderDonMapper.insert(orderDon);
@@ -887,4 +925,205 @@ public class CodexServiceImpl implements CodexService {
 			}
 		}
 	}
+
+	public CouponPopularizeDto checkCouponStatus(Long skuId, String couponExCode, Long couponId, Long userId, Boolean isRenew) throws Exception {
+		log.info("开始校验兑换码:{},优惠券id:{}状态", couponExCode, couponId);
+		//实物还是虚物商品
+		GoodsDonSku goodsDonSku = skuMapper.selectById(skuId);
+		GoodsDon goodsDon = goodsDonMapper.selectById(goodsDonSku.getGoodsId());
+		if (StrUtil.isNotBlank(couponExCode) && couponId != null) {
+			throw BusinessRuntimeException.getInstance("优惠券与优惠码不可同时使用..");
+		}
+		if (StrUtil.isNotBlank(couponExCode)) {
+			CouponPopularizeDto exists = couponMapper.checkExCode(couponExCode);
+			if (exists == null) {
+				throw BusinessRuntimeException.getInstance("该优惠码不存在");
+			}
+			//推广码
+			if (exists.getIsGeneral() != null) {
+				if (exists.getIsGeneral() && userId.equals(exists.getUserId())) {
+					throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
+				}
+				if (!exists.getIsGeneral()) {
+					UserDistribute userDistribute = userDistributeMapper.selectById(exists.getDistributeId());
+					if (userDistribute != null && userDistribute.getUserId().equals(userId)) {
+						throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
+					}
+				}
+				//是否有上下级关系
+				if (exists.getIsGeneral()) {
+					UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class)
+							.eq(UserDistributeShared::getUserId, userId).last("limit 1"));
+					if (userDistributeShared == null) {
+						//是否是 当天注册新用户 且下过单
+						User user = userMapper.selectById(userId);
+						if (user.getCreatedTime().before(DateUtil.beginOfDay(DateTime.now()))) {
+							throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
+						}
+						CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
+						if (couponNewUserView != null)
+							throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
+					}
+					if (userDistributeShared != null && !userDistributeShared.getSharedId().equals(exists.getUserId())) {
+						throw BusinessRuntimeException.getInstance("您已有推广,无法使用其他人推广码");
+					}
+				}
+			}
+			checkCouponGoods(goodsDon, skuId, exists.getCouponId(), true);
+			//检验是优惠券使用范围
+			if (isRenew && exists.getUseScope() == Coupon.UseScope.orders) {
+				throw BusinessRuntimeException.getInstance("该优惠码续费时不可使用");
+			}
+			if (!isRenew && exists.getUseScope() == Coupon.UseScope.renew) {
+				throw BusinessRuntimeException.getInstance("该优惠码下单时不可使用");
+			}
+			if (exists.getScope() == Coupon.Scope.newUser) {
+				CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
+				if (couponNewUserView != null) {
+					throw BusinessRuntimeException.getInstance("该新用户优惠码有且仅可使用一次");
+				}
+			}
+			if (exists.getIsValidTime() && exists.getValidEndTime().before(DateTime.now())) {
+				throw BusinessRuntimeException.getInstance("该优惠码已失效");
+			}
+			if (exists.getIsValidTime() && exists.getValidStartTime().after(DateTime.now())) {
+				throw BusinessRuntimeException.getInstance("该优惠码待生效");
+			}
+			return exists;
+		} else if (couponId != null) {
+			CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
+					.field(CouponUserView::getCouponId, couponId).op(Operator.Equal)
+					.field(CouponUserView::getUserId, userId).op(Operator.Equal)
+					.build());
+			if (couponUserView == null) {
+				throw BusinessRuntimeException.getInstance("该优惠券不存在");
+			}
+			if (couponUserView.getCouponUserStatus() == CouponUser.Status.used) {
+				throw BusinessRuntimeException.getInstance("该优惠券已使用");
+			}
+			couponFontService.setCouponUserStatus(couponUserView, DateTime.now());
+			if (couponUserView.getCouponUserStatus() != CouponUser.Status.unused) {
+				throw BusinessRuntimeException.getInstance(couponUserView.getReason());
+			}
+			checkCouponGoods(goodsDon, skuId, couponUserView.getCouponId(), false);
+			//检验是优惠券使用范围
+			if (isRenew && couponUserView.getUseScope() == Coupon.UseScope.orders) {
+				throw BusinessRuntimeException.getInstance("该优惠券续费时不可使用");
+			}
+			if (!isRenew && couponUserView.getUseScope() == Coupon.UseScope.renew) {
+				throw BusinessRuntimeException.getInstance("该优惠券下单时不可使用");
+			}
+		}
+		return null;
+	}
+
+
+	private CouponUser couponStatusRecord(String couponExCode, Long couponId, Long userId, CouponPopularizeDto exists) {
+		log.info("兑换码:{},优惠券id:{},更新其优惠券状态", couponExCode, couponId);
+		CouponUser couponUser = null;
+		if (StrUtil.isNotBlank(couponExCode)) {
+			if (exists == null) {
+				throw BusinessRuntimeException.getInstance("该优惠码不存在");
+			}
+			couponUser = new CouponUser();
+			couponUser.setCouponId(exists.getCouponId());
+			if (exists.getPopularizeId() != null) {
+				couponUser.setCouponId(exists.getPopularizeCouponId());
+				couponUser.setPopularizeId(exists.getPopularizeId());
+			}
+			//续费优惠码可重复使用
+			if (exists.getUseScope() != Coupon.UseScope.renew) {
+				//非渠道推广 推广优惠码只可使用一次
+				if ((exists.getPopularizeId() != null && exists.getIsGeneral()) || exists.getPopularizeId() == null) {
+					CouponUser received = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponUser.getCouponId()).last("limit 1"));
+					if (received != null && received.getStatus() != CouponUser.Status.unused) {
+						throw BusinessRuntimeException.getInstance("您已使用该优惠码所对应的优惠券");
+					}
+					couponUser.setUserId(userId);
+					couponUser.setStatus(CouponUser.Status.used);
+					couponUser.setChannel(CouponUser.Channel.exCode);
+					couponFontService.updateCouponUserValidTime(couponUser.getCouponId(), couponUser);
+					try {
+						couponUserMapper.insert(couponUser);
+					} catch (DuplicateKeyException e) {
+						log.info("用户已领取该{}优惠券", couponUser.getCouponId());
+						throw BusinessRuntimeException.getInstance("您已领取该优惠码对应的优惠券,请使用优惠券");
+					}
+				}
+			}
+		} else {
+			couponUser = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponId).last("limit 1"));
+			if (couponUser == null) {
+				throw BusinessRuntimeException.getInstance("该优惠券不存在");
+			}
+			couponUser.setStatus(CouponUser.Status.used);
+			couponUserMapper.updateById(couponUser);
+		}
+		return couponUser;
+	}
+
+	public void checkCouponGoods(GoodsDon goodsDon, Long skuId, Long couponId, Boolean isCouponCode) throws Exception {
+		if (goodsDon.getType() == 1) {
+			CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
+					.eq(CouponSku::getSkuId, skuId)
+					.eq(CouponSku::getCouponId, couponId)
+					.select(CouponSku::getId).last("limit 1"));
+			if (couponSku == null) {
+				throw BusinessRuntimeException.getInstance(String.format("该%s不适用于该规格", isCouponCode ? "优惠码" : "优惠券"));
+			}
+		} else {
+			//实物、潮玩 优惠码优惠券 针对平台
+			Long gid = goodsDon.getId();
+			CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
+					.eq(CouponSku::getGoodsId, gid)
+					.eq(CouponSku::getCouponId, couponId)
+					.select(CouponSku::getId).last("limit 1"));
+			if (couponSku == null) {
+				throw BusinessRuntimeException.getInstance(String.format("该%s不可用于该商品", isCouponCode ? "优惠码" : "优惠券"));
+			}
+		}
+	}
+
+	/**
+	 * 使用优惠营销 订单金额抵扣
+	 */
+	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser) throws Exception {
+		BigDecimal first_money = orderDon.getMoney();
+		//存在优惠券
+		if (couponUser != null) {
+			Long couponId = couponUser.getCouponId();
+			Coupon coupon = couponMapper.getCouponById(couponId);
+			BigDecimal couponMoney = null;
+			BigDecimal payMoney = orderDon.getMoney();
+			BigDecimal needDeductMoney = payMoney;
+			if (orderDon.getOriMoney() == null) {
+				orderDon.setOriMoney(payMoney);
+			}
+			if (orderDon.getIsDp() != null && orderDon.getIsDp()) {
+				needDeductMoney = needDeductMoney.subtract(orderDon.getDpMoney());
+			}
+			if (coupon.getType() == Coupon.Type.discount) {
+				couponMoney = needDeductMoney.multiply(BigDecimal.valueOf(1).subtract(coupon.getDiscount()));
+				//需支付金额
+				orderDon.setMoney(payMoney.subtract(couponMoney));
+
+				orderDon.setOriMoney(orderDon.getOriMoney().multiply(coupon.getDiscount()));
+				//记录折扣 用于分销
+				couponUser.setDiscount(coupon.getDiscount());
+				couponUserMapper.updateById(couponUser);
+			} else if (coupon.getType() == Coupon.Type.reduce) {
+				BigDecimal subtractMoney = payMoney.subtract(coupon.getReduceMoney());
+				orderDon.setMoney(subtractMoney);
+				couponMoney = coupon.getReduceMoney();
+
+				orderDon.setOriMoney(orderDon.getOriMoney().subtract(coupon.getReduceMoney()));
+			}
+			if (couponMoney != null && couponMoney.compareTo(first_money) >= 0) {
+				throw BusinessRuntimeException.getInstance("支付金额不能小于优惠金额");
+			}
+			orderDon.setCouponMoney(couponMoney);
+			orderDon.setCouponUserId(couponUser.getId());
+			orderDon.setCouponId(couponUser.getCouponId());
+		}
+	}
 }

+ 25 - 0
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -401,6 +401,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final CodexDeductRecordMapper codexDeductRecordMapper;
 
+	private final CodexUserMapper codexUserMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -486,6 +488,14 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			if (sku != null && ObjectUtil.equal(sku.getId(), Constant.DISTRIBUTE_CLAUDE_CODE_TRIAL_SKU_ID)) {
 				checkCCTrialCardNum(userIdList);
 			}
+			//是否是赠送codex sku
+			if (sku.getIsCodex()) {
+				//是否存在codex
+				CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList));
+				if (codexUser != null) {
+					throw BusinessRuntimeException.getInstance("您已购买了codex套餐,如需claude可用codex抵扣升级,不可重复购买");
+				}
+			}
 		}
 		//codex 限购
 		if (goodsId == Constant.CODEX_GOODS_ID) {
@@ -493,6 +503,11 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			if (selectCount > 0) {
 				throw BusinessRuntimeException.getInstance("codex车票限购一次");
 			}
+			//是否拥有cc赠送codex
+			CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList));
+			if (codexUser != null) {
+				throw BusinessRuntimeException.getInstance("您已购买了Claude+codex的组合套餐,用量不够请续费升级,不可重复购买");
+			}
 		}
 
 		//校验奈飞限购信息
@@ -4607,6 +4622,16 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			throw BusinessRuntimeException.getInstance("不支持单独续费");
 		}
 
+		//claude code 续费升级
+		if (goodsDon.getId() == Constant.CLAUDE_CODE_GOODS_ID) {
+			//是否存在已购买的codex
+			List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+			Integer selectCount = groupsRelationMapper.selectCountByGoodsId(userIdList, Constant.CODEX_GOODS_ID, DateTime.now());
+			if (selectCount > 0) {
+				throw BusinessRuntimeException.getInstance("您已购买了codex套餐,如需claude可用codex抵扣升级,不可重复购买");
+			}
+		}
+
 		OrderDon orderDon = new OrderDon();
 		orderDon.setUserId(userId);
 		orderDon.setGoodsId(goodsDonSku.getGoodsId());

+ 1 - 1
netflix-web/src/main/java/com/cyksj/web/controller/codex/CodexController.java

@@ -115,7 +115,7 @@ public class CodexController {
      * codex 抵扣升级 预下单
      */
     @PostMapping("/deduct/submit/order")
-    public Result<OrderDon> deductSubmitOrder(CodexUpgradePayReq payReq) {
+    public Result<OrderDon> deductSubmitOrder(CodexUpgradePayReq payReq) throws Exception {
         long userId = StpUserUtil.getLoginIdAsLong();
         payReq.setUserId(userId);
         OrderDon orderDon = codexService.deductSubmitOrder(payReq);

+ 16 - 0
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -1478,4 +1478,20 @@ public class GroupRelationController {
                 .build());
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }
+
+    /**
+     * claude code+codex 套餐情况
+     */
+    @GetMapping("/get/cc/codex/info")
+    public Result<CcCodexInfoView> getCcCodexInfo() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+        ClaudeCodeUser claudeCodeUser = beanSearcher.searchFirst(ClaudeCodeUser.class, MapUtils.builder().field(ClaudeCodeUser::getUserId, userIdList).op(Operator.InList).build());
+        CodexUser codexUser = beanSearcher.searchFirst(CodexUser.class, MapUtils.builder().field(CodexUser::getUserId, userIdList).op(Operator.InList).build());
+        //cc codex
+        CcCodexInfoView ccCodexInfoView = new CcCodexInfoView();
+        ccCodexInfoView.setClaudeCodeUser(claudeCodeUser);
+        ccCodexInfoView.setCodexUser(codexUser);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
 }