| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158 |
- package com.cyksj.service.codex.impl;
- import cn.hutool.core.collection.CollUtil;
- 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.core.util.StrUtil;
- 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.mapper.manage.coupon.CouponMapper;
- import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
- import com.cyksj.mapper.manage.coupon.CouponUserMapper;
- import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
- import com.cyksj.mapper.manage.distribute.UserDistributeSharedMapper;
- import com.cyksj.model.dto.CouponPopularizeDto;
- import com.cyksj.model.entity.*;
- import com.cyksj.model.manage.views.GroupsRelationView;
- import com.cyksj.model.request.CodexUpgradePayReq;
- 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.model.views.CouponNewUserView;
- import com.cyksj.model.views.CouponUserView;
- import com.cyksj.redis.RedisService;
- import com.cyksj.service.codex.CodexService;
- import com.cyksj.service.coupon.CouponFontService;
- import com.cyksj.service.groups.GroupsFuncService;
- import com.cyksj.service.user.UserBindRelationService;
- import com.ejlchina.searcher.BeanSearcher;
- import com.ejlchina.searcher.param.Operator;
- import com.ejlchina.searcher.util.MapBuilder;
- import com.ejlchina.searcher.util.MapUtils;
- import com.github.rholder.retry.Retryer;
- import com.github.rholder.retry.RetryerBuilder;
- import com.github.rholder.retry.StopStrategies;
- import com.github.rholder.retry.WaitStrategies;
- 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;
- import java.util.stream.Collectors;
- /**
- * 项目名: yhlxj11111111
- * 文件名: CodexServiceImpl
- * 创建者: Claude
- * 创建时间:2025/9/15
- */
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class CodexServiceImpl implements CodexService {
- private final CodexUserMapper codexUserMapper;
- private final ClaudeCodeUserMapper claudeCodeUserMapper;
- private final UserBindRelationService userBindRelationService;
- private final GoodsDonSkuMapper skuMapper;
- private final GoodsDonMapper goodsDonMapper;
- private final CouponMapper couponMapper;
- private final GroupsRelationMapper relationMapper;
- 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 final CouponSkuMapper couponSkuMapper;
- private final CouponUserMapper couponUserMapper;
- private final UserDistributeMapper userDistributeMapper;
- private final UserDistributeSharedMapper userDistributeSharedMapper;
- private final UserMapper userMapper;
- private final CouponFontService couponFontService;
- private static final Sequence SEQUENCE = new Sequence(0);
- @Override
- public CodexUserInfoView getCodexUserInfo(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- // 查询Claude Code信息
- CodexUserInfoView.ClaudeCodeInfo claudeCodeInfo = getClaudeCodeInfo(userId);
- if (codexUser == null) {
- //是否有claude code
- if (claudeCodeInfo != null && claudeCodeInfo.getClaudeDailyLimit() != null) {
- GoodsDonSku sku = null;
- if (claudeCodeInfo.getRenewSkuId() != null) {
- sku = skuMapper.selectById(claudeCodeInfo.getRenewSkuId());
- }
- //续费升级规格不存在 或者 不赠送codex
- if (sku == null || !sku.getIsCodex()) {
- GroupsRelation relation = relationMapper.selectById(claudeCodeInfo.getRelationId());
- GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
- sku = skuMapper.selectById(groupsTrips.getSkuId());
- }
- //sku 存在并且开启赠送codex
- if (sku != null && sku.getIsCodex()) {
- CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
- .userId(claudeCodeInfo.getUserId())
- .planName(sku.getCodexPlanName())
- .openaiDailyLimit(sku.getOpenaiDailyLimit())
- .openaiQuota(sku.getOpenaiQuota())
- .expiryTime(claudeCodeInfo.getExpiryTime())
- .build();
- createOrUpdateUserPackage(codexPackageReq);
- codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- }
- }
- if (codexUser == null) {
- return null;
- }
- }
- return CodexUserInfoView.builder().planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).claudeCodeInfo(claudeCodeInfo).build();
- }
- private CodexUserInfoView.ClaudeCodeInfo getClaudeCodeInfo(Long userId) {
- // 获取用户关联的ID列表
- 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) {
- return null;
- }
- return CodexUserInfoView.ClaudeCodeInfo.builder()
- .userId(claudeCodeUser.getUserId())
- .planName(claudeCodeUser.getPlanName())
- .relationId(claudeCodeUser.getRelationId())
- .claudeDailyLimit(claudeCodeUser.getClaudeDailyLimit())
- .claudeQuota(claudeCodeUser.getClaudeQuota())
- .expiryTime(claudeCodeUser.getExpiryTime())
- .renewSkuId(claudeCodeUser.getRenewSkuId())
- .renewExpiryTime(claudeCodeUser.getRenewExpiryTime()).build();
- }
- @Override
- public void createOrUpdateUserPackage(CodexUserPackageReq req) {
- Long userId = req.getUserId();
- // 构建完整的套餐参数
- String planName = req.getPlanName();
- Date expiryTime = req.getExpiryTime();
- Integer openaiDailyLimit = req.getOpenaiDailyLimit();
- Integer openaiQuota = req.getOpenaiQuota();
- Long relationId = req.getRelationId();
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser existingCodexUser = Optional.ofNullable(codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"))).orElse(new CodexUser());
- existingCodexUser.setPlanName(planName);
- existingCodexUser.setRelationId(relationId);
- existingCodexUser.setUserId(userId);
- existingCodexUser.setOpenaiDailyLimit(openaiDailyLimit);
- existingCodexUser.setOpenaiQuota(openaiQuota);
- existingCodexUser.setExpiryTime(expiryTime);
- if (existingCodexUser.getId() == null) {
- try {
- codexUserMapper.insert(existingCodexUser);
- } catch (DuplicateKeyException e) {
- }
- return;
- }
- codexUserMapper.updateById(existingCodexUser);
- }
- /**
- * 创建或更新Codex用户套餐
- */
- @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);
- params.put("openai_quota", openaiQuota);
- params.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 codexResp = executeCodexPostApi(planUrl, Jsons.toJson(params));
- if (!"success".equals(codexResp.getMessage())) {
- log.info("用户codex用户:{}套餐:{}创建或更新失败,info:{}", userId, planName, codexResp.getMessage());
- throw BusinessRuntimeException.getInstance("调用codex 套餐接口失败");
- }
- return codexResp;
- }
- @Override
- public CodexDeductResp getDeductMoney(Long userId, Long relationId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexDeductResp codexDeductResp = new CodexDeductResp();
- List<Long> sendCodexSkuIds = skuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).eq(GoodsDonSku::getIsCodex, Boolean.TRUE)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
- if (CollUtil.isNotEmpty(sendCodexSkuIds)) {
- GroupsRelationView ccRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getSkuId, sendCodexSkuIds).op(Operator.InList).field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan).field(GroupsRelationView::getUserId, userIdList).op(Operator.InList).field(GroupsRelationView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).build());
- if (ccRelationView != null) {
- codexDeductResp.setIsDeduct(Boolean.FALSE);
- return codexDeductResp;
- }
- }
- MapBuilder builder = MapUtils.builder();
- if (relationId != null) {
- builder.field(GroupsRelationView::getId, relationId);
- }
- GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, builder
- .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;
- } else {
- relationId = groupsRelationView.getId();
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
- Assert.notNull(codexUser, "系统异常,请联系客服");
- 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) throws Exception {
- 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();
- Long skuId = payReq.getSkuId();
- GoodsDonSku sku = skuMapper.selectById(skuId);
- if (sku == null || sku.getGoodsId() != Constant.CLAUDE_CODE_GOODS_ID || !sku.getIsCodex()) {
- throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
- }
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- int noPayCount = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class).in(OrderDon::getUserId, userIdList).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("系统繁忙,请刷新页面重试");
- }
- CouponUser couponUser = null;
- if (payReq.getCouponId() != null) {
- CouponPopularizeDto couponPopularizeDto = checkCouponStatus(skuId, null, payReq.getCouponId(), userId, false);
- //记录优惠券使用状态
- couponUser = couponStatusRecord(null, payReq.getCouponId(), userId, couponPopularizeDto);
- }
- OrderDon orderDon;
- try {
- orderDon = new OrderDon();
- orderDon.setGoodsId(sku.getGoodsId());
- orderDon.setSkuId(sku.getId());
- orderDon.setUserId(userId);
- //优惠 --> 订单金额
- deductOrderMoney(orderDon, couponUser);
- orderDon.setMoney(sku.getPrice().subtract(deductMoney));
- /* 生成订单 */
- String donNo = SEQUENCE.nextId().toString();
- orderDon.setOrderNo(donNo);
- //锁一个cc的车票id
- //是否存在无赠送的claude code 直接原规格上抵扣
- List<Long> sendCodexSkuIds = skuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID).eq(GoodsDonSku::getIsCodex, Boolean.TRUE)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
- //cc车票id
- Long ccRelationId = null;
- if (CollUtil.isEmpty(sendCodexSkuIds)) {
- //是否存在cc
- Integer selectCount = claudeCodeUserMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList));
- if (selectCount > 0) {
- throw BusinessRuntimeException.getInstance("你存在claude code 无法抵扣");
- }
- } else {
- GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getUserId, userIdList).op(Operator.InList).field(GroupsRelationView::getSkuId, sendCodexSkuIds).op(Operator.InList).field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan).build());
- if (groupsRelationView != null) {
- ccRelationId = groupsRelationView.getId();
- }
- }
- GroupsRelation relation = getClaudeCodeRelation(userId, sku);
- orderDon.setRelationId(relation.getId());
- orderDonMapper.insert(orderDon);
- //记录抵扣记录
- CodexDeductRecord codexDeductRecord = new CodexDeductRecord();
- codexDeductRecord.setCcRelationId(ccRelationId);
- 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请求
- */
- public ClaudeCodeResp executeCodexPostApi(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 (!"success".equals(resp.getMessage())) {
- log.error("codex POST URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (Exception e) {
- log.error("codex POST请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
- return null;
- }
- });
- } catch (ExecutionException | com.github.rholder.retry.RetryException e) {
- log.info("重试调用codex POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- throw BusinessRuntimeException.getInstance("创建或更新codex user失败");
- }
- }
- /**
- * codex用户信息重试更新信息
- */
- public void setCodexUserRetryUpdateInfo(Long relationId) {
- 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);
- }
- }
- @Override
- public ClaudeCodeResp getUserOpenAIUsage(Long userId, String period) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- if (codexUser == null) {
- return null;
- }
- // 调用Codex API获取实时使用统计
- String usageUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/usage?period=%s", codexUser.getUserId(), period);
- ClaudeCodeResp codexResp = executeCodexGetApi(usageUrl);
- return codexResp;
- }
- @Override
- public ClaudeCodeResp updateUserOpenAIDailyLimit(Long userId, UpdateDailyLimitRequest request) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- if (codexUser == null) {
- throw new BusinessRuntimeException("用户未开通Codex服务");
- }
- Integer dailyLimit = request.getDailyLimit();
- Integer totalQuota = request.getTotalQuota();
- // 验证每日限额参数
- if (dailyLimit == null || dailyLimit <= 0) {
- throw new BusinessRuntimeException("每日限额必须大于0");
- }
-
- // 保存原始值用于回滚
- Integer originalDailyLimit = codexUser.getOpenaiDailyLimit();
-
- // 更新数据库中的每日限额
- codexUser.setOpenaiDailyLimit(dailyLimit);
- codexUserMapper.updateById(codexUser);
-
- try {
- // 调用Codex API更新每日限额
- String updateUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/limit", codexUser.getUserId());
- Map<String, Object> params = new HashMap<>();
- params.put("daily_limit", dailyLimit);
- params.put("total_quota", totalQuota);
- ClaudeCodeResp codexResp = executeCodexPostApi(updateUrl, Jsons.toJson(params));
-
- if (!"success".equals(codexResp.getMessage())) {
- log.error("更新用户{}每日限额{}失败: {}", userId, dailyLimit, codexResp.getMessage());
- // API调用失败时回滚数据库更新
- codexUser.setOpenaiDailyLimit(originalDailyLimit);
- codexUserMapper.updateById(codexUser);
- throw new BusinessRuntimeException("更新每日限额失败");
- }
-
- log.info("成功更新用户{}每日限额为{}", userId, dailyLimit);
- return codexResp;
-
- } catch (Exception e) {
- log.error("更新用户{}每日限额{}异常: {}", userId, dailyLimit, StringUtil.getErrorText(e));
- // 异常时回滚数据库更新
- codexUser.setOpenaiDailyLimit(originalDailyLimit);
- codexUserMapper.updateById(codexUser);
- throw new BusinessRuntimeException("更新每日限额失败");
- }
- }
- @Override
- public ClaudeCodeResp getSystemMetrics(String period, String metric) {
- try {
- // 构建系统指标API URL
- String metricsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/system/metrics");
-
- // 添加查询参数
- List<String> queryParams = new ArrayList<>();
- if (period != null && !period.isEmpty()) {
- queryParams.add("period=" + period);
- }
- if (metric != null && !metric.isEmpty()) {
- queryParams.add("metric=" + metric);
- }
-
- if (!queryParams.isEmpty()) {
- metricsUrl += "?" + String.join("&", queryParams);
- }
-
- // 调用Codex API获取系统指标
- ClaudeCodeResp codexResp = executeCodexGetApi(metricsUrl);
-
- if (codexResp == null) {
- log.error("获取系统指标失败: API返回null");
- throw new BusinessRuntimeException("获取系统指标失败");
- }
-
- log.info("成功获取系统指标, period={}, metric={}", period, metric);
- return codexResp;
-
- } catch (Exception e) {
- log.error("获取系统指标异常, period={}, metric={}, error={}", period, metric, StringUtil.getErrorText(e));
- throw new BusinessRuntimeException("获取系统指标失败");
- }
- }
-
- @Override
- public ClaudeCodeResp getJavaUserDashboard(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- if (codexUser == null) {
- return null;
- }
- // 调用Codex API获取用户控制台数据
- String dashboardUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/dashboard", codexUser.getUserId());
- ClaudeCodeResp codexResp = executeCodexGetApi(dashboardUrl);
- return codexResp;
- }
-
- @Override
- public ClaudeCodeResp getJavaUserAnalytics(Long userId, String start, String end, Integer page, Integer limit, String order) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- if (codexUser == null) {
- return null;
- }
- if (start == null) {
- DateTime now = DateTime.now();
- start = DateUtil.offsetDay(now, -1).toString();
- end = now.toString();
- }
- // 调用Codex API获取用户分析数据
- String analyticsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/analytics?start=%s&end=%s&page=%s&limit=%s&order=%s", codexUser.getUserId(), start, end, page, limit, order);
- ClaudeCodeResp codexResp = executeCodexGetApi(analyticsUrl);
- return codexResp;
- }
- @Override
- public void delCodexUser(Long userId, Long relationId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).eq(CodexUser::getRelationId, relationId).last("limit 1"));
- if (codexUser != null) {
- codexUserMapper.deleteById(codexUser.getId());
- }
- }
- @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, Boolean.TRUE);
- 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, Boolean isPay) {
- 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.setIsPay(isPay);
- 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请求
- */
- public ClaudeCodeResp executeCodexDeleteApi(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 (!"success".equals(resp.getMessage())) {
- log.error("codex DELETE URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (Exception e) {
- log.error("codex DELETE请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
- return null;
- }
- });
- } catch (ExecutionException | com.github.rholder.retry.RetryException e) {
- log.error("重试调用codex DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- throw BusinessRuntimeException.getInstance("删除操作失败");
- }
- }
- /**
- * Codex GET请求
- */
- public ClaudeCodeResp executeCodexGetApi(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 (!"success".equals(resp.getMessage())) {
- log.error("codex GET URL:{}接口返回msg:{}", url, resp.getMessage());
- }
- return resp;
- } catch (Exception e) {
- log.error("codex GET请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
- return null;
- }
- });
- } catch (ExecutionException | com.github.rholder.retry.RetryException e) {
- log.error("重试调用codex GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
- 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));
- }
- }
- }
- public CouponPopularizeDto checkCouponStatus(Long skuId, String couponExCode, Long couponId, Long userId, Boolean isRenew) throws Exception {
- log.info("开始校验兑换码:{},优惠券id:{}状态", couponExCode, couponId);
- //实物还是虚物商品
- GoodsDonSku goodsDonSku = skuMapper.selectById(skuId);
- GoodsDon goodsDon = goodsDonMapper.selectById(goodsDonSku.getGoodsId());
- if (StrUtil.isNotBlank(couponExCode) && couponId != null) {
- throw BusinessRuntimeException.getInstance("优惠券与优惠码不可同时使用..");
- }
- if (StrUtil.isNotBlank(couponExCode)) {
- CouponPopularizeDto exists = couponMapper.checkExCode(couponExCode);
- if (exists == null) {
- throw BusinessRuntimeException.getInstance("该优惠码不存在");
- }
- //推广码
- if (exists.getIsGeneral() != null) {
- if (exists.getIsGeneral() && userId.equals(exists.getUserId())) {
- throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
- }
- if (!exists.getIsGeneral()) {
- UserDistribute userDistribute = userDistributeMapper.selectById(exists.getDistributeId());
- if (userDistribute != null && userDistribute.getUserId().equals(userId)) {
- throw BusinessRuntimeException.getInstance("不可以使用自己的优惠码");
- }
- }
- //是否有上下级关系
- if (exists.getIsGeneral()) {
- UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class)
- .eq(UserDistributeShared::getUserId, userId).last("limit 1"));
- if (userDistributeShared == null) {
- //是否是 当天注册新用户 且下过单
- User user = userMapper.selectById(userId);
- if (user.getCreatedTime().before(DateUtil.beginOfDay(DateTime.now()))) {
- throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
- }
- CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
- if (couponNewUserView != null)
- throw BusinessRuntimeException.getInstance("该优惠码只适用于新用户");
- }
- if (userDistributeShared != null && !userDistributeShared.getSharedId().equals(exists.getUserId())) {
- throw BusinessRuntimeException.getInstance("您已有推广,无法使用其他人推广码");
- }
- }
- }
- checkCouponGoods(goodsDon, skuId, exists.getCouponId(), true);
- //检验是优惠券使用范围
- if (isRenew && exists.getUseScope() == Coupon.UseScope.orders) {
- throw BusinessRuntimeException.getInstance("该优惠码续费时不可使用");
- }
- if (!isRenew && exists.getUseScope() == Coupon.UseScope.renew) {
- throw BusinessRuntimeException.getInstance("该优惠码下单时不可使用");
- }
- if (exists.getScope() == Coupon.Scope.newUser) {
- CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
- if (couponNewUserView != null) {
- throw BusinessRuntimeException.getInstance("该新用户优惠码有且仅可使用一次");
- }
- }
- if (exists.getIsValidTime() && exists.getValidEndTime().before(DateTime.now())) {
- throw BusinessRuntimeException.getInstance("该优惠码已失效");
- }
- if (exists.getIsValidTime() && exists.getValidStartTime().after(DateTime.now())) {
- throw BusinessRuntimeException.getInstance("该优惠码待生效");
- }
- return exists;
- } else if (couponId != null) {
- CouponUserView couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
- .field(CouponUserView::getCouponId, couponId).op(Operator.Equal)
- .field(CouponUserView::getUserId, userId).op(Operator.Equal)
- .build());
- if (couponUserView == null) {
- throw BusinessRuntimeException.getInstance("该优惠券不存在");
- }
- if (couponUserView.getCouponUserStatus() == CouponUser.Status.used) {
- throw BusinessRuntimeException.getInstance("该优惠券已使用");
- }
- couponFontService.setCouponUserStatus(couponUserView, DateTime.now());
- if (couponUserView.getCouponUserStatus() != CouponUser.Status.unused) {
- throw BusinessRuntimeException.getInstance(couponUserView.getReason());
- }
- checkCouponGoods(goodsDon, skuId, couponUserView.getCouponId(), false);
- //检验是优惠券使用范围
- if (isRenew && couponUserView.getUseScope() == Coupon.UseScope.orders) {
- throw BusinessRuntimeException.getInstance("该优惠券续费时不可使用");
- }
- if (!isRenew && couponUserView.getUseScope() == Coupon.UseScope.renew) {
- throw BusinessRuntimeException.getInstance("该优惠券下单时不可使用");
- }
- }
- return null;
- }
- private CouponUser couponStatusRecord(String couponExCode, Long couponId, Long userId, CouponPopularizeDto exists) {
- log.info("兑换码:{},优惠券id:{},更新其优惠券状态", couponExCode, couponId);
- CouponUser couponUser = null;
- if (StrUtil.isNotBlank(couponExCode)) {
- if (exists == null) {
- throw BusinessRuntimeException.getInstance("该优惠码不存在");
- }
- couponUser = new CouponUser();
- couponUser.setCouponId(exists.getCouponId());
- if (exists.getPopularizeId() != null) {
- couponUser.setCouponId(exists.getPopularizeCouponId());
- couponUser.setPopularizeId(exists.getPopularizeId());
- }
- //续费优惠码可重复使用
- if (exists.getUseScope() != Coupon.UseScope.renew) {
- //非渠道推广 推广优惠码只可使用一次
- if ((exists.getPopularizeId() != null && exists.getIsGeneral()) || exists.getPopularizeId() == null) {
- CouponUser received = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponUser.getCouponId()).last("limit 1"));
- if (received != null && received.getStatus() != CouponUser.Status.unused) {
- throw BusinessRuntimeException.getInstance("您已使用该优惠码所对应的优惠券");
- }
- couponUser.setUserId(userId);
- couponUser.setStatus(CouponUser.Status.used);
- couponUser.setChannel(CouponUser.Channel.exCode);
- couponFontService.updateCouponUserValidTime(couponUser.getCouponId(), couponUser);
- try {
- couponUserMapper.insert(couponUser);
- } catch (DuplicateKeyException e) {
- log.info("用户已领取该{}优惠券", couponUser.getCouponId());
- throw BusinessRuntimeException.getInstance("您已领取该优惠码对应的优惠券,请使用优惠券");
- }
- }
- }
- } else {
- couponUser = couponUserMapper.selectOne(Wrappers.lambdaQuery(CouponUser.class).eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, couponId).last("limit 1"));
- if (couponUser == null) {
- throw BusinessRuntimeException.getInstance("该优惠券不存在");
- }
- couponUser.setStatus(CouponUser.Status.used);
- couponUserMapper.updateById(couponUser);
- }
- return couponUser;
- }
- public void checkCouponGoods(GoodsDon goodsDon, Long skuId, Long couponId, Boolean isCouponCode) throws Exception {
- if (goodsDon.getType() == 1) {
- CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
- .eq(CouponSku::getSkuId, skuId)
- .eq(CouponSku::getCouponId, couponId)
- .select(CouponSku::getId).last("limit 1"));
- if (couponSku == null) {
- throw BusinessRuntimeException.getInstance(String.format("该%s不适用于该规格", isCouponCode ? "优惠码" : "优惠券"));
- }
- } else {
- //实物、潮玩 优惠码优惠券 针对平台
- Long gid = goodsDon.getId();
- CouponSku couponSku = couponSkuMapper.selectOne(Wrappers.lambdaQuery(CouponSku.class)
- .eq(CouponSku::getGoodsId, gid)
- .eq(CouponSku::getCouponId, couponId)
- .select(CouponSku::getId).last("limit 1"));
- if (couponSku == null) {
- throw BusinessRuntimeException.getInstance(String.format("该%s不可用于该商品", isCouponCode ? "优惠码" : "优惠券"));
- }
- }
- }
- /**
- * 使用优惠营销 订单金额抵扣
- */
- public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser) throws Exception {
- BigDecimal first_money = orderDon.getMoney();
- //存在优惠券
- if (couponUser != null) {
- Long couponId = couponUser.getCouponId();
- Coupon coupon = couponMapper.getCouponById(couponId);
- BigDecimal couponMoney = null;
- BigDecimal payMoney = orderDon.getMoney();
- BigDecimal needDeductMoney = payMoney;
- if (orderDon.getOriMoney() == null) {
- orderDon.setOriMoney(payMoney);
- }
- if (orderDon.getIsDp() != null && orderDon.getIsDp()) {
- needDeductMoney = needDeductMoney.subtract(orderDon.getDpMoney());
- }
- if (coupon.getType() == Coupon.Type.discount) {
- couponMoney = needDeductMoney.multiply(BigDecimal.valueOf(1).subtract(coupon.getDiscount()));
- //需支付金额
- orderDon.setMoney(payMoney.subtract(couponMoney));
- orderDon.setOriMoney(orderDon.getOriMoney().multiply(coupon.getDiscount()));
- //记录折扣 用于分销
- couponUser.setDiscount(coupon.getDiscount());
- couponUserMapper.updateById(couponUser);
- } else if (coupon.getType() == Coupon.Type.reduce) {
- BigDecimal subtractMoney = payMoney.subtract(coupon.getReduceMoney());
- orderDon.setMoney(subtractMoney);
- couponMoney = coupon.getReduceMoney();
- orderDon.setOriMoney(orderDon.getOriMoney().subtract(coupon.getReduceMoney()));
- }
- if (couponMoney != null && couponMoney.compareTo(first_money) >= 0) {
- throw BusinessRuntimeException.getInstance("支付金额不能小于优惠金额");
- }
- orderDon.setCouponMoney(couponMoney);
- orderDon.setCouponUserId(couponUser.getId());
- orderDon.setCouponId(couponUser.getCouponId());
- }
- }
- }
|