Переглянути джерело

claude code套餐升级处理

zoujiajian 1 рік тому
батько
коміт
1b2fd9619d

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/mapper/ClaudeCodeUserRenewExpiryRecordMapper.java

@@ -2,6 +2,9 @@ package com.cyksj.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.entity.ClaudeCodeUserRenewExpiryRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * 项目名: yhlxj11111111
@@ -10,4 +13,5 @@ import com.cyksj.model.entity.ClaudeCodeUserRenewExpiryRecord;
  * 创建时间:2025/8/11 13:39
  */
 public interface ClaudeCodeUserRenewExpiryRecordMapper extends BaseMapper<ClaudeCodeUserRenewExpiryRecord> {
+	ClaudeCodeUserRenewExpiryRecord getOtherRenewSku(@Param("orderId") Long orderId, @Param("relationId") Long relationId, @Param("userIds") List<Long> userIds);;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ClaudeCodeUser.java

@@ -37,6 +37,12 @@ public class ClaudeCodeUser extends BaseEntity{
 	 */
 	private Date expiryTime;
 
+	/**
+	 * 续费升级订单id
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Long renewOrderId;
+
 	/**
 	 * 续费升级skuid
 	 */

+ 4 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/ClaudeCodeUserRenewExpiryRecord.java

@@ -22,10 +22,13 @@ public class ClaudeCodeUserRenewExpiryRecord extends BaseEntity{
 
 	private Long orderId;
 
+	/**
+	 * 过期时间
+	 */
 	private Date expiryTime;
 
 	/**
-	 * 是否有效 默认有效 true
+	 * 是否失效 默认false
 	 */
 	private Boolean isValid;
 }

+ 0 - 2
netflix-dao/src/main/java/com/cyksj/model/response/claudecode/ClaudeCodeResp.java

@@ -12,8 +12,6 @@ import lombok.Setter;
 @Getter
 @Setter
 public class ClaudeCodeResp {
-	private Boolean success;
-
 	private Object data;
 
 	private Integer code;

+ 18 - 0
netflix-dao/src/main/resources/mapper/ClaudeCodeUserRenewExpiryRecordMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.cyksj.mapper.ClaudeCodeUserRenewExpiryRecordMapper">
+
+    <select id="getOtherRenewSku" resultType="com.cyksj.model.entity.ClaudeCodeUserRenewExpiryRecord">
+        select o.* from (select order_id from claude_code_user_renew_expiry_record where order_id != #{orderId}
+        and is_valid = 0
+        and user_id in
+        <foreach collection="userIds" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>) orr inner join order_don o on o.id = orr.order_id
+        and o.status not in ('close','noPayment','refund')
+        and o.order_type = 2 and o.relation_id = #{relationId}
+        inner join goods_don_sku sku on sku.id = o.sku_id
+        order by sku.months desc,sku.code_points desc
+        limit 1
+    </select>
+</mapper>

+ 3 - 0
netflix-service/src/main/java/com/cyksj/service/claude/ClaudeCodeService.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.claude;
 
+import com.cyksj.model.entity.ClaudeCodeUser;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.request.ClaudeCodeApiKeysReq;
 import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
@@ -65,4 +66,6 @@ public interface ClaudeCodeService {
 	ClaudeCodeUserInfoView getClaudeCodeUserSubsInfo(Long userId);
 
 	Boolean checkClaudeCodeUser(Long userId);
+
+	void updateClaudeCodeUserPackageInfo(ClaudeCodeUser claudeCodeUser, String planName);
 }

+ 24 - 8
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -102,10 +102,10 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			if (orderType == 2) {
 				invalidateUserCache(relationUserId);
 			}
-			generateOrUpdateClaudeCodeUser(relationUserId, relationId, codePoints, codeCreditRecovery, expiryTime, isUpgrade, skuId, renewExpiryTime);
+			generateOrUpdateClaudeCodeUser(relationUserId, relationId, codePoints, codeCreditRecovery, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime);
 			//生成claude code或更新用户套餐
 			ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(relation.getUserId(), sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
-			if (!codeUserPackage.getSuccess()) {
+			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
 				log.info("更新 claude code 用户:{}套餐数据失败", userId);
 				//重试更新code userInfo数据
 				setClaudeCodeUserRetryUpdateInfo(relationId);
@@ -117,7 +117,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		}
 	}
 
-	private void generateOrUpdateClaudeCodeUser(Long relationUserId, Long relationId, Integer codePoints, Integer codeCreditRecovery, Date expiryTime, Boolean isUpgrade, Long renewSkuId, Date renewExpiryTime) {
+	private void generateOrUpdateClaudeCodeUser(Long relationUserId, Long relationId, Integer codePoints, Integer codeCreditRecovery, Date expiryTime, Boolean isUpgrade, Long orderId, Long renewSkuId, Date renewExpiryTime) {
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
 		if (claudeCodeUser == null) {
 			claudeCodeUser = new ClaudeCodeUser();
@@ -128,6 +128,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			claudeCodeUser.setCodeCreditRecovery(codeCreditRecovery);
 		}
 		if (isUpgrade) {
+			claudeCodeUser.setRenewOrderId(orderId);
 			claudeCodeUser.setRenewSkuId(renewSkuId);
 			claudeCodeUser.setRenewExpiryTime(renewExpiryTime);
 		}
@@ -155,7 +156,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			}
 			String responseBody = executeClaudeCodePostApi(apiKeyUrl, parmas.toString());
 			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-			if (!claudeCodeResp.getSuccess()) {
+			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
 				throw BusinessRuntimeException.getInstance("创建失败");
 			}
 			return claudeCodeResp;
@@ -177,7 +178,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			parmas.put("status", status);
 			String responseBody = executeClaudeCodePostApi(apiKeyUrl, parmas.toString());
 			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-			if (claudeCodeResp.getSuccess()) {
+			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
 				//更新用户apikey缓存
 				updateUserApiKeysCache(keyValue);
 			}
@@ -230,7 +231,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", claudeCodeUserId);
 			String responseBody = executeClaudeCodeGetApi(url);
 			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-			if (claudeCodeResp.getSuccess()) {
+			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
 				return Jsons.parseObject(responseBody, ClaudeCodeUserPackageView.class);
 			}
 		}
@@ -331,7 +332,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		if (claudeCodeUser.getIsRetry()) {
 			try {
 				ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), specVal, claudeCodeUser.getCodePoints(), claudeCodeUser.getCodeCreditRecovery(), claudeCodeUser.getExpiryTime());
-				if (codeUserPackage.getSuccess()) {
+				if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
 					claudeCodeUser.setIsRetry(Boolean.FALSE);
 					claudeCodeUserMapper.updateById(claudeCodeUser);
 				}
@@ -359,7 +360,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		String planUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
 		String responseBody = executeClaudeCodePostApi(planUrl, parmas.toString());
 		ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-		if (claudeCodeResp.getSuccess()) {
+		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
 			log.info("用户claude code用户:{}套餐:{}创建或更新成功", userId, planName);
 		}
 		return claudeCodeResp;
@@ -378,6 +379,21 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		return count > 0;
 	}
 
+	@Override
+	public void updateClaudeCodeUserPackageInfo(ClaudeCodeUser claudeCodeUser, String planName) {
+		try {
+			ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), planName, claudeCodeUser.getCodePoints(), claudeCodeUser.getCodeCreditRecovery(), claudeCodeUser.getExpiryTime());
+			if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
+				//重试标记
+				claudeCodeUser.setIsRetry(Boolean.TRUE);
+				claudeCodeUserMapper.updateById(claudeCodeUser);
+			}
+		} catch (Exception e) {
+			claudeCodeUser.setIsRetry(Boolean.TRUE);
+			claudeCodeUserMapper.updateById(claudeCodeUser);
+		}
+	}
+
 	/**
 	 * 获取claude code用户id
 	 */

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

@@ -8,6 +8,7 @@ import com.cyksj.common.constant.Constant;
 import com.cyksj.mapper.*;
 import com.cyksj.model.entity.*;
 import com.cyksj.redis.RedisService;
+import com.cyksj.service.claude.ClaudeCodeService;
 import com.cyksj.service.mange.MirrorUserCleatService;
 import com.cyksj.service.user.UserBindRelationService;
 import lombok.RequiredArgsConstructor;
@@ -56,6 +57,12 @@ public class MirrorUserCleatServiceImpl implements MirrorUserCleatService {
 
 	private final UserTicketClearedRecordMapper userTicketClearedRecordMapper;
 
+	private final ClaudeCodeUserRenewExpiryRecordMapper claudeCodeUserRenewExpiryRecordMapper;
+
+	private final ClaudeCodeUserMapper claudeCodeUserMapper;
+
+	private final ClaudeCodeService claudeCodeService;
+
 	/**
 	 * 删除镜像User
 	 */
@@ -124,14 +131,63 @@ public class MirrorUserCleatServiceImpl implements MirrorUserCleatService {
 
 	@Override
 	public void handleRenewUpgradeOrders(OrderDon orderDon, GoodsDonSku sku) {
+		Long goodsId = orderDon.getGoodsId();
 		Long orderId = orderDon.getId();
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(orderDon.getUserId(), null);
+		//claude code user
+		if (goodsId == Constant.CLAUDE_CODE_GOODS_ID) {
+			ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class)
+					.eq(ClaudeCodeUser::getRelationId, orderDon.getRelationId())
+					.last("limit 1"));
+			if (claudeCodeUser == null) {
+				return;
+			}
+			Long presentRenewSkuId = claudeCodeUser.getRenewSkuId();
+			if (presentRenewSkuId == null) {
+				return;
+			}
+			GroupsRelation relation = groupsRelationMapper.selectById(orderDon.getRelationId());
+			GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
+			GoodsDonSku finalSku = skuMapper.selectById(groupsTrips.getSkuId());
+			ClaudeCodeUserRenewExpiryRecord renewExpiryRecord = claudeCodeUserRenewExpiryRecordMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUserRenewExpiryRecord.class).eq(ClaudeCodeUserRenewExpiryRecord::getOrderId, orderId).eq(ClaudeCodeUserRenewExpiryRecord::getIsValid, Boolean.TRUE).last("limit 1"));
+			Date renewExpiryTime = null;
+			claudeCodeUser.setRenewSkuId(null);
+			claudeCodeUser.setRenewOrderId(null);
+			if (renewExpiryRecord != null) {
+				//是否存在其他续费升级
+				ClaudeCodeUserRenewExpiryRecord otherRenewRecord = claudeCodeUserRenewExpiryRecordMapper.getOtherRenewSku(orderDon.getId(), relation.getId(), userIdList);
+				GoodsDonSku otherRenewSku = null;
+				if (otherRenewRecord != null) {
+					otherRenewSku = skuMapper.selectById(otherRenewRecord.getRenewSkuId());
+					renewExpiryTime = otherRenewRecord.getExpiryTime();
+				}
+				//续费升级
+				if (otherRenewSku != null) {
+					finalSku = otherRenewSku;
+					claudeCodeUser.setRenewOrderId(otherRenewRecord.getId());
+					claudeCodeUser.setRenewSkuId(otherRenewRecord.getRenewSkuId());
+				}
+			}
+			//还原镜像user
+			claudeCodeUser.setCodePoints(finalSku.getCodePoints());
+			claudeCodeUser.setCodeCreditRecovery(finalSku.getCodeCreditRecovery());
+			claudeCodeUser.setRenewExpiryTime(renewExpiryTime);
+			claudeCodeUserMapper.updateById(claudeCodeUser);
+			log.info("还原镜像claude code user套餐成功");
+			//将续费有效置为过期
+			renewExpiryRecord.setIsValid(true);
+			claudeCodeUserRenewExpiryRecordMapper.updateById(renewExpiryRecord);
+			//调用api更新claude code用户信息
+			claudeCodeService.updateClaudeCodeUserPackageInfo(claudeCodeUser, finalSku.getSpecVal());
+			return;
+		}
 		OrderDonRenewRecord orderDonRenewRecord = orderDonRenewRecordMapper.selectOne(Wrappers.lambdaQuery(OrderDonRenewRecord.class)
 				.eq(OrderDonRenewRecord::getOrderId, orderId)
+				.eq(OrderDonRenewRecord::getIsValid, Boolean.FALSE)
 				.last("limit 1"));
 		if (orderDonRenewRecord == null) {
 			return;
 		}
-		List<Long> userIdList = userBindRelationService.getRelationUserIdList(orderDon.getUserId(), null);
 		//Claude pro
 		if (orderDon.getGoodsId() == 75) {
 			ClaudeUser claudeUser = claudeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeUser.class)