| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282 |
- package com.cyksj.service.claude.impl;
- import cn.hutool.core.date.DateTime;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.lang.Assert;
- import cn.hutool.core.util.ObjectUtil;
- import cn.hutool.http.HttpException;
- import cn.hutool.http.HttpResponse;
- import cn.hutool.http.HttpUtil;
- import cn.hutool.http.Method;
- import cn.hutool.json.JSONObject;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.cyksj.common.constant.Constant;
- import com.cyksj.common.exception.BusinessRuntimeException;
- import com.cyksj.common.util.Jsons;
- import com.cyksj.common.util.StringUtil;
- import com.cyksj.mapper.*;
- import com.cyksj.mapper.claudecode.*;
- import com.cyksj.mapper.manage.distribute.DistributePointsExchangeMoneyMapper;
- import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
- import com.cyksj.model.dto.ClaudeCodeDeductDto;
- import com.cyksj.model.entity.*;
- import com.cyksj.model.manage.views.GroupsRelationView;
- import com.cyksj.model.request.ClaudeCodeApiKeysReq;
- import com.cyksj.model.request.ClaudeCodeCreditCardUseReq;
- import com.cyksj.model.request.ClaudeCodeDelReq;
- import com.cyksj.model.request.CreditResetReq;
- import com.cyksj.model.request.codex.CodexUserPackageReq;
- import com.cyksj.model.response.ClaudeCodeRewardDetailsResp;
- import com.cyksj.model.response.CreditResetResp;
- import com.cyksj.model.response.TimeRateConfigsResp;
- import com.cyksj.model.response.claudecode.ClaudeCodeResp;
- import com.cyksj.model.views.*;
- import com.cyksj.redis.RedisService;
- import com.cyksj.service.api.ClaudeCodexApiService;
- import com.cyksj.service.claude.ClaudeCodeService;
- import com.cyksj.service.codex.CodexService;
- import com.cyksj.service.user.UserBindRelationService;
- import com.ejlchina.searcher.BeanSearcher;
- import com.ejlchina.searcher.SearchResult;
- import com.ejlchina.searcher.param.Operator;
- import com.ejlchina.searcher.util.MapUtils;
- import com.github.rholder.retry.*;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.dao.DuplicateKeyException;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.*;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.TimeUnit;
- /**
- * 项目名: yhlxj11111111
- * 文件名: ClaudeCodeServiceImpl
- * 创建者: JavaZou
- * 创建时间:2025/8/8 10:55
- */
- @Service
- @RequiredArgsConstructor
- @Slf4j
- public class ClaudeCodeServiceImpl implements ClaudeCodeService {
- private final UserBindRelationService userBindRelationService;
- private final GroupsRelationMapper relationMapper;
- private final BeanSearcher beanSearcher;
- private final ClaudeCodeUserRenewExpiryRecordMapper claudeCodeUserRenewExpiryRecordMapper;
- private final ClaudeCodeUserMapper claudeCodeUserMapper;
- private final GoodsDonSkuMapper skuMapper;
- private final GroupsMapper groupsMapper;
- private final OrderDonMapper orderDonMapper;
- private final ClaudeCodeUserResetRecordMapper claudeCodeUserResetRecordMapper;
- private final ClaudeCodeUserCreditCardRecordMapper claudeCodeUserCreditCardRecordMapper;
- private final ClaudeCodeCreditCardMapper claudeCodeCreditCardMapper;
- private final UserMapper userMapper;
- private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;
- private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
- private final GoodsDonMapper goodsDonMapper;
- private final ClaudeCodeDayResetRecordMapper claudeCodeDayResetRecordMapper;
- private final RedisService redisService;
- private final CodexService codexService;
-
- private final CodexUserMapper codexUserMapper;
- private final ClaudeCodexApiService claudeCodexApiService;
- private final ClaudeCodeDeductOrderRelateMapper claudeCodeDeductOrderRelateMapper;
- @Override
- public void generateOrUpdateClaudeCodeUserInfo(Long orderId, Long relationId, Long userId, GoodsDonSku sku, Integer orderType) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getId, relationId).in(GroupsRelation::getUserId, userIdList));
- GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
- GoodsDonSku relationSku = skuMapper.selectById(groupsTrips.getSkuId());
- Long thisCodeOriSkuId = relationSku.getId();
- Long relationUserId = relation.getUserId();
- //此时车票的套餐规格积分
- Integer thisRelationCodeDayilyLimit = null;
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
- if (claudeCodeUser != null) {
- thisRelationCodeDayilyLimit = claudeCodeUser.getClaudeDailyLimit();
- }
- Date expiryTime = relation.getExpiryTime();
- Integer claudeDailyLimit = sku.getClaudeDailyLimit();
- Integer claudeQuota = sku.getClaudeQuota();
- Long skuId = sku.getId();
- Boolean isUpgrade = false;
- Date renewExpiryTime = null;
- //若是续费升级 记录此时续费升级的过期时间
- if (!ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
- //非车票原规格id 续费升级记录
- saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, skuId);
- //是否需要修改当前claude code user 套餐等级
- if (thisRelationCodeDayilyLimit != null && thisRelationCodeDayilyLimit <= claudeDailyLimit) {
- if (sku.getDays() != null) {
- renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
- } else {
- renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
- }
- isUpgrade = true;
- }
- }
- generateOrUpdateClaudeCodeUser(relationUserId, relationId, claudeDailyLimit, claudeQuota, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal(), userIdList);
- try {
- //获取最新的claude code user
- claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
- //生成claude code或更新用户套餐
- ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(relation.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), claudeCodeUser.getExpiryTime(), claudeCodeUser.getRelationId(), sku);
- if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
- //重试更新code userInfo数据
- setClaudeCodeUserRetryUpdateInfo(relationId);
- return;
- }
- //清缓存
- if (orderType != null && orderType == 2) {
- invalidateUserCache(relationUserId);
- }
- } catch (Exception e) {
- log.error("生成或更新claude code用户:{}套餐skuId:{} 失败,error_info:{}", userId, skuId, StringUtil.getErrorText(e));
- //重试更新code userInfo数据
- setClaudeCodeUserRetryUpdateInfo(relationId);
- }
- }
- private void generateOrUpdateClaudeCodeUser(Long relationUserId, Long relationId, Integer claudeDailyLimit, Integer claudeQuota, Date expiryTime, Boolean isUpgrade, Long orderId, Long renewSkuId, Date renewExpiryTime, String planName, List<Long> userIdList) {
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
- if (claudeCodeUser == null) {
- claudeCodeUser = new ClaudeCodeUser();
- }
- if (isUpgrade) {
- claudeCodeUser.setRenewOrderId(orderId);
- claudeCodeUser.setRenewSkuId(renewSkuId);
- claudeCodeUser.setRenewExpiryTime(renewExpiryTime);
- claudeCodeUser.setPlanName(planName);
- claudeCodeUser.setClaudeDailyLimit(claudeDailyLimit);
- claudeCodeUser.setClaudeQuota(claudeQuota);
- }
- claudeCodeUser.setUserId(relationUserId);
- claudeCodeUser.setRelationId(relationId);
- claudeCodeUser.setExpiryTime(expiryTime);
- if (claudeCodeUser.getId() == null) {
- claudeCodeUser.setPlanName(planName);
- claudeCodeUser.setClaudeDailyLimit(claudeDailyLimit);
- claudeCodeUser.setClaudeQuota(claudeQuota);
- //可重置次数
- Integer resetCount = claudeCodeUserResetRecordMapper.getUserResetCountByUserIds(userIdList);
- if (resetCount != null && resetCount > 0) {
- claudeCodeUser.setResetCount(resetCount);
- }
- }
- if (claudeCodeUser.getId() == null) {
- try {
- claudeCodeUserMapper.insert(claudeCodeUser);
- } catch (DuplicateKeyException e) {
- log.info("插入claude code user 重复");
- }
- } else claudeCodeUserMapper.updateById(claudeCodeUser);
- }
- @Override
- public ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
- Long userId = req.getUserId();
- if (checkClaudeCodeUser(userId)) {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
- req.setUserId(claudeCodeUserId);
- return claudeCodexApiService.createApiKeys(req);
- }
- throw new BusinessRuntimeException("您还没有claudecode账号");
- }
- @Override
- public void deleteApiKeysById(ClaudeCodeDelReq delReq) throws Exception {
- Long userId = delReq.getUserId();
- Long keyId = delReq.getKeyId();
- if (checkClaudeCodeUser(userId)) {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- claudeCodexApiService.deleteApiKeysById(claudeCodeUserId, keyId);
- }
- }
- @Override
- public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- if (claudeCodeUserId != null) {
- return claudeCodexApiService.getUserApiKeys(claudeCodeUserId);
- }
- return null;
- }
- @Override
- public ClaudeCodeResp getUserDashboard(Long userId) throws Exception {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- if (claudeCodeUserId != null) {
- String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/claude/users/%s/dashboard", claudeCodeUserId);
- ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
- return claudeCodeResp;
- }
- return null;
- }
- @Override
- public ClaudeCodeResp getUserBalance(Long userId) throws Exception {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- if (claudeCodeUserId != null) {
- String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/balance", claudeCodeUserId);
- ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
- return claudeCodeResp;
- }
- return null;
- }
- @Override
- public ClaudeCodeResp getCreditsAnalytics(Long userId, String start, String end, String tz, Integer page, Integer limit, String order, String type) throws Exception {
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
- if (start == null) {
- DateTime now = DateTime.now();
- start = DateUtil.offsetDay(now, -1).toString();
- end = now.toString();
- }
- if (claudeCodeUserId != null) {
- String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/claude/users/%s/analytics?start=%s&end=%s&tz=%s&page=%s&limit=%s&order=%s&type=%s", claudeCodeUserId, start, end, tz, page, limit, order, type);
- ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
- return claudeCodeResp;
- }
- return null;
- }
- /**
- * 用户缓存失效
- */
- @Override
- public void invalidateUserCache(Long userId) {
- String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/user/%s", userId);
- try {
- executeClaudeCodePostApi(url, null);
- } catch (Exception e) {
- }
- }
- @Override
- public ClaudeCodeUserInfoView getClaudeCodeUserSubsInfo(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- //是否有该车票
- GroupsRelationMirrorView groupsRelationMirrorView = beanSearcher.searchFirst(GroupsRelationMirrorView.class, MapUtils.builder()
- .field(GroupsRelationMirrorView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationMirrorView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
- CodexUser codexUser = null;
- CodexUserInfoView codexUserInfoView = null;
- //车票不存在
- if (groupsRelationMirrorView == null) {
- //套餐是否存在
- if (claudeCodeUser != null) {
- //清除用户套餐
- if (delUserPackages(claudeCodeUser.getUserId())) {
- claudeCodeUserMapper.deleteById(claudeCodeUser.getId());
- //codex
- codexUserMapper.delete(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, claudeCodeUser.getRelationId()).in(CodexUser::getUserId, userIdList));
- }
- }
- return null;
- }
- GoodsDonSku sku = null;
- if (claudeCodeUser == null) {
- OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
- .eq(OrderDon::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .eq(OrderDon::getRelationId, groupsRelationMirrorView.getId())
- .in(OrderDon::getUserId, userIdList)
- .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
- .orderByDesc(OrderDon::getId)
- .last("limit 1"));
- if (orderDon != null) {
- sku = skuMapper.selectById(orderDon.getSkuId());
- generateOrUpdateClaudeCodeUserInfo(orderDon.getId(), orderDon.getRelationId(), orderDon.getUserId(), sku, orderDon.getOrderType());
- claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
- } else {
- //试用车票
- Long skuId = groupsRelationMirrorView.getSkuId();
- sku = skuMapper.selectById(skuId);
- generateOrUpdateClaudeCodeUserInfo(null, groupsRelationMirrorView.getId(), groupsRelationMirrorView.getUserId(), sku, null);
- claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
- }
- }
- //续费升级
- if (claudeCodeUser.getRenewSkuId() != null) {
- sku = skuMapper.selectById(claudeCodeUser.getRenewSkuId());
- }
- if (sku == null) {
- sku = skuMapper.selectById(groupsRelationMirrorView.getSkuId());
- }
- if (claudeCodeUser != null) {
- claudeCodeUser.setPlanName(sku.getSpecVal());
- claudeCodeUser.setExpiryTime(groupsRelationMirrorView.getExpiryTime());
- claudeCodeUserMapper.updateById(claudeCodeUser);
- }
- //是否需要重试更新 cladueCode userInfo信息
- if (claudeCodeUser.getIsRetry()) {
- try {
- ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), claudeCodeUser.getExpiryTime(), claudeCodeUser.getRelationId(), sku);
- if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
- claudeCodeUser.setIsRetry(Boolean.TRUE);
- claudeCodeUserMapper.updateById(claudeCodeUser);
- } else {
- claudeCodeUser.setIsRetry(Boolean.FALSE);
- claudeCodeUserMapper.updateById(claudeCodeUser);
- }
- } catch (Exception e) {
- }
- }
- codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, claudeCodeUser.getRelationId()).in(CodexUser::getUserId, userIdList).last("limit 1"));
- if (codexUser == null) {
- //是否赠送codex
- if (sku.getIsCodex()) {
- CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
- .userId(claudeCodeUser.getUserId())
- .relationId(claudeCodeUser.getRelationId())
- .planName(sku.getCodexPlanName())
- .openaiDailyLimit(sku.getOpenaiDailyLimit())
- .openaiQuota(sku.getOpenaiQuota())
- .expiryTime(claudeCodeUser.getExpiryTime()).build();
- codexService.createOrUpdateUserPackage(codexPackageReq);
- }
- }
- return ClaudeCodeUserInfoView.builder()
- .planName(claudeCodeUser.getPlanName())
- .relationId(claudeCodeUser.getRelationId())
- .claudeDailyLimit(claudeCodeUser.getClaudeDailyLimit())
- .claudeQuota(claudeCodeUser.getClaudeQuota())
- .expiryTime(claudeCodeUser.getExpiryTime())
- .skuId(groupsRelationMirrorView.getSkuId())
- .renewSkuId(claudeCodeUser.getRenewSkuId())
- .renewOrderId(claudeCodeUser.getRenewOrderId())
- .renewExpiryTime(claudeCodeUser.getRenewExpiryTime())
- .highestUsage(sku.getHighestUsage())
- .build();
- }
- public ClaudeCodeResp createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer claudeDailyLimit, Integer claudeQuota, Date expiryTime, Long relationId, GoodsDonSku sku) throws Exception {
- Map<String, Object> parmas = new HashMap<>();
- parmas.put("plan_name", planName.replaceAll(";", ""));
- parmas.put("claude_daily_limit", claudeDailyLimit);
- parmas.put("claude_quota", claudeQuota);
- //服务类型
- parmas.put("service_type", "claude");
- if (sku != null && sku.getIsCodex()) {
- parmas.put("openai_daily_limit", sku.getOpenaiDailyLimit());
- parmas.put("openai_quota", sku.getOpenaiQuota());
- //组合
- parmas.put("service_type", "combined");
- } else {
- parmas.put("openai_daily_limit", 0);
- parmas.put("openai_quota", 0);
- //单独 claude类型
- parmas.put("service_type", "claude");
- }
- parmas.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
- String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
- ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(planUrl, Jsons.toJson(parmas));
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
- log.info("用户claude code用户:{}套餐:{}创建或更新失败,info:{}", userId, planName, claudeCodeResp.getMessage());
- } else {
- //是否赠送codex
- if (sku != null && sku.getIsCodex()) {
- CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
- .userId(userId)
- .relationId(relationId)
- .planName(sku.getCodexPlanName())
- .openaiDailyLimit(sku.getOpenaiDailyLimit())
- .openaiQuota(sku.getOpenaiQuota())
- .expiryTime(expiryTime).build();
- codexService.createOrUpdateUserPackage(codexPackageReq);
- } else {
- codexService.delCodexUser(userId, relationId);
- }
- }
- return claudeCodeResp;
- }
- /**
- * 校验是否是claude code用户
- * @param userId
- * @return
- */
- @Override
- public Boolean checkClaudeCodeUser(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- Integer count = relationMapper.selectCountByGoodsId(userIdList, Constant.CLAUDE_CODE_GOODS_ID, DateTime.now());
- return count > 0;
- }
- @Override
- public void updateClaudeCodeUserPackageInfo(ClaudeCodeUser claudeCodeUser, Date expiryTime, GoodsDonSku sku) {
- try {
- ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(claudeCodeUser.getUserId(), claudeCodeUser.getPlanName(), claudeCodeUser.getClaudeDailyLimit(), claudeCodeUser.getClaudeQuota(), expiryTime, claudeCodeUser.getRelationId(), sku);
- if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
- //重试标记
- claudeCodeUser.setIsRetry(Boolean.TRUE);
- claudeCodeUserMapper.updateById(claudeCodeUser);
- return;
- }
- //刷新缓存
- invalidateUserCache(claudeCodeUser.getUserId());
- } catch (Exception e) {
- claudeCodeUser.setIsRetry(Boolean.TRUE);
- claudeCodeUserMapper.updateById(claudeCodeUser);
- }
- }
- @Override
- public Boolean delUserPackages(Long userId) {
- String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=claude", userId);
- try {
- ClaudeCodeResp claudeCodeResp = executeClaudeCodeDeletedApi(url);
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
- log.error("删除用户:{} claude code套餐失败:{}", userId, claudeCodeResp.getMessage());
- return Boolean.FALSE;
- }
- return Boolean.TRUE;
- } catch (Exception e) {
- log.error("删除用户:{} claude code套餐报错:{}", userId, StringUtil.getErrorText(e));
- }
- return Boolean.FALSE;
- }
- @Override
- public void handleClaudeCodeUserPackageSku(GroupsRelation relation, GoodsDonSku sku, Long orderId) {
- generateOrUpdateClaudeCodeUserInfo(orderId, relation.getId(), relation.getUserId(), sku, 2);
- }
- @Override
- public TimeRateConfigsResp getAllConfigs() {
- try {
- String url = Constant.CLAUDE_CODE_API_PREFIX + "api/time-multiplier/configs";
- ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
- return Jsons.parseObject(claudeCodeResp.getData(), TimeRateConfigsResp.class);
- } catch (Exception e) {
- log.error("获取时间倍率配置列表失败", e);
- throw BusinessRuntimeException.getInstance("获取时间倍率配置列表失败");
- }
- }
- @Override
- public CreditResetResp resetUserCredits(Long userId, CreditResetReq req) throws Exception {
- if (userId <= 0) {
- throw BusinessRuntimeException.getInstance("用户ID无效");
- }
- String url = Constant.CLAUDE_CODE_API_PREFIX + "api/users/" + userId + "/credits/reset";
- String body = req != null ? Jsons.toJson(req) : "{}";
- ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(url, body);
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
- throw BusinessRuntimeException.getInstance("重置次数失败");
- }
- return Jsons.parseObject(claudeCodeResp.getData(), CreditResetResp.class);
- }
- /**
- * 验证时间范围
- */
- private void validateTimeRange(Integer startHour, Integer endHour) {
- if (startHour == null || endHour == null) {
- throw BusinessRuntimeException.getInstance("开始和结束小时不能为空");
- }
- if (startHour < 0 || startHour > 23) {
- throw BusinessRuntimeException.getInstance("开始小时必须在0-23之间");
- }
- if (endHour < 0 || endHour > 23) {
- throw BusinessRuntimeException.getInstance("结束小时必须在0-23之间");
- }
- }
- /**
- * 获取claude code用户id
- */
- public Long getClaudeCodeUserId(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- GroupsRelationMirrorView groupsRelationMirrorView = beanSearcher.searchFirst(GroupsRelationMirrorView.class, MapUtils.builder()
- .field(GroupsRelationMirrorView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationMirrorView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- if (groupsRelationMirrorView != null) {
- return groupsRelationMirrorView.getUserId();
- }
- return null;
- }
- /**
- * claude code GET请求
- */
- public ClaudeCodeResp executeClaudeCodeGetApi(String url) {
- Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
- try {
- return build.call(() -> {
- try {
- HttpResponse execute = HttpUtil.createGet(url)
- .header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
- .setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
- .execute();
- ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
- if (!Constant.SUCCESS.equals(resp.getMessage())) {
- log.error("claude code GET URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (HttpException e) {
- return null;
- }
- });
- } catch (ExecutionException | RetryException e) {
- log.error("重试调用claude code GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- throw BusinessRuntimeException.getInstance("接口请求失败");
- }
- }
- /**
- * claude code Post请求
- */
- public ClaudeCodeResp executeClaudeCodePostApi(String url, String body) {
- Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
- try {
- return build.call(() -> {
- try {
- HttpResponse execute = HttpUtil.createPost(url)
- .header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
- .setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
- .body(body)
- .execute();
- ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
- if (!Constant.SUCCESS.equals(resp.getMessage())) {
- log.error("claude code POST URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (Exception e) {
- return null;
- }
- });
- } catch (ExecutionException | RetryException e) {
- log.info("重试调用claude code POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- throw BusinessRuntimeException.getInstance("接口请求失败");
- }
- }
- /**
- * claude code DELETE请求
- */
- public ClaudeCodeResp executeClaudeCodeDeletedApi(String url) {
- Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
- try {
- return build.call(() -> {
- try {
- HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
- ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
- if (!Constant.SUCCESS.equals(resp.getMessage())) {
- log.error("claude code DELETE URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (HttpException e) {
- return null;
- }
- });
- } catch (ExecutionException | RetryException e) {
- log.error("重试调用claude code DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- throw BusinessRuntimeException.getInstance("接口请求失败");
- }
- }
- /**
- * 记录claude code 续费升级的过期时间
- */
- private void saveClaudeCodeRenewExpiryRecord(Long orderId, Long relationUserId, Long relationId, Long skuId) {
- ClaudeCodeUserRenewExpiryRecord renewExpiryRecord = new ClaudeCodeUserRenewExpiryRecord();
- renewExpiryRecord.setOrderId(orderId);
- renewExpiryRecord.setUserId(relationUserId);
- renewExpiryRecord.setRelationId(relationId);
- renewExpiryRecord.setRenewSkuId(skuId);
- claudeCodeUserRenewExpiryRecordMapper.insert(renewExpiryRecord);
- }
- /**
- * claude code、codex user用户信息重试更新信息
- */
- public void setClaudeCodeUserRetryUpdateInfo(Long relationId) {
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
- if (claudeCodeUser != null) {
- claudeCodeUser.setIsRetry(Boolean.TRUE);
- claudeCodeUserMapper.updateById(claudeCodeUser);
- }
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
- if (codexUser != null) {
- codexUser.setIsRetry(Boolean.TRUE);
- codexUserMapper.updateById(codexUser);
- }
- }
- public Retryer getApiRetryer(Integer sleepSecond, Integer attemptNum) {
- Retryer build = RetryerBuilder.newBuilder()
- .retryIfException()
- //运行时异常重试
- .retryIfRuntimeException()
- //false重试
- .retryIfResult(res -> res == null)
- //1s 间隔
- .withWaitStrategy(WaitStrategies.fixedWait(sleepSecond, TimeUnit.SECONDS))
- //停止策略 : 尝试请求3次
- .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNum)).build();
- return build;
- }
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public void useResetCount(Long userId) throws Exception {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- if (claudeCodeUser == null) {
- throw new BusinessRuntimeException("用户未开通Claude Code服务");
- }
- Integer currentResetCount = claudeCodeUser.getResetCount();
- if (currentResetCount == null || currentResetCount <= 0) {
- throw BusinessRuntimeException.getInstance("可用重置次数为0");
- }
- claudeCodeUser.setResetCount(currentResetCount - 1);
- int updateResult = claudeCodeUserMapper.update(claudeCodeUser,
- Wrappers.lambdaUpdate(ClaudeCodeUser.class)
- .eq(ClaudeCodeUser::getId, claudeCodeUser.getId())
- .eq(ClaudeCodeUser::getResetCount, currentResetCount)
- );
- if (updateResult > 0) {
- log.info("用户{}成功使用重置次数,剩余次数:{}", userId, currentResetCount - 1);
- //重置用户次数
- CreditResetReq creditResetReq = new CreditResetReq();
- creditResetReq.setDescription("用户使用重置次数");
- //调用API重置用户次数
- resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);
- ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
- resetRecord.setUserId(userId);
- resetRecord.setNum(-1);
- resetRecord.setResetReason("使用重置次数");
- claudeCodeUserResetRecordMapper.insert(resetRecord);
- } else {
- throw BusinessRuntimeException.getInstance("使用重置次数失败");
- }
- }
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public void useCreditCard(ClaudeCodeCreditCardUseReq req) throws Exception {
- Long userId = req.getUserId();
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- if (claudeCodeUser == null) {
- throw new BusinessRuntimeException("用户未开通Claude Code服务");
- }
- ClaudeCodeCreditCard creditCard = claudeCodeCreditCardMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
- .eq(ClaudeCodeCreditCard::getStatus, 0)
- .in(ClaudeCodeCreditCard::getUserId, userIdList)
- .last("limit 1")
- );
- if (creditCard == null) {
- throw new BusinessRuntimeException("无可用补充卡");
- }
- if (creditCard.getStatus() != 0) {
- if (creditCard.getStatus() == 1) {
- throw new BusinessRuntimeException("补充卡已被使用");
- } else if (creditCard.getStatus() == 2) {
- throw new BusinessRuntimeException("补充卡已过期");
- } else {
- throw new BusinessRuntimeException("补充卡状态异常");
- }
- }
- String cardNumber = creditCard.getCardNumber();
- if (creditCard.getExpiryTime() != null && creditCard.getExpiryTime().before(new Date())) {
- creditCard.setStatus(2);
- claudeCodeCreditCardMapper.updateById(creditCard);
- throw new BusinessRuntimeException("补充卡已过期");
- }
- ClaudeCodeResp dashboard = getUserDashboard(userId);
- JSONObject data = Jsons.parseObject(dashboard.getData(), JSONObject.class);
- BigDecimal daily_remaining = data.getBigDecimal("daily_remaining");
- BigDecimal daily_total = BigDecimal.valueOf(claudeCodeUser.getClaudeDailyLimit());
- //超出积分 异常
- if (daily_remaining.add(BigDecimal.valueOf(creditCard.getCreditAmount())).compareTo(daily_total) > 0) {
- throw BusinessRuntimeException.getInstance("目前使用只能补充到{0},建议您消耗更多额度后再补充使用", daily_total);
- }
- BigDecimal beforeCodePoints = daily_remaining;
- BigDecimal addCodePoints = BigDecimal.valueOf(creditCard.getCreditAmount());
- BigDecimal afterCodePoints = beforeCodePoints.add(addCodePoints);
- creditCard.setStatus(1);
- creditCard.setUsedUserId(userId);
- creditCard.setUsedTime(new Date());
- int cardUpdateResult = claudeCodeCreditCardMapper.update(creditCard,
- Wrappers.lambdaUpdate(ClaudeCodeCreditCard.class)
- .eq(ClaudeCodeCreditCard::getId, creditCard.getId())
- .eq(ClaudeCodeCreditCard::getStatus, 0)
- );
- if (cardUpdateResult > 0) {
- ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
- creditCardRecord.setUserId(userId);
- creditCardRecord.setBeforeCodePoints(beforeCodePoints);
- creditCardRecord.setAddCodePoints(addCodePoints);
- creditCardRecord.setAfterCodePoints(afterCodePoints);
- creditCardRecord.setCardNumber(cardNumber);
- //使用一次
- creditCardRecord.setNum(-1);
- creditCardRecord.setUseReason("使用补充卡");
- claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
- log.info("用户{}成功使用补充卡{},增加{}预算", userId, cardNumber, addCodePoints);
- //调用API调整用户积分
- adjClaudeCodeUserPoints(claudeCodeUser.getUserId(), creditCard.getCreditAmount(), "adjustment", "用户使用补充卡");
- } else {
- throw new BusinessRuntimeException("补充卡使用失败,请重试");
- }
- }
- @Override
- public SearchResult<ClaudeCodeUserResetRecordView> getUserResetRecords(Long userId, Integer page, Integer limit) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- return beanSearcher.search(ClaudeCodeUserResetRecordView.class, MapUtils.builder()
- .field(ClaudeCodeUserResetRecordView::getUserId, userIdList).op(Operator.InList)
- .page(page, limit)
- .orderBy(ClaudeCodeUserResetRecordView::getCreatedTime).desc()
- .build());
- }
- @Override
- public SearchResult<ClaudeCodeUserCreditCardRecordView> getUserCreditCardRecords(Long userId, Integer page, Integer limit) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- return beanSearcher.search(ClaudeCodeUserCreditCardRecordView.class, MapUtils.builder()
- .field(ClaudeCodeUserCreditCardRecordView::getUserId, userIdList).op(Operator.InList)
- .page(page, limit)
- .orderBy(ClaudeCodeUserCreditCardRecordView::getCreatedTime).desc()
- .build());
- }
- @Override
- public ClaudeCodeRewardDetailsResp getUserRewardDetails(Long userId, Boolean general) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- ClaudeCodeRewardDetailsResp response = new ClaudeCodeRewardDetailsResp();
- // 获取用户Claude Code信息
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- // 设置可重置次数
- if (claudeCodeUser != null) {
- Integer resetCount = claudeCodeUser.getResetCount();
- response.setResetCount(resetCount != null ? resetCount : 0);
- } else {
- response.setResetCount(0);
- }
- // 获取可用补充卡数量
- Integer availableCreditCards = claudeCodeCreditCardMapper.selectCount(
- Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
- .eq(ClaudeCodeCreditCard::getStatus, 0)
- .in(ClaudeCodeCreditCard::getUserId, userIdList)
- .isNull(ClaudeCodeCreditCard::getUsedUserId)
- );
- response.setAvailableCreditCards(availableCreditCards != null ? availableCreditCards : 0);
- //是否是普通推广
- if (general != null && general) {
- //提现门槛
- DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).last("limit 1"));
- response.setThresholdMoney(BigDecimal.valueOf(distributePointsExchangeMoney.getMinPoints()).divide(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).multiply(distributePointsExchangeMoney.getMoney()));
- // 获取分销相关数据
- try {
- User user = userMapper.selectById(userId);
- List<DistributeWaitingSendPoints> distributeWaitingSendPoints = distributeWaitingSendPointsMapper.selectList(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class).eq(DistributeWaitingSendPoints::getSendStatus, DistributeWaitingSendPoints.Status.waiting).eq(DistributeWaitingSendPoints::getSharedId, userId).select(DistributeWaitingSendPoints::getPoints));
- BigDecimal waitingPoints = BigDecimal.ZERO;
- if (!distributeWaitingSendPoints.isEmpty()) {
- Optional<BigDecimal> points = distributeWaitingSendPoints.stream().map(DistributeWaitingSendPoints::getPoints).reduce(BigDecimal::add);
- if (points.isPresent()) {
- waitingPoints = points.get();
- }
- }
- GoodsDon goodsDon = goodsDonMapper.selectById(Constant.CLAUDE_CODE_GOODS_ID);
- //cc 分销平台比例
- if (goodsDon != null) {
- response.setRate(goodsDon.getRate());
- }
- if (user.getPoints().compareTo(BigDecimal.ZERO) <= 0 && waitingPoints.compareTo(BigDecimal.ZERO) <= 0) {
- response.setGotMoney(BigDecimal.ZERO);
- response.setWaitingMoney(BigDecimal.ZERO);
- } else {
- BigDecimal points = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
- BigDecimal money = distributePointsExchangeMoney.getMoney();
- BigDecimal oneHundred = BigDecimal.valueOf(100);
- if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
- response.setGotMoney(user.getPoints().divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.HALF_DOWN));
- }
- if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
- response.setWaitingMoney(waitingPoints.divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
- }
- }
- } catch (Exception e) {
- log.warn("获取用户{}分销数据异常", userId, e);
- // 设置默认值
- response.setGotMoney(BigDecimal.ZERO);
- response.setWaitingMoney(BigDecimal.ZERO);
- }
- }
- return response;
- }
- @Override
- public void sendCreditCard(Long orderId, Long userId, Integer points, String cardNumber, String remark) {
- //暂时不送积分卡
- if (true) {
- return;
- }
- ClaudeCodeCreditCard creditCard = new ClaudeCodeCreditCard();
- creditCard.setUserId(userId);
- creditCard.setOrderId(orderId);
- creditCard.setCardNumber(cardNumber);
- creditCard.setCreditAmount(points);
- creditCard.setRemark(remark);
- claudeCodeCreditCardMapper.insert(creditCard);
- //补充卡明细
- ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
- creditCardRecord.setUserId(userId);
- creditCardRecord.setCardNumber(cardNumber);
- creditCardRecord.setUseReason(remark);
- creditCardRecord.setNum(1);
- creditCardRecord.setAddCodePoints(BigDecimal.valueOf(points));
- claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
- }
- @Override
- public void adjUserRestNum(Long orderId, Long userId, Integer num, String remark) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- // 获取用户Claude Code信息
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- if (claudeCodeUser == null) {
- log.info("claude code user不存在");
- return;
- }
- Integer resetCount = claudeCodeUser.getResetCount();
- claudeCodeUser.setResetCount(resetCount + num);
- if (claudeCodeUser.getResetCount() < 0) {
- return;
- }
- int update = 0;
- while (update == 0) {
- update = claudeCodeUserMapper.update(claudeCodeUser, Wrappers.lambdaUpdate(ClaudeCodeUser.class).eq(ClaudeCodeUser::getUserId, claudeCodeUser.getUserId()).eq(ClaudeCodeUser::getResetCount, resetCount));
- if (update == 0) {
- claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- if (claudeCodeUser == null) {
- break;
- }
- resetCount = claudeCodeUser.getResetCount();
- claudeCodeUser.setResetCount(resetCount + num);
- if (claudeCodeUser.getResetCount() < 0) {
- break;
- }
- }
- //记录获取重置次数记录
- ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
- resetRecord.setOrderId(orderId);
- resetRecord.setUserId(userId);
- resetRecord.setResetReason(remark);
- resetRecord.setNum(num);
- claudeCodeUserResetRecordMapper.insert(resetRecord);
- }
- }
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public void useDayResetCount(Long userId) throws Exception {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- // 获取用户Claude Code信息
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
- Wrappers.lambdaQuery(ClaudeCodeUser.class)
- .in(ClaudeCodeUser::getUserId, userIdList)
- .last("limit 1")
- );
- if (claudeCodeUser == null) {
- log.info("claude code user不存在");
- return;
- }
- //非标准版、专业版 不给使用
- if (claudeCodeUser.getClaudeDailyLimit() < 5000) {
- return;
- }
- Integer selectCount = claudeCodeDayResetRecordMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeDayResetRecord.class).in(ClaudeCodeDayResetRecord::getUserId, userIdList).gt(ClaudeCodeDayResetRecord::getCreatedTime, DateUtil.beginOfDay(DateTime.now())));
- //今日使用为0
- if (selectCount == 0) {
- String idxKey = "cc:uid:" + userId;
- try {
- if (redisService.setNx(idxKey, userId, 5l)) {
- //重置用户次数
- CreditResetReq creditResetReq = new CreditResetReq();
- creditResetReq.setDescription("用户使用每日重置");
- //调用API重置用户次数
- resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);
- ClaudeCodeDayResetRecord claudeCodeDayResetRecord = new ClaudeCodeDayResetRecord();
- claudeCodeDayResetRecord.setUserId(userId);
- claudeCodeDayResetRecord.setRelationId(claudeCodeUser.getRelationId());
- claudeCodeDayResetRecordMapper.insert(claudeCodeDayResetRecord);
- }
- } finally {
- if (redisService.hasKey(idxKey)) {
- redisService.del(idxKey);
- }
- }
- }
- }
- @Override
- public Boolean getUserSubs(long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- //是否有该车票
- GroupsRelationMirrorView groupsRelationMirrorView = beanSearcher.searchFirst(GroupsRelationMirrorView.class, MapUtils.builder()
- .field(GroupsRelationMirrorView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationMirrorView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
- //车票不存在
- if (groupsRelationMirrorView == null) {
- //套餐是否存在
- if (claudeCodeUser != null) {
- //清除用户套餐
- if (delUserPackages(claudeCodeUser.getUserId())) {
- claudeCodeUserMapper.deleteById(claudeCodeUser.getId());
- }
- }
- return false;
- }
- return true;
- }
- @Override
- public ClaudeCodeDeductDto getDeductSkuMoney(Long userId, Long relationId, Long skuId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- GroupsRelationView relationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
- .field(GroupsRelationView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .field(GroupsRelationView::getId, relationId)
- .field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- ClaudeCodeDeductDto claudeCodeDeductDto = new ClaudeCodeDeductDto();
- if (relationView == null) {
- claudeCodeDeductDto.setDeductMoney(BigDecimal.ZERO);
- return claudeCodeDeductDto;
- }
- ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
- GoodsDonSku upgradeSku = skuMapper.selectById(skuId);
- if (upgradeSku.getGoodsId() != Constant.CLAUDE_CODE_GOODS_ID) {
- claudeCodeDeductDto.setDeductMoney(BigDecimal.ZERO);
- return claudeCodeDeductDto;
- }
- GoodsDonSku relationPresentSku = null;
- Long renewSkuId = claudeCodeUser.getRenewSkuId();
- if (renewSkuId != null) {
- relationPresentSku = skuMapper.selectById(renewSkuId);
- }
- if (relationPresentSku == null) {
- relationPresentSku = skuMapper.selectById(relationView.getSkuId());
- }
- if (upgradeSku.getClaudeQuota().intValue() < relationPresentSku.getClaudeQuota().intValue()) {
- claudeCodeDeductDto.setDeductMoney(BigDecimal.ZERO);
- return claudeCodeDeductDto;
- }
- claudeCodeDeductDto = getDeductMoney(relationId, relationView.getSkuId(), claudeCodeUser.getRenewSkuId(), claudeCodeUser.getRenewOrderId(), claudeCodeUser.getRenewExpiryTime(), relationView.getStartTime(), relationView.getExpiryTime(), DateTime.now(), userIdList, upgradeSku);
- return claudeCodeDeductDto;
- }
- @Override
- public ClaudeCodeDeductDto getDeductMoney(Long relationId, Long relationSkuId, Long renewSkuId, Long renewOrderId, Date renewExpiryTime, Date relationStartTime, Date relationExpiryTime, DateTime now, List<Long> userIdList, GoodsDonSku upgradeSku) {
- BigDecimal deductMoney = BigDecimal.ZERO;
- //一个月当30天算单价 往上取整
- //续费规格
- ClaudeCodeDeductDto claudeCodeDeductDto = new ClaudeCodeDeductDto();
- if (renewSkuId != null && renewExpiryTime.compareTo(now) > 0) {
- OrderDon renewOrderDon = orderDonMapper.selectById(renewOrderId);
- BigDecimal orderMoney = renewOrderDon.getMoney().add(Optional.ofNullable(renewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
- GoodsDonSku presentSku = skuMapper.selectById(renewSkuId);
- if (orderMoney.compareTo(BigDecimal.ZERO) == 0) {
- //存在升级后的0元订单 即兑换码订单 不让抵扣
- claudeCodeDeductDto.setDeductMoney(BigDecimal.ZERO);
- return claudeCodeDeductDto;
- } else {
- Long betweenDay = DateUtil.betweenDay(now, renewExpiryTime, false) + 1;
- //当天购买的按规格原价抵扣
- BigDecimal renewDeductMoney;
- if (now.toDateStr().equals(DateUtil.format(renewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
- renewDeductMoney = orderMoney;
- deductMoney = deductMoney.add(renewDeductMoney);
- if (presentSku.getDays() != null) {
- relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -presentSku.getDays());
- } else {
- relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -presentSku.getMonths());
- }
- } else {
- //此次续费规格单价
- BigDecimal single = getPayOrderSingle(orderMoney, presentSku);
- //该车票抵扣金额
- renewDeductMoney = single.multiply(BigDecimal.valueOf(betweenDay));
- log.info("车票id:{}目前续费升级规格可抵扣的金额为:{}", relationId, renewDeductMoney);
- deductMoney = deductMoney.add(renewDeductMoney);
- relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -betweenDay.intValue());
- }
- }
- //上一个续费升级规格
- List<OrderDon> orderDOns = claudeCodeUserRenewExpiryRecordMapper.getOtherRenewSkuOrders(renewOrderId, relationId, userIdList);
- OrderDon presentRenewOrderDon = renewOrderDon;
- for (OrderDon thisRenewOrderDon : orderDOns) {
- Long skuId = thisRenewOrderDon.getSkuId();
- GoodsDonSku thisRenewSku = skuMapper.selectById(skuId);
- BigDecimal thisOrderMoney = thisRenewOrderDon.getMoney().add(Optional.ofNullable(thisRenewOrderDon.getBalance()).orElse(BigDecimal.ZERO));
- if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
- //存在升级后的0元订单 即兑换码订单 不让抵扣
- claudeCodeDeductDto.setDeductMoney(BigDecimal.ZERO);
- return claudeCodeDeductDto;
- }
- //当天购买的按规格原价抵扣
- BigDecimal thisRenewDeductMoney = BigDecimal.ZERO;
- if (now.toDateStr().equals(DateUtil.format(thisRenewOrderDon.getCreatedTime(), "yyyy-MM-dd"))) {
- thisRenewDeductMoney = thisOrderMoney;
- deductMoney = deductMoney.add(thisRenewDeductMoney);
- if (thisRenewSku.getDays() != null) {
- relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisRenewSku.getDays());
- } else {
- relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -thisRenewSku.getMonths());
- }
- } else {
- //此次续费订单过期时间
- Date thisOrderExpiryTime;
- if (thisRenewSku.getDays() != null) {
- thisOrderExpiryTime = DateUtil.offsetDay(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getDays());
- } else {
- thisOrderExpiryTime = DateUtil.offsetMonth(thisRenewOrderDon.getCreatedTime(), thisRenewSku.getMonths());
- }
- //续费同规格不处理
- if (!ObjectUtil.equal(thisRenewOrderDon.getSkuId(), presentRenewOrderDon.getSkuId())) {
- //先扣除已使用的天数
- //相差多少天
- Long thisRenewBetDay = DateUtil.betweenDay(thisRenewOrderDon.getCreatedTime(), presentRenewOrderDon.getCreatedTime(), false);
- //扣除已使用的
- thisOrderExpiryTime = DateUtil.offsetDay(thisOrderExpiryTime, -thisRenewBetDay.intValue());
- }
- //此订单过期时间
- if (thisOrderExpiryTime.compareTo(now) > 0) {
- //距离过期还剩多少天
- Long thisDeductBetweenDay = DateUtil.betweenDay(now, thisOrderExpiryTime, false) + 1;
- if (thisDeductBetweenDay != 0) {
- //此次续费规格单价
- BigDecimal single = getPayOrderSingle(thisOrderMoney, thisRenewSku);
- //该车票抵扣金额
- thisRenewDeductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
- deductMoney = deductMoney.add(thisRenewDeductMoney);
- }
- //目前级别续费订单
- presentRenewOrderDon = thisRenewOrderDon;
- relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -thisDeductBetweenDay.intValue());
- }
- }
- log.info("车票id:{}目前次一级规格:{}可抵扣的金额为:{}", relationId, thisRenewSku.getSpecVal(), thisRenewDeductMoney);
- }
- }
- if (relationExpiryTime.after(now)) {
- //该车票抵扣金额
- BigDecimal deductMoneyFromTicket = getDeductMoneyFromTicket(relationId, userIdList, relationSkuId, now, relationStartTime, relationExpiryTime);
- deductMoney = deductMoney.add(deductMoneyFromTicket);
- }
- log.info("车票id:{}最终到期时间为:{}车票可返回 抵扣金额:{}", relationId, DateUtil.format(relationExpiryTime, "yyyy-MM-dd HH:mm:ss"), deductMoney);
- //超出可抵扣的金额 直接返回
- if (deductMoney.compareTo(upgradeSku.getPrice()) >= 0) {
- BigDecimal overMoney = deductMoney.subtract(upgradeSku.getPrice());
- //超过抵扣金额可换延长会员多少天
- //每天单价
- BigDecimal daySingle = upgradeSku.getPrice().divide(BigDecimal.valueOf(upgradeSku.getMonths())).divide(BigDecimal.valueOf(30), 0, RoundingMode.DOWN);
- //超出部分可换取多少天 低于每天单价为0天
- BigDecimal extendsDays = overMoney.divide(daySingle, 0, RoundingMode.UP);
- claudeCodeDeductDto.setExtendsDays(extendsDays.intValue());
- }
- claudeCodeDeductDto.setDeductMoney(deductMoney);
- return claudeCodeDeductDto;
- }
- private void adjClaudeCodeUserPoints(Long userId, Integer points, String type, String description) throws Exception {
- String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/claude/users/%s/limit", userId);
- Map<String, Object> parmas = new HashMap<>();
- parmas.put("amount", points);
- parmas.put("type", type);
- parmas.put("description", description);
- ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
- throw BusinessRuntimeException.getInstance("使用补充卡失败");
- }
- }
- /**
- * 获取订单单价
- */
- public BigDecimal getPayOrderSingle(BigDecimal orderMoney, GoodsDonSku sku) {
- //此次续费规格单价
- BigDecimal single;
- //区分天/月
- if (sku.getDays() != null) {
- single = orderMoney.divide(BigDecimal.valueOf(sku.getDays()), 0, RoundingMode.HALF_UP);
- } else {
- single = orderMoney.divide(BigDecimal.valueOf(sku.getMonths()).multiply(BigDecimal.valueOf(30)), 0, RoundingMode.HALF_UP);
- }
- return single;
- }
- /**
- * 获取车票可抵扣金额
- */
- public BigDecimal getDeductMoneyFromTicket(Long relationId, List<Long> userIdList, Long skuId, DateTime now, Date relationStartTime, Date relationExpiryTime) {
- List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
- .eq(OrderDon::getRelationId, relationId)
- .in(OrderDon::getUserId, userIdList)
- .eq(OrderDon::getSkuId, skuId)
- .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
- .orderByDesc(OrderDon::getId));
- //部分退款
- if (orderDonList.isEmpty()) {
- orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
- .eq(OrderDon::getRelationId, relationId)
- .in(OrderDon::getUserId, userIdList)
- .eq(OrderDon::getSkuId, skuId)
- .notIn(OrderDon::getStatus, Constant.noOrderStatus)
- .orderByDesc(OrderDon::getId));
- }
- //未有订单 返回抵扣金额0
- if (orderDonList.isEmpty()) {
- return BigDecimal.ZERO;
- }
- //原车票订单总实付金额
- BigDecimal totalOrderMoney = BigDecimal.ZERO;
- //原车票订单总天数
- Integer totalDays = 0;
- for (OrderDon orderDon : orderDonList) {
- GoodsDonSku sku = skuMapper.selectById(skuId);
- BigDecimal thisOrderMoney = orderDon.getMoney().add(Optional.ofNullable(orderDon.getBalance()).orElse(BigDecimal.ZERO)).subtract(Optional.ofNullable(orderDon.getRefundMoney()).orElse(BigDecimal.ZERO));
- if (thisOrderMoney.compareTo(BigDecimal.ZERO) == 0) {
- if (sku.getDays() != null) {
- relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -sku.getDays());
- } else {
- relationExpiryTime = DateUtil.offsetMonth(relationExpiryTime, -sku.getMonths());
- }
- continue;
- }
- totalOrderMoney = totalOrderMoney.add(thisOrderMoney);
- //总时间
- if (sku.getDays() != null) {
- totalDays += sku.getDays();
- } else {
- totalDays += sku.getMonths() * 30;
- }
- ClaudeCodeDeductOrderRelate claudeCodeDeductOrderRelate = claudeCodeDeductOrderRelateMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeDeductOrderRelate.class).eq(ClaudeCodeDeductOrderRelate::getOrderId, orderDon.getId()).last("limit 1"));
- if (claudeCodeDeductOrderRelate != null) {
- totalOrderMoney = totalOrderMoney.add(claudeCodeDeductOrderRelate.getDeductMoney());
- }
- //原订单数
- if (orderDonList.size() == 1) {
- //此次订单过期时间
- Date thisOrderExpiryTime;
- if (sku.getDays() != null) {
- thisOrderExpiryTime = DateUtil.offsetDay(orderDon.getCreatedTime(), sku.getDays());
- } else {
- thisOrderExpiryTime = DateUtil.offsetMonth(orderDon.getCreatedTime(), sku.getMonths());
- }
- //当天购买的按规格原价抵扣
- if (now.toDateStr().equals(DateUtil.format(relationStartTime, "yyyy-MM-dd")) && (DateUtil.betweenDay(thisOrderExpiryTime, relationExpiryTime, true) == 0)) {
- return totalOrderMoney;
- }
- }
- }
- //总天数为0 不抵扣
- if (totalDays == 0) {
- return BigDecimal.ZERO;
- }
- Long thisDeductBetweenDay = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
- BigDecimal single = totalOrderMoney.divide(BigDecimal.valueOf(totalDays), 0, RoundingMode.HALF_UP);
- //该车票抵扣金额
- BigDecimal deductMoney = single.multiply(BigDecimal.valueOf(thisDeductBetweenDay));
- if (deductMoney.compareTo(totalOrderMoney) > 0) {
- deductMoney = totalOrderMoney;
- }
- return deductMoney;
- }
- }
|