| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193 |
- 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.conditions.query.LambdaQueryWrapper;
- 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.mapper.renew.RenewUpgradePackageMapper;
- import com.cyksj.model.dto.CouponPopularizeDto;
- import com.cyksj.model.entity.*;
- import com.cyksj.model.request.ClaudeCodeApiKeysReq;
- import com.cyksj.model.request.ClaudeCodeDelReq;
- 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.*;
- import com.cyksj.redis.RedisService;
- import com.cyksj.service.api.ClaudeCodexApiService;
- 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 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 final OrderDonGalaxyCoinRecordMapper orderDonGalaxyCoinRecordMapper;
- private final RenewUpgradePackageMapper renewUpgradePackageMapper;
- private static final Sequence SEQUENCE = new Sequence(0);
- private final ClaudeCodexApiService claudeCodexApiService;
- @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 {
- return claudeCodexApiService.createOrUpdateCodexUserPackageApi(userId, planName, openaiDailyLimit, openaiQuota, expiryTime);
- }
- @Override
- public CodexDeductResp getDeductMoney(Long userId, Long relationId, Long upgradeSkuId) {
- 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)) {
- GroupsRelationMirrorView ccRelationView = beanSearcher.searchFirst(GroupsRelationMirrorView.class, MapUtils.builder()
- .field(GroupsRelationMirrorView::getSkuId, sendCodexSkuIds).op(Operator.InList)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .field(GroupsRelationMirrorView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationMirrorView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
- .build());
- if (ccRelationView != null) {
- codexDeductResp.setIsDeduct(Boolean.FALSE);
- return codexDeductResp;
- }
- }
- GoodsDonSku upgradeSku = skuMapper.selectById(upgradeSkuId);
- if (upgradeSku.getGoodsId() != Constant.CODEX_GOODS_ID) {
- codexDeductResp.setDeductMoney(BigDecimal.ZERO);
- return codexDeductResp;
- }
- MapBuilder builder = MapUtils.builder();
- if (relationId != null) {
- builder.field(GroupsRelationMirrorView::getId, relationId);
- }
- GroupsRelationMirrorView groupsRelationMirrorView = beanSearcher.searchFirst(GroupsRelationMirrorView.class, builder
- .field(GroupsRelationMirrorView::getGoodsId, Constant.CODEX_GOODS_ID)
- .field(GroupsRelationMirrorView::getUserId, userIdList).op(Operator.InList)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- if (groupsRelationMirrorView == null || groupsRelationMirrorView.getExpiryTime().before(DateTime.now())) {
- codexDeductResp.setDeductMoney(BigDecimal.ZERO);
- } else {
- relationId = groupsRelationMirrorView.getId();
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).eq(CodexUser::getRelationId, relationId).last("limit 1"));
- Assert.notNull(codexUser, "系统异常,请联系客服");
- codexDeductResp = getFinalDeductMoney(relationId, groupsRelationMirrorView.getSkuId(), codexUser.getRenewSkuId(), codexUser.getRenewOrderId(), codexUser.getRenewExpiryTime(), groupsRelationMirrorView.getStartTime(), groupsRelationMirrorView.getExpiryTime(), DateTime.now(), userIdList, upgradeSku);
- }
- return codexDeductResp;
- }
- @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.CODEX_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- //车票不存在
- if (groupsRelationMirrorView == null) {
- //套餐是否存在
- if (codexUser != null) {
- //清除用户套餐
- if (delUserPackages(codexUser.getUserId())) {
- codexUserMapper.deleteById(codexUser.getId());
- }
- }
- return false;
- }
- return true;
- }
- @Override
- public CodexUserInfoView getUserSubsInfo(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.CODEX_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- //车票不存在
- if (groupsRelationMirrorView == null) {
- //套餐是否存在
- if (codexUser != null) {
- //清除用户套餐
- if (delUserPackages(codexUser.getUserId())) {
- codexUserMapper.deleteById(codexUser.getId());
- }
- }
- return null;
- }
- GoodsDonSku sku = null;
- if (codexUser == null) {
- OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
- .eq(OrderDon::getGoodsId, Constant.CODEX_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());
- createOrUpdateCodexUserInfo(orderDon.getId(), orderDon.getRelationId(), orderDon.getUserId(), sku, orderDon.getOrderType());
- } else {
- //试用车票
- Long skuId = groupsRelationMirrorView.getSkuId();
- sku = skuMapper.selectById(skuId);
- createOrUpdateCodexUserInfo(null, groupsRelationMirrorView.getId(), groupsRelationMirrorView.getUserId(), sku, null);
- }
- codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
- }
- //续费升级
- if (codexUser.getRenewSkuId() != null) {
- sku = skuMapper.selectById(codexUser.getRenewSkuId());
- }
- if (sku == null) {
- sku = skuMapper.selectById(groupsRelationMirrorView.getSkuId());
- }
- if (codexUser != null) {
- codexUser.setPlanName(sku.getSpecVal());
- codexUser.setExpiryTime(groupsRelationMirrorView.getExpiryTime());
- codexUserMapper.updateById(codexUser);
- }
- //是否需要重试更新 cladueCode userInfo信息
- if (codexUser.getIsRetry()) {
- try {
- ClaudeCodeResp codeUserPackage = createOrUpdateCodexUserPackageApi(codexUser.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), codexUser.getExpiryTime());
- if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
- codexUser.setIsRetry(Boolean.TRUE);
- codexUserMapper.updateById(codexUser);
- } else {
- codexUser.setIsRetry(Boolean.FALSE);
- codexUserMapper.updateById(codexUser);
- }
- } catch (Exception e) {
- }
- }
- return CodexUserInfoView.builder()
- .isPay(codexUser.getIsPay())
- .planName(codexUser.getPlanName())
- .relationId(codexUser.getRelationId())
- .openaiDailyLimit(codexUser.getOpenaiDailyLimit())
- .openaiQuota(codexUser.getOpenaiQuota())
- .expiryTime(codexUser.getExpiryTime())
- .renewSkuId(Optional.ofNullable(codexUser.getRenewSkuId()).orElse(groupsRelationMirrorView.getSkuId()))
- .renewOrderId(codexUser.getRenewOrderId())
- .renewExpiryTime(codexUser.getRenewExpiryTime())
- .build();
- }
- @Override
- public ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
- Long userId = req.getUserId();
- if (checkCodexUser(userId)) {
- Long codexUserId = getCodexUserId(userId);
- Assert.notNull(codexUserId, "您的codex账号已过期");
- req.setUserId(codexUserId);
- ClaudeCodeResp claudeCodeResp = claudeCodexApiService.createApiKeys(req);
- return claudeCodeResp;
- }
- throw new BusinessRuntimeException("您还没有codex账号");
- }
- @Override
- public void deleteApiKeysById(ClaudeCodeDelReq delReq) throws Exception {
- Long userId = delReq.getUserId();
- Long keyId = delReq.getKeyId();
- if (checkCodexUser(userId)) {
- Long codexUserId = getCodexUserId(userId);
- claudeCodexApiService.deleteApiKeysById(codexUserId, keyId);
- }
- }
- @Override
- public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
- Long codexUserId = getCodexUserId(userId);
- if (codexUserId != null) {
- List<ClaudeCodeUserApiKeysView> keysViews = claudeCodexApiService.getUserApiKeys(codexUserId);
- return keysViews;
- }
- return null;
- }
- @Override
- public 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("系统繁忙,请重试");
- }
- relation.setUserId(userId);
- //重新置为锁定
- relation.setStatus(GroupsRelation.Status.locking);
- relationMapper.updateById(relation);
- 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 CodexDeductResp getFinalDeductMoney(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天算单价 往上取整
- //续费规格
- if (renewSkuId != null && renewExpiryTime.compareTo(now) > 0) {
- OrderDon renewOrderDon = orderDonMapper.selectById(renewOrderId);
- BigDecimal orderMoney = renewOrderDon.getMoney().add(Optional.ofNullable(renewOrderDon.getBalance()).orElse(BigDecimal.ZERO)).add(Optional.ofNullable(renewOrderDon.getCouponMoney()).orElse(BigDecimal.ZERO));
- OrderDonGalaxyCoinRecord orderDonGalaxyCoinRecord = orderDonGalaxyCoinRecordMapper.selectOne(Wrappers.lambdaQuery(OrderDonGalaxyCoinRecord.class).eq(OrderDonGalaxyCoinRecord::getOrderId, renewOrderDon.getId()).last("limit 1"));
- if (orderDonGalaxyCoinRecord != null) {
- orderMoney = orderMoney.add(orderDonGalaxyCoinRecord.getDeductMoney());
- }
- // 续费升级订单的实际价值还包含上一次升级使用的 Codex 抵扣。
- // 若不回补这部分金额,连续升级时抵扣金额会逐级变少。
- CodexDeductRecord renewCodexDeductRecord = codexDeductRecordMapper.selectOne(Wrappers.lambdaQuery(CodexDeductRecord.class)
- .eq(CodexDeductRecord::getOrderId, renewOrderDon.getId()).last("limit 1"));
- if (renewCodexDeductRecord != null) {
- orderMoney = orderMoney.add(Optional.ofNullable(renewCodexDeductRecord.getDeductMoney()).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));
- CodexDeductRecord thisRenewCodexDeductRecord = codexDeductRecordMapper.selectOne(Wrappers.lambdaQuery(CodexDeductRecord.class)
- .eq(CodexDeductRecord::getOrderId, thisRenewOrderDon.getId()).last("limit 1"));
- if (thisRenewCodexDeductRecord != null) {
- thisOrderMoney = thisOrderMoney.add(Optional.ofNullable(thisRenewCodexDeductRecord.getDeductMoney()).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);
- }
- }
- CodexDeductResp codexDeductResp = new CodexDeductResp();
- if (relationExpiryTime.after(now)) {
- //该车票抵扣金额
- BigDecimal deductMoneyFromTicket = getDeductMoneyFromTicket(relationId, userIdList, relationSkuId, now, relationStartTime, relationExpiryTime);
- deductMoney = deductMoney.add(deductMoneyFromTicket);
- }
- Long presentSkuId = renewSkuId != null && renewSkuId > 0 ? renewSkuId : relationSkuId;
- RenewUpgradePackage renewUpgradePackage = renewUpgradePackageMapper.selectOne(Wrappers.lambdaQuery(RenewUpgradePackage.class)
- .eq(RenewUpgradePackage::getGoodsId, Constant.CODEX_GOODS_ID)
- .eq(RenewUpgradePackage::getSkuId, presentSkuId)
- .apply("JSON_CONTAINS(upgrade_sku_ids,'\"" + upgradeSku.getId() + "\"')")
- .eq(RenewUpgradePackage::getStatus, 1)
- .eq(RenewUpgradePackage::getDeleted, 1)
- .orderByAsc(RenewUpgradePackage::getDiscount)
- .last("limit 1"));
- BigDecimal skuPrice = upgradeSku.getPrice();
- if (renewUpgradePackage != null && renewUpgradePackage.getDiscount() != null) {
- skuPrice = skuPrice.multiply(renewUpgradePackage.getDiscount());
- }
- //超出可抵扣的金额 直接返回
- if (deductMoney.compareTo(skuPrice) >= 0) {
- BigDecimal overMoney = deductMoney.subtract(skuPrice);
- //超过抵扣金额可换延长会员多少天
- //每天单价
- BigDecimal daySingle = skuPrice.divide(BigDecimal.valueOf(upgradeSku.getMonths())).divide(BigDecimal.valueOf(30), 0, RoundingMode.DOWN);
- //超出部分可换取多少天 低于每天单价为0天
- BigDecimal extendsDays = overMoney.divide(daySingle, 0, RoundingMode.UP);
- codexDeductResp.setExtendsDays(extendsDays.intValue());
- }
- log.info("codex车票id:{}最终到期时间为:{}车票可返回 抵扣金额:{}", relationId, DateUtil.format(relationExpiryTime, "yyyy-MM-dd HH:mm:ss"), deductMoney);
- codexDeductResp.setDeductMoney(deductMoney);
- return codexDeductResp;
- }
- 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;
- }
- return claudeCodexApiService.getCodexUserOpenAIUsage(codexUser.getUserId(), period);
- }
- @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 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;
- }
- ClaudeCodeResp codexUserDashboard = claudeCodexApiService.getCodexUserDashboard(codexUser.getUserId());
- if (codexUserDashboard != null && codexUserDashboard.getMessage() != null && codexUserDashboard.getMessage().contains("套餐失败")) {
- try {
- createOrUpdateCodexUserPackageApi(codexUser.getUserId(), codexUser.getPlanName(), codexUser.getOpenaiDailyLimit(), codexUser.getOpenaiQuota(), codexUser.getExpiryTime());
- } catch (Exception e) {
- log.error("用户id:{}仪表盘获取套餐失败,重新加载用户套餐", codexUser.getUserId());
- }
- }
- return codexUserDashboard;
- }
-
- @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();
- }
- return claudeCodexApiService.getCodexUserAnalytics(codexUser.getUserId(), start, end, page, limit, order);
- }
- @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("删除操作失败");
- }
- }
- /**
- * 获取订单单价
- */
- 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) {
- OrderDon oriOrderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getRelationId, relationId).in(OrderDon::getUserId, userIdList).notIn(OrderDon::getStatus, Constant.noOrderAllStatus).eq(OrderDon::getOrderType, 1).orderByDesc(OrderDon::getId).last("limit 1"));
- LambdaQueryWrapper<OrderDon> queryWrapper = Wrappers.lambdaQuery(OrderDon.class);
- Long remainDays = DateUtil.betweenDay(now, relationExpiryTime, false) + 1;
- int deductMonth = Math.max(1, BigDecimal.valueOf(remainDays).divide(BigDecimal.valueOf(30), 0, RoundingMode.UP).intValue());
- Date deductStartTime = DateUtil.offsetMonth(now, -deductMonth);
- Date cutoffTime = deductStartTime;
- if (oriOrderDon != null) {
- cutoffTime = DateUtil.compare(oriOrderDon.getCreatedTime(), deductStartTime) > 0 ? oriOrderDon.getCreatedTime() : deductStartTime;
- queryWrapper.ge(OrderDon::getCreatedTime, cutoffTime);
- } else {
- queryWrapper.ge(OrderDon::getCreatedTime, deductStartTime);
- }
- List<OrderDon> orderDonList = orderDonMapper.selectList(queryWrapper
- .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)
- .ge(OrderDon::getCreatedTime, cutoffTime)
- .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)).add(Optional.ofNullable(orderDon.getCouponMoney()).orElse(BigDecimal.ZERO));
- OrderDonGalaxyCoinRecord orderDonGalaxyCoinRecord = orderDonGalaxyCoinRecordMapper.selectOne(Wrappers.lambdaQuery(OrderDonGalaxyCoinRecord.class).eq(OrderDonGalaxyCoinRecord::getOrderId, orderDon.getId()).last("limit 1"));
- if (orderDonGalaxyCoinRecord != null) {
- thisOrderMoney = thisOrderMoney.add(orderDonGalaxyCoinRecord.getDeductMoney());
- }
- 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;
- }
- CodexDeductRecord codexDeductRecord = codexDeductRecordMapper.selectOne(Wrappers.lambdaQuery(CodexDeductRecord.class).eq(CodexDeductRecord::getOrderId, orderDon.getId()).last("limit 1"));
- if (codexDeductRecord != null) {
- totalOrderMoney = totalOrderMoney.add(Optional.ofNullable(codexDeductRecord.getDeductMoney()).orElse(BigDecimal.ZERO));
- }
- //原订单数
- 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(orderDon.getCreatedTime(), "yyyy-MM-dd")) && (DateUtil.betweenDay(thisOrderExpiryTime, relationExpiryTime, true) == 0)) {
- if (codexDeductRecord != null) {
- thisOrderMoney = thisOrderMoney.add(Optional.ofNullable(codexDeductRecord.getDeductMoney()).orElse(BigDecimal.ZERO));
- }
- return thisOrderMoney;
- }
- }
- }
- 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));
- 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());
- }
- }
- @Override
- public boolean delUserPackages(Long userId) {
- return claudeCodexApiService.delCodexUserPackages(userId);
- }
- @Override
- public void handleClaudeCodeUserPackageSku(GroupsRelation relation, GoodsDonSku sku, Long orderId) {
- //更新套餐
- createOrUpdateCodexUserInfo(orderId, relation.getId(), relation.getUserId(), sku, 2);
- }
- /**
- * 校验是否是codex用户
- * @param userId
- * @return
- */
- public Boolean checkCodexUser(Long userId) {
- List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
- Integer count = relationMapper.selectCountByGoodsId(userIdList, Constant.CODEX_GOODS_ID, DateTime.now());
- return count > 0;
- }
- /**
- * 获取codex用户id
- */
- public Long getCodexUserId(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.CODEX_GOODS_ID)
- .field(GroupsRelationMirrorView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
- .build());
- if (groupsRelationMirrorView != null) {
- return groupsRelationMirrorView.getUserId();
- }
- return null;
- }
- }
|