|
|
@@ -2,22 +2,35 @@ 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.http.HttpResponse;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
import cn.hutool.http.Method;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.cyksj.common.constant.Constant;
|
|
|
import com.cyksj.common.exception.BusinessRuntimeException;
|
|
|
+import com.cyksj.common.snowflake.Sequence;
|
|
|
import com.cyksj.common.util.Jsons;
|
|
|
import com.cyksj.common.util.StringUtil;
|
|
|
+import com.cyksj.dto.RedisKey;
|
|
|
import com.cyksj.mapper.*;
|
|
|
+import com.cyksj.mapper.codex.CodexDeductRecordMapper;
|
|
|
+import com.cyksj.mapper.codex.CodexUserRenewExpiryRecordMapper;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
+import com.cyksj.model.manage.views.GroupsRelationView;
|
|
|
+import com.cyksj.model.request.CodexUpgradePayReq;
|
|
|
import com.cyksj.model.request.UpdateDailyLimitRequest;
|
|
|
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.redis.RedisService;
|
|
|
import com.cyksj.service.codex.CodexService;
|
|
|
+import com.cyksj.service.groups.GroupsFuncService;
|
|
|
import com.cyksj.service.user.UserBindRelationService;
|
|
|
+import com.ejlchina.searcher.BeanSearcher;
|
|
|
+import com.ejlchina.searcher.param.Operator;
|
|
|
+import com.ejlchina.searcher.util.MapUtils;
|
|
|
import com.github.rholder.retry.Retryer;
|
|
|
import com.github.rholder.retry.RetryerBuilder;
|
|
|
import com.github.rholder.retry.StopStrategies;
|
|
|
@@ -26,7 +39,10 @@ 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;
|
|
|
@@ -54,6 +70,19 @@ public class CodexServiceImpl implements CodexService {
|
|
|
|
|
|
private final GroupsMapper groupsMapper;
|
|
|
|
|
|
+ private final CodexUserRenewExpiryRecordMapper codexUserRenewExpiryRecordMapper;
|
|
|
+
|
|
|
+ private final BeanSearcher beanSearcher;
|
|
|
+
|
|
|
+ private final OrderDonMapper orderDonMapper;
|
|
|
+
|
|
|
+ private final GroupsFuncService groupsFuncService;
|
|
|
+
|
|
|
+ private final RedisService redisService;
|
|
|
+
|
|
|
+ private final CodexDeductRecordMapper codexDeductRecordMapper;
|
|
|
+
|
|
|
+ private static final Sequence SEQUENCE = new Sequence(0);
|
|
|
@Override
|
|
|
public CodexUserInfoView getCodexUserInfo(Long userId) {
|
|
|
List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
@@ -151,7 +180,8 @@ public class CodexServiceImpl implements CodexService {
|
|
|
/**
|
|
|
* 创建或更新Codex用户套餐
|
|
|
*/
|
|
|
- public ClaudeCodeResp createOrUpdateCodexUserPackage(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
|
|
|
+ @Override
|
|
|
+ public ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
|
|
|
Map<String, Object> params = new HashMap<>();
|
|
|
params.put("plan_name", planName.replaceAll(";", ""));
|
|
|
params.put("openai_daily_limit", openaiDailyLimit);
|
|
|
@@ -169,13 +199,231 @@ public class CodexServiceImpl implements CodexService {
|
|
|
return codexResp;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public CodexDeductResp getDeductMoney(Long userId, Long relationId) {
|
|
|
+ List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
+ CodexDeductResp codexDeductResp = new CodexDeductResp();
|
|
|
+ Integer selectCount = claudeCodeUserMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList));
|
|
|
+ if (selectCount > 0) {
|
|
|
+ codexDeductResp.setIsDeduct(Boolean.FALSE);
|
|
|
+ return codexDeductResp;
|
|
|
+ }
|
|
|
+ GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
|
|
|
+ .field(GroupsRelationView::getId, relationId)
|
|
|
+ .field(GroupsRelationView::getGoodsId, Constant.CODEX_GOODS_ID)
|
|
|
+ .field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
|
|
|
+ .field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
|
|
|
+ .build());
|
|
|
+ BigDecimal deductMoney;
|
|
|
+ if (groupsRelationView == null || groupsRelationView.getExpiryTime().before(DateTime.now())) {
|
|
|
+ deductMoney = BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ 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) {
|
|
|
+ Long userId = payReq.getUserId();
|
|
|
+ //codex 车票id
|
|
|
+ Long relationId = payReq.getRelationId();
|
|
|
+ CodexDeductResp codexDeductResp = getDeductMoney(userId, relationId);
|
|
|
+ if (!codexDeductResp.getIsDeduct()) {
|
|
|
+ throw BusinessRuntimeException.getInstance("你存在claude code 无法抵扣");
|
|
|
+ }
|
|
|
+ //抵扣金额
|
|
|
+ BigDecimal deductMoney = codexDeductResp.getDeductMoney();
|
|
|
+
|
|
|
+ GoodsDonSku sku = skuMapper.selectById(payReq.getSkuId());
|
|
|
+ if (sku == null || sku.getGoodsId() != Constant.CLAUDE_CODE_GOODS_ID || !sku.getIsCodex()) {
|
|
|
+ throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ int noPayCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getGoodsId, sku.getGoodsId())
|
|
|
+ .eq(OrderDon::getStatus, OrderDon.Status.noPayment.toString()));
|
|
|
+ if (noPayCount > 0) {
|
|
|
+ throw new BusinessRuntimeException("您有未支付订单.");
|
|
|
+ }
|
|
|
+ String cacheKye = "codex_deduct_cache_key:" + relationId;
|
|
|
+ boolean b = redisService.setNx(cacheKye, relationId, 10L);
|
|
|
+ if (!b) {
|
|
|
+ throw BusinessRuntimeException.getInstance("系统繁忙,请刷新页面重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ OrderDon orderDon;
|
|
|
+ try {
|
|
|
+ orderDon = new OrderDon();
|
|
|
+ orderDon.setGoodsId(sku.getGoodsId());
|
|
|
+ orderDon.setSkuId(sku.getId());
|
|
|
+ orderDon.setUserId(userId);
|
|
|
+ orderDon.setMoney(sku.getPrice().subtract(deductMoney));
|
|
|
+
|
|
|
+ /* 生成订单 */
|
|
|
+ String donNo = SEQUENCE.nextId().toString();
|
|
|
+ orderDon.setOrderNo(donNo);
|
|
|
+
|
|
|
+ //锁一个cc的车票id
|
|
|
+ GroupsRelation relation = getClaudeCodeRelation(userId, sku);
|
|
|
+ orderDon.setRelationId(relation.getId());
|
|
|
+ orderDonMapper.insert(orderDon);
|
|
|
+
|
|
|
+ //记录抵扣记录
|
|
|
+ CodexDeductRecord codexDeductRecord = new CodexDeductRecord();
|
|
|
+ codexDeductRecord.setOrderId(orderDon.getId());
|
|
|
+ codexDeductRecord.setRelationId(relationId);
|
|
|
+ codexDeductRecordMapper.insert(codexDeductRecord);
|
|
|
+ } finally {
|
|
|
+ if (redisService.hasKey(cacheKye)) {
|
|
|
+ redisService.del(cacheKye);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return orderDon;
|
|
|
+ }
|
|
|
+
|
|
|
+ private GroupsRelation getClaudeCodeRelation(Long userId, GoodsDonSku sku) {
|
|
|
+ //获取车票车位
|
|
|
+ GroupsRelation relation = getRelation(sku);
|
|
|
+ //锁定座位
|
|
|
+ setRelation(relation);
|
|
|
+ //校验座位
|
|
|
+ int update = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
|
|
|
+ .set(GroupsRelation::getUserId, userId)
|
|
|
+ .eq(GroupsRelation::getUserId, 0)
|
|
|
+ .eq(GroupsRelation::getId, relation.getId()));
|
|
|
+ if (update == 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("系统繁忙,请重试");
|
|
|
+ }
|
|
|
+ return relation;
|
|
|
+ }
|
|
|
+
|
|
|
+ private GroupsRelation getRelation(GoodsDonSku sku) {
|
|
|
+ GroupsRelation relation = null;
|
|
|
+ Integer maxNum = sku.getNum();
|
|
|
+ GroupsTrips groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.validity, maxNum, null, null);
|
|
|
+ if (groups == null) {
|
|
|
+ //待发车
|
|
|
+ groups = groupsMapper.selectTicketGroups(sku.getId(), GroupsTrips.Status.waiting, maxNum, null, null);
|
|
|
+ }
|
|
|
+ //新增空车队
|
|
|
+ if (groups == null) {
|
|
|
+ relation = groupsFuncService.createNewGroupsTrips(sku);
|
|
|
+ }
|
|
|
+ //获取车位
|
|
|
+ if (relation == null) {
|
|
|
+ //寻找快满编车队进行占座
|
|
|
+ relation = relationMapper.selectRandomOneRelationByGroupsId(groups.getId());
|
|
|
+ if (relation == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("系统繁忙,请重试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return relation;
|
|
|
+ }
|
|
|
+
|
|
|
+ public BigDecimal getFinalDeductMoney(Long relationId, Long relationSkuId, Long renewSkuId, Long renewOrderId, Date renewExpiryTime, Date relationStartTime, Date relationExpiryTime, DateTime now, List<Long> userIdList) {
|
|
|
+ BigDecimal deductMoney = BigDecimal.ZERO;
|
|
|
+ //一个月当30天算单价 往上取整
|
|
|
+ //续费规格
|
|
|
+ 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) {
|
|
|
+ orderMoney = presentSku.getPrice();
|
|
|
+ }
|
|
|
+ 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("codex车票id:{}目前续费升级规格可抵扣的金额为:{}", relationId, renewDeductMoney);
|
|
|
+ deductMoney = deductMoney.add(renewDeductMoney);
|
|
|
+ relationExpiryTime = DateUtil.offsetDay(relationExpiryTime, -betweenDay.intValue());
|
|
|
+ }
|
|
|
+ //上一个续费升级规格
|
|
|
+ List<OrderDon> orderDOns = codexUserRenewExpiryRecordMapper.getOtherRenewSkus(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) {
|
|
|
+ thisOrderMoney = thisRenewSku.getPrice();
|
|
|
+ }
|
|
|
+ //当天购买的按规格原价抵扣
|
|
|
+ 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("codex车票id:{}目前次一级规格:{}可抵扣的金额为:{}", relationId, thisRenewSku.getSpecVal(), thisRenewDeductMoney);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (relationExpiryTime.after(now)) {
|
|
|
+ //该车票抵扣金额
|
|
|
+ BigDecimal deductMoneyFromTicket = getDeductMoneyFromTicket(relationId, userIdList, relationSkuId, now, relationStartTime, relationExpiryTime);
|
|
|
+ deductMoney = deductMoney.add(deductMoneyFromTicket);
|
|
|
+ }
|
|
|
+ log.info("codex车票id:{}最终到期时间为:{}车票可返回 抵扣金额:{}", relationId, DateUtil.format(relationExpiryTime, "yyyy-MM-dd HH:mm:ss"), deductMoney);
|
|
|
+ return deductMoney;
|
|
|
+ }
|
|
|
|
|
|
private Retryer<ClaudeCodeResp> getApiRetryer(int wait, int stop) {
|
|
|
return RetryerBuilder.<ClaudeCodeResp>newBuilder().retryIfResult(result -> result == null).retryIfException().withWaitStrategy(WaitStrategies.fixedWait(wait, TimeUnit.SECONDS)).withStopStrategy(StopStrategies.stopAfterAttempt(stop)).build();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Codex POST请求 - 复制ClaudeCodeServiceImpl的实现模式
|
|
|
+ * Codex POST请求
|
|
|
*/
|
|
|
public ClaudeCodeResp executeCodexPostApi(String url, String body) {
|
|
|
Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
|
|
|
@@ -358,6 +606,113 @@ public class CodexServiceImpl implements CodexService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public void createOrUpdateCodexUserInfo(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 thisRelationDayilyLimit = null;
|
|
|
+ CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
|
|
|
+ if (codexUser != null) {
|
|
|
+ thisRelationDayilyLimit = codexUser.getOpenaiDailyLimit();
|
|
|
+ }
|
|
|
+ Date expiryTime = relation.getExpiryTime();
|
|
|
+ Integer openaiDailyLimit = sku.getOpenaiDailyLimit();
|
|
|
+ Integer openaiQuota = sku.getOpenaiQuota();
|
|
|
+ Long skuId = sku.getId();
|
|
|
+ Boolean isUpgrade = false;
|
|
|
+ Date renewExpiryTime = null;
|
|
|
+ //若是续费升级 记录此时续费升级的过期时间
|
|
|
+ if (!ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
|
|
|
+ //非车票原规格id 续费升级记录
|
|
|
+ saveCodexRenewExpiryRecord(orderId, relationUserId, relationId, skuId);
|
|
|
+ //是否需要修改当前claude code user 套餐等级
|
|
|
+ if (thisRelationDayilyLimit != null && thisRelationDayilyLimit <= openaiDailyLimit) {
|
|
|
+ if (sku.getDays() != null) {
|
|
|
+ renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
|
|
|
+ } else {
|
|
|
+ renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
|
|
|
+ }
|
|
|
+ isUpgrade = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //更新db codexUser
|
|
|
+ generateOrUpdateCodexUser(relationUserId, relationId, openaiDailyLimit, openaiQuota, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal(), userIdList);
|
|
|
+
|
|
|
+ try {
|
|
|
+ //获取最新的claude code user
|
|
|
+ codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
|
|
|
+ //生成codex或更新用户套餐
|
|
|
+ ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(relation.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), codexUser.getExpiryTime());
|
|
|
+ if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
|
|
|
+ //重试更新code userInfo数据
|
|
|
+ setCodexUserRetryUpdateInfo(relationId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("生成或更新claude code用户:{}套餐skuId:{} 失败,error_info:{}", userId, skuId, StringUtil.getErrorText(e));
|
|
|
+ //重试更新code userInfo数据
|
|
|
+ setCodexUserRetryUpdateInfo(relationId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void updateCodexUserPackageInfo(CodexUser codexUser, Date expiryTime, GoodsDonSku finalSku) {
|
|
|
+ try {
|
|
|
+ ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(codexUser.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), expiryTime);
|
|
|
+ if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
|
|
|
+ //重试标记
|
|
|
+ codexUser.setIsRetry(Boolean.TRUE);
|
|
|
+ codexUserMapper.updateById(codexUser);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ codexUser.setIsRetry(Boolean.TRUE);
|
|
|
+ codexUserMapper.updateById(codexUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void generateOrUpdateCodexUser(Long relationUserId, Long relationId, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime, Boolean isUpgrade, Long orderId, Long renewSkuId, Date renewExpiryTime, String planName, List<Long> userIdList) {
|
|
|
+ CodexUser codexUser = Optional.ofNullable(codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"))).orElse(new CodexUser());
|
|
|
+ if (isUpgrade) {
|
|
|
+ codexUser.setRenewOrderId(orderId);
|
|
|
+ codexUser.setRenewSkuId(renewSkuId);
|
|
|
+ codexUser.setRenewExpiryTime(renewExpiryTime);
|
|
|
+ codexUser.setPlanName(planName);
|
|
|
+ codexUser.setOpenaiDailyLimit(openaiDailyLimit);
|
|
|
+ codexUser.setOpenaiQuota(openaiQuota);
|
|
|
+ }
|
|
|
+ codexUser.setUserId(relationUserId);
|
|
|
+ codexUser.setRelationId(relationId);
|
|
|
+ codexUser.setExpiryTime(expiryTime);
|
|
|
+ if (codexUser.getId() == null) {
|
|
|
+ codexUser.setPlanName(planName);
|
|
|
+ codexUser.setOpenaiDailyLimit(openaiDailyLimit);
|
|
|
+ codexUser.setOpenaiQuota(openaiQuota);
|
|
|
+ }
|
|
|
+ if (codexUser.getId() == null) {
|
|
|
+ try {
|
|
|
+ codexUserMapper.insert(codexUser);
|
|
|
+ } catch (DuplicateKeyException e) {
|
|
|
+ log.info("插入codex user 重复");
|
|
|
+ }
|
|
|
+ } else codexUserMapper.updateById(codexUser);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveCodexRenewExpiryRecord(Long orderId, Long relationUserId, Long relationId, Long skuId) {
|
|
|
+ CodexUserRenewExpiryRecord renewExpiryRecord = new CodexUserRenewExpiryRecord();
|
|
|
+ renewExpiryRecord.setOrderId(orderId);
|
|
|
+ renewExpiryRecord.setUserId(relationUserId);
|
|
|
+ renewExpiryRecord.setRelationId(relationId);
|
|
|
+ renewExpiryRecord.setRenewSkuId(skuId);
|
|
|
+ codexUserRenewExpiryRecordMapper.insert(renewExpiryRecord);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Codex DELETE请求
|
|
|
*/
|
|
|
@@ -413,4 +768,123 @@ public class CodexServiceImpl implements CodexService {
|
|
|
throw BusinessRuntimeException.getInstance("获取codex使用统计失败");
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取订单单价
|
|
|
+ */
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+ //原车票订单总实付金额
|
|
|
+ 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) {
|
|
|
+ thisOrderMoney = sku.getPrice();
|
|
|
+ }
|
|
|
+ totalOrderMoney = totalOrderMoney.add(thisOrderMoney);
|
|
|
+ //总时间
|
|
|
+ if (sku.getDays() != null) {
|
|
|
+ totalDays += sku.getDays();
|
|
|
+ } else {
|
|
|
+ totalDays += sku.getMonths() * 30;
|
|
|
+ }
|
|
|
+ //原订单数
|
|
|
+ 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 thisOrderMoney;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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));
|
|
|
+ return deductMoney;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setRelation(GroupsRelation relation) {
|
|
|
+ Long relationId = relation.getId();
|
|
|
+ Long userId = relation.getUserId();
|
|
|
+ Long groupsId = relation.getGroupsId();
|
|
|
+ GroupsRelation.Status status = relation.getStatus();
|
|
|
+ String relation_num_key = RedisKey.GROUPS_RELATION_NUM_KEY + relationId;
|
|
|
+ if (!redisService.setNx(relation_num_key, userId, 60 * 5L)) {
|
|
|
+ GroupsRelation dbRelation = relationMapper.selectById(relationId);
|
|
|
+ if (dbRelation.getUserId() != 0) {
|
|
|
+ log.info("=====>用户:{}未抢到座位:{}", userId, relationId);
|
|
|
+ throw new BusinessRuntimeException("系统繁忙,请重试...");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (status == GroupsRelation.Status.outside) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int count = groupsMapper.decrAvailableNum(groupsId);
|
|
|
+ if (count == 0) {
|
|
|
+ log.error("车位异常 groupId:{}", groupsId);
|
|
|
+ groupsMapper.updateAvailableNum(groupsId);
|
|
|
+ //清除座位缓存key
|
|
|
+ delRelationKey(relationId, userId);
|
|
|
+ throw new BusinessRuntimeException("车位异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清除座位缓存key
|
|
|
+ */
|
|
|
+ public void delRelationKey(Long relationId, Long userId) {
|
|
|
+ String relation_num_key = RedisKey.GROUPS_RELATION_NUM_KEY + relationId;
|
|
|
+ Object object = redisService.get(relation_num_key);
|
|
|
+ if (object != null) {
|
|
|
+ try {
|
|
|
+ Long keyUserId = Long.parseLong(object.toString());
|
|
|
+ //清除车票key
|
|
|
+ if (ObjectUtil.equal(userId, keyUserId)) {
|
|
|
+ redisService.del(relation_num_key);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("删除缓存key错误:{}", StringUtil.getErrorText(e));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|