p-honggang.li
2025-09-03 7307fad287994fce2567bf4a7bdd4b7d3f06ea83
src/main/java/com/webmanage/service/impl/PointsFlowServiceImpl.java
@@ -7,12 +7,17 @@
import com.webmanage.common.BusinessException;
import com.webmanage.common.PageResult;
import com.webmanage.dto.AddPointsFlowDTO;
import com.webmanage.dto.DeductUserPointsDTO;
import com.webmanage.dto.PointsFlowQueryDTO;
import com.webmanage.emun.RuleTypeEnum;
import com.webmanage.entity.PointsFlow;
import com.webmanage.entity.PointsRule;
import com.webmanage.entity.UserPoints;
import com.webmanage.mapper.PointsFlowMapper;
import com.webmanage.mapper.UserPointsMapper;
import com.webmanage.mapper.PointsTransactionMapper;
import com.webmanage.entity.PointsTransaction;
import com.webmanage.service.OrderInfoService;
import com.webmanage.service.PointsFlowService;
import com.webmanage.service.PointsRuleService;
import lombok.extern.slf4j.Slf4j;
@@ -24,6 +29,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 积分流水Service实现类
@@ -38,17 +44,20 @@
    @Resource
    private PointsRuleService pointsRuleService;
    @Resource
    private PointsTransactionMapper pointsTransactionMapper;
    @Override
    public PageResult<PointsFlow> getPersonalPointsFlowPage(PointsFlowQueryDTO queryDTO) {
        if (queryDTO.getUserId() == null) {
        if (!StringUtils.hasText(queryDTO.getUserId())) {
            throw new BusinessException("用户ID不能为空");
        }
        Page<PointsFlow> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("user_id", queryDTO.getUserId());
        wrapper.eq("user_id", queryDTO.getUserId());
        
        buildQueryWrapper(wrapper, queryDTO);
        
@@ -72,8 +81,7 @@
        Page<PointsFlow> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("unit_id", queryDTO.getUnitId());
        wrapper.eq("unit_id", queryDTO.getUnitId());
        
        buildQueryWrapper(wrapper, queryDTO);
        
@@ -118,97 +126,124 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean recordPointsFlow(Long userId, Long unitId, String flowType, String pointsSource,
                                  Integer pointsValue, String orderId, String description) {
        if (userId == null || unitId == null || !StringUtils.hasText(flowType) ||
            !StringUtils.hasText(pointsSource) || pointsValue == null) {
            throw new BusinessException("参数不完整");
        }
        // 创建积分流水记录
        PointsFlow pointsFlow = new PointsFlow();
        pointsFlow.setUserId(userId);
        pointsFlow.setUnitId(unitId);
        pointsFlow.setDataType(flowType);
        pointsFlow.setDataCategory(pointsSource);
        pointsFlow.setPoints(pointsValue);
        pointsFlow.setName(description);
        pointsFlow.setFlowTime(LocalDateTime.now());
        boolean saved = save(pointsFlow);
        if (!saved) {
            throw new BusinessException("保存积分流水失败");
        }
        // 更新用户积分
        updateUserPoints(userId, unitId, pointsValue);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addPointsFlowByRule(AddPointsFlowDTO addPointsFlowDTO) {
        if (addPointsFlowDTO == null) {
            throw new BusinessException("参数不能为空");
        }
        Long userId = addPointsFlowDTO.getUserId();
        Long unitId = addPointsFlowDTO.getUnitId();
        String ruleType = addPointsFlowDTO.getRuleType();
        String ruleName = addPointsFlowDTO.getRuleName();
        String userId = addPointsFlowDTO.getUserId();
        String providerId = addPointsFlowDTO.getProviderId();
        String unitId = addPointsFlowDTO.getUnitId();
        Integer ruleType = addPointsFlowDTO.getRuleType();
        String category = addPointsFlowDTO.getCategory();
        String ruleNameCode = addPointsFlowDTO.getRuleNameCode();
        Integer count = addPointsFlowDTO.getCount() != null ? addPointsFlowDTO.getCount() : 1;
        // 查询积分规则
        PointsRule pointsRule = pointsRuleService.getRuleByTriggerCondition(ruleName);
        if (pointsRule == null) {
            throw new BusinessException("积分规则不存在或未启用: " + ruleName);
        boolean applyUser = StringUtils.hasText(userId) ;
        boolean applyProvider = StringUtils.hasText(providerId) ;;
        if (!applyUser && !applyProvider) {
            throw new BusinessException("userId 与 providerId 不能同时为空");
        }
        // 验证规则类型是否匹配
        if (!ruleType.equals(pointsRule.getRuleType())) {
            throw new BusinessException("规则类型不匹配,期望: " + pointsRule.getRuleType() + ",实际: " + ruleType);
        // 分别获取用户侧/提供者侧最新生效规则(按 points_winner 过滤:1用户、0提供者)
        PointsRule userRule = null;
        PointsRule providerRule = null;
        if (applyUser) {
            userRule = getLatestEffectiveRule(ruleType, ruleNameCode, category, 1);
            if (userRule == null) {
                throw new BusinessException("未找到用户侧生效规则: ruleType=" + ruleType + ", ruleNameCode=" + ruleNameCode + ", category=" + category + ", points_winner=1");
            }
            if (!ruleType.equals(userRule.getRuleType())) {
                throw new BusinessException("用户侧规则类型不匹配,期望: " + userRule.getRuleType() + ",实际: " + ruleType);
            }
        }
        if (applyProvider) {
            providerRule = getLatestEffectiveRule(ruleType, ruleNameCode, category, 0);
            if (providerRule == null) {
                throw new BusinessException("未找到提供者侧生效规则: ruleType=" + ruleType + ", ruleNameCode=" + ruleNameCode + ", category=" + category + ", points_winner=0");
            }
            if (!ruleType.equals(providerRule.getRuleType())) {
                throw new BusinessException("提供者侧规则类型不匹配,期望: " + providerRule.getRuleType() + ",实际: " + ruleType);
            }
        }
        // 计算积分值
        Integer basePoints = pointsRule.getPointsValue() != null ? pointsRule.getPointsValue() : 0;
        Integer totalPoints = basePoints * count;
        // 如果是消费类型,积分为负数
        if ("消费".equals(ruleType)) {
            totalPoints = -totalPoints;
        // 计算两侧积分变化(各自按规则计算)
        int userPointsChange = 0;
        int providerPointsChange = 0;
        if (applyUser) {
            int base = userRule.getPointsValue() != null ? userRule.getPointsValue() : 0;
            int amount = base * count;
            userPointsChange = (ruleType == RuleTypeEnum.CONSUME.getCode()) ? -Math.abs(amount) : Math.abs(amount);
        }
        if (applyProvider) {
            int base = providerRule.getPointsValue() != null ? providerRule.getPointsValue() : 0;
            int amount = base * count;
            providerPointsChange = (ruleType == RuleTypeEnum.CONSUME.getCode()) ? -Math.abs(amount) : Math.abs(amount);
        }
        // 检查每日积分上限
        if (basePoints > 0 && pointsRule.getPriority() != null && pointsRule.getPriority() > 0) {
            checkDailyLimit(userId, unitId, ruleName, totalPoints, pointsRule.getPriority());
        // 每日上限校验(分别校验)
        if (applyUser && userRule.getIsLimit() != null && userRule.getIsLimit() == 0) {
            checkDailyLimitByRule(userId, unitId, userRule, userPointsChange);
        }
        if (applyProvider && providerRule.getIsLimit() != null && providerRule.getIsLimit() == 0) {
            checkDailyLimitByRule(providerId, providerId, providerRule, providerPointsChange);
        }
        // 创建积分流水记录
        PointsFlow pointsFlow = new PointsFlow();
        pointsFlow.setUserId(userId);
        pointsFlow.setUnitId(unitId);
        pointsFlow.setDataType(ruleType);
        pointsFlow.setDataCategory(ruleName);
        pointsFlow.setPoints(totalPoints);
        pointsFlow.setName(addPointsFlowDTO.getDescription() != null ? addPointsFlowDTO.getDescription() : pointsRule.getRuleDescription());
        pointsFlow.setFlowTime(LocalDateTime.now());
        boolean saved = save(pointsFlow);
        if (!saved) {
            throw new BusinessException("保存积分流水失败");
        // 余额校验(仅在扣减时)
        if (applyUser && userPointsChange < 0) {
            checkBalanceSufficient(userId, unitId, Math.abs(userPointsChange));
        }
        if (applyProvider && providerPointsChange < 0) {
            checkBalanceSufficient(providerId, providerId, Math.abs(providerPointsChange));
        }
        // 更新用户积分账户
        updateUserPointsByRule(userId, unitId, totalPoints, ruleType);
        // 生成用户侧流水并更新账户
        if (applyUser && userPointsChange != 0) {
            PointsFlow pointsFlow = new PointsFlow();
            pointsFlow.setUserId(userId);
            pointsFlow.setUnitId(unitId);
            pointsFlow.setDataType(ruleType);
            pointsFlow.setDataCategory(addPointsFlowDTO.getCategory());
            pointsFlow.setPoints(userPointsChange);
            pointsFlow.setName(addPointsFlowDTO.getDescription() != null ? addPointsFlowDTO.getDescription() : userRule.getRuleDescription());
            pointsFlow.setFlowTime(LocalDateTime.now());
            pointsFlow.setRlueId(userRule.getId());
            boolean saved = save(pointsFlow);
            if (!saved) {
                throw new BusinessException("保存积分流水失败");
            }
            updateUserPointsByRule(userId, unitId, userPointsChange);
        }
        // 生成提供者侧流水并更新账户
        if (applyProvider && providerPointsChange != 0) {
            PointsFlow providerFlow = new PointsFlow();
            providerFlow.setUserId(providerId);
            providerFlow.setUnitId(providerId);
            providerFlow.setDataType(ruleType);
            providerFlow.setDataCategory(addPointsFlowDTO.getCategory());
            providerFlow.setPoints(providerPointsChange);
            providerFlow.setName(addPointsFlowDTO.getDescription() != null ? addPointsFlowDTO.getDescription() : providerRule.getRuleDescription());
            providerFlow.setFlowTime(LocalDateTime.now());
            providerFlow.setRlueId(providerRule.getId());
            boolean providerSaved = save(providerFlow);
            if (!providerSaved) {
                throw new BusinessException("保存提供者积分流水失败");
            }
            updateProviderUnitPoints(providerId, providerPointsChange);
        }
        return true;
    }
    @Override
    public Integer getUserPointsTotal(Long userId) {
        if (userId == null) {
            return 0;
    public UserPoints getUserPointsTotal(String userId) {
        if (!StringUtils.hasText(userId)) {
            throw new BusinessException("用户ID不能为null");
        }
        
        QueryWrapper<UserPoints> wrapper = new QueryWrapper<>();
@@ -216,13 +251,13 @@
               .eq("user_id", userId);
        
        UserPoints userPoints = userPointsMapper.selectOne(wrapper);
        return userPoints != null ? userPoints.getBalance() : 0;
        return userPoints ;
    }
    @Override
    public Integer getUnitPointsTotal(Long unitId) {
    public UserPoints getUnitPointsTotal(Long unitId) {
        if (unitId == null) {
            return 0;
            throw new BusinessException("用户ID不能为null");
        }
        
        QueryWrapper<UserPoints> wrapper = new QueryWrapper<>();
@@ -230,15 +265,37 @@
               .eq("unit_id", unitId);
        
        UserPoints userPoints = userPointsMapper.selectOne(wrapper);
        return userPoints != null ? userPoints.getBalance() : 0;
        return userPoints;
    }
    @Override
    public List<String> getPointsFlowCategories() {
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT data_category")
               .isNotNull("data_category")
               .ne("data_category", "")
               .ne("data_category", "null")
               .eq("deleted", 0)
               .orderByAsc("data_category");
        List<PointsFlow> flows = list(wrapper);
        return flows.stream()
                .map(PointsFlow::getDataCategory)
                .filter(category -> category != null && !category.trim().isEmpty())
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }
    /**
     * 构建查询条件
     */
    private void buildQueryWrapper(QueryWrapper<PointsFlow> wrapper, PointsFlowQueryDTO queryDTO) {
        if (StringUtils.hasText(queryDTO.getFlowType())) {
            wrapper.eq("flow_type", queryDTO.getFlowType());
        if(StringUtils.hasText(queryDTO.getDataCategory())){
            wrapper.eq("data_category", queryDTO.getDataCategory());
        }
        if (queryDTO.getDataType()!=null) {
            wrapper.eq("data_type", queryDTO.getDataType());
        }
        if (StringUtils.hasText(queryDTO.getPointsSource())) {
            wrapper.eq("points_source", queryDTO.getPointsSource());
@@ -246,18 +303,107 @@
        if (StringUtils.hasText(queryDTO.getOrderId())) {
            wrapper.eq("order_id", queryDTO.getOrderId());
        }
        if (queryDTO.getStartTime() != null) {
            wrapper.ge("flow_time", queryDTO.getStartTime());
        if (queryDTO.getFlowEndTime() != null) {
            wrapper.ge("flow_time", queryDTO.getFlowStartTime());
        }
        if (queryDTO.getEndTime() != null) {
            wrapper.le("flow_time", queryDTO.getEndTime());
        if (queryDTO.getFlowEndTime() != null) {
            wrapper.le("flow_time", queryDTO.getFlowEndTime());
        }
        
        wrapper.orderByDesc("flow_time");
    }
    /**
     * 检查每日积分上限
     * 根据ruleType、ruleNameCode、category查询生效时间最新的积分规则
     */
    private PointsRule getLatestEffectiveRule(Integer ruleType, String ruleNameCode, String category) {
        QueryWrapper<PointsRule> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("is_enabled", 0) // 0表示启用
               .eq("rule_type", ruleType)
               .eq("rule_name_code", ruleNameCode)
               .eq("category", category)
               .orderByDesc("created_at") // 按创建时间倒序,获取最新的规则
               .last("LIMIT 1");
        return pointsRuleService.getOne(wrapper);
    }
    /**
     * 根据ruleType、ruleNameCode、category、points_winner查询生效时间最新的积分规则
     */
    private PointsRule getLatestEffectiveRule(Integer ruleType, String ruleNameCode, String category, Integer pointsWinner) {
        QueryWrapper<PointsRule> wrapper = new QueryWrapper<>();
        wrapper.eq("is_enabled", 0)
               .eq("rule_type", ruleType)
               .eq("rule_name_code", ruleNameCode)
               .eq("category", category)
               .eq(pointsWinner != null, "points_winner", pointsWinner)
               .orderByDesc("created_at")
               .last("LIMIT 1");
        return pointsRuleService.getOne(wrapper);
    }
    /**
     * 检查每日积分上限(基于规则)
     */
    private void checkDailyLimitByRule(String userId, String unitId, PointsRule pointsRule, Integer currentPoints) {
        // 获取今日开始和结束时间
        LocalDate today = LocalDate.now();
        LocalDateTime startOfDay = today.atStartOfDay();
        LocalDateTime endOfDay = today.atTime(23, 59, 59);
        // 查询今日该规则的积分流水
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("user_id", userId)
               .eq("unit_id", unitId)
//               .eq("data_category", pointsRule.getRuleName())
                .eq("rule_id",pointsRule.getId())
               .ge("flow_time", startOfDay)
               .le("flow_time", endOfDay);
        List<PointsFlow> todayFlows = list(wrapper);
        // 计算今日累计积分
        int todayTotal = todayFlows.stream()
                .mapToInt(flow -> flow.getPoints() != null ? flow.getPoints() : 0)
                .sum();
        // 获取规则的每日积分上限
        Integer dailyLimit = pointsRule.getDailyLimit();
        if (dailyLimit != null && dailyLimit > 0) {
            // 如果今日累计积分超过每日上限,则抛出异常
            if (Math.abs(todayTotal) >= dailyLimit) {
                throw new BusinessException("今日该规则积分已达上限: " + dailyLimit);
            }
            // 如果加上当前积分会超过每日上限,则抛出异常
            if (Math.abs(todayTotal + currentPoints) > dailyLimit) {
                throw new BusinessException("本次积分操作将超过每日上限: " + dailyLimit + ",当前已累计: " + Math.abs(todayTotal));
            }
        }
    }
    /**
     * 检查积分余额是否足够
     */
    private void checkBalanceSufficient(String userId, String unitId, Integer requiredPoints) {
        // 仅检查个人积分余额(移除单位余额判定)
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
                  .eq("user_id", userId);
        UserPoints userPoints = userPointsMapper.selectOne(userWrapper);
        if (userPoints == null || userPoints.getBalance() < requiredPoints) {
            throw new BusinessException("个人积分余额不足,当前余额: " + (userPoints != null ? userPoints.getBalance() : 0) + ",需要扣除: " + requiredPoints);
        }
        // 原单位余额校验已移除
    }
    /**
     * 检查每日积分上限(旧方法,保留兼容性)
     */
    private void checkDailyLimit(Long userId, Long unitId, String ruleName, Integer currentPoints, Integer priority) {
        // 获取今日开始和结束时间
@@ -290,7 +436,7 @@
    /**
     * 更新用户积分
     */
    private void updateUserPoints(Long userId, Long unitId, Integer pointsValue) {
    private void updateUserPoints(String userId, String unitId, Integer pointsValue) {
        // 更新个人积分
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
@@ -331,7 +477,7 @@
    /**
     * 根据规则更新用户积分账户
     */
    private void updateUserPointsByRule(Long userId, Long unitId, Integer pointsValue, String ruleType) {
    private void updateUserPointsByRule(String userId, String unitId, Integer pointsValue) {
        // 更新个人积分账户
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
@@ -339,6 +485,11 @@
        
        UserPoints userPoints = userPointsMapper.selectOne(userWrapper);
        if (userPoints == null) {
            // 如果是新用户且是扣积分操作,余额不足
            if (pointsValue < 0) {
                throw new BusinessException("积分余额不足,无法扣除积分");
            }
            userPoints = new UserPoints();
            userPoints.setUserId(userId);
            userPoints.setUnitId(unitId);
@@ -347,6 +498,11 @@
            userPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(userPoints);
        } else {
            // 检查扣积分时余额是否足够
            if (pointsValue < 0 && userPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("积分余额不足,当前余额: " + userPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            userPoints.setBalance(userPoints.getBalance() + pointsValue);
            
            // 更新累计获取积分
@@ -372,6 +528,11 @@
        
        UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper);
        if (unitPoints == null) {
            // 如果是新单位且是扣积分操作,余额不足
            if (pointsValue < 0) {
                throw new BusinessException("单位积分余额不足,无法扣除积分");
            }
            unitPoints = new UserPoints();
            unitPoints.setUserId(userId);
            unitPoints.setUnitId(unitId);
@@ -380,6 +541,11 @@
            unitPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(unitPoints);
        } else {
            // 检查扣积分时余额是否足够
            if (pointsValue < 0 && unitPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("单位积分余额不足,当前余额: " + unitPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            unitPoints.setBalance(unitPoints.getBalance() + pointsValue);
            
            // 更新累计获取积分
@@ -398,4 +564,168 @@
            userPointsMapper.updateById(unitPoints);
        }
    }
    /**
     * 扣减用户积分
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deductUserPoints(DeductUserPointsDTO deductDTO) {
        try {
            String userId = deductDTO.getUserId();
            String providerId = deductDTO.getProviderId();
            String unitId = deductDTO.getUnitId();
            Integer points = deductDTO.getPoints();
            String orderId = deductDTO.getOrderId();
            String remark = deductDTO.getRemark();
            String dataCategory = deductDTO.getDataCategory();
            Integer dataType = deductDTO.getDataType();
            if (!StringUtils.hasText(userId)) {
                throw new BusinessException("用户ID不能为空");
            }
            if (points == null || points <= 0) {
                throw new BusinessException("扣减积分数量必须大于0");
            }
            // 检查用户积分余额是否充足
            checkBalanceSufficient(userId, unitId, points);
            // 创建积分流水记录
            PointsFlow pointsFlow = new PointsFlow();
            pointsFlow.setUserId(userId);
            pointsFlow.setUnitId(unitId);
            pointsFlow.setDataCategory(dataCategory != null ? dataCategory : "积分交易");
            pointsFlow.setDataType(dataType != null ? dataType : 1);
            pointsFlow.setPoints(-points); // 负数表示扣减
            pointsFlow.setName(remark != null ? remark : "积分扣减"); // name字段存储remark内容
            pointsFlow.setFlowTime(LocalDateTime.now());
            pointsFlow.setRlueId(null); // 直接扣减,不关联规则
            boolean saved = save(pointsFlow);
            if (!saved) {
                throw new BusinessException("保存积分流水失败");
            }
            // 更新用户积分账户
            updateUserPointsOnly(userId, -points);
            // 新增积分交易记录(与流水同事务)
            PointsTransaction trans = new PointsTransaction();
            // tb_points_transaction 的 chk_data_category 仅允许 '用户参与'、'其他'
            // 这里将业务类目映射为数据库允许的值
            trans.setDataCategory("用户参与");
            trans.setTransactionName(pointsFlow.getName());
            trans.setTransactionTime(LocalDateTime.now());
            trans.setPointsChange(-points);
            trans.setRuleType("消耗");
            try {
                trans.setUserId(Long.valueOf(userId));
            } catch (Exception ignore) {}
            try {
                if (StringUtils.hasText(unitId)) trans.setUnitId(Long.valueOf(unitId));
            } catch (Exception ignore) {}
            trans.setUserType("个人用户");
            trans.setRuleId(null);
            trans.setDetailId(null);
            trans.setCreatedAt(LocalDateTime.now());
            trans.setDeleted(0);
            int inserted = pointsTransactionMapper.insert(trans);
            log.info("Points transaction inserted rows={}, id={}", inserted, trans.getId());
            if (inserted <= 0 || trans.getId() == null) {
                throw new BusinessException("保存积分交易记录失败");
            }
            // 为提供者新增积分
            AddPointsFlowDTO addPointsFlowDTO = new AddPointsFlowDTO();
            addPointsFlowDTO.setCategory("资源交易");
            addPointsFlowDTO.setCount(1);
            addPointsFlowDTO.setProviderId(providerId);
            addPointsFlowDTO.setRuleType(0);
            addPointsFlowDTO.setRuleNameCode("digital_product_transaction");
            addPointsFlowDTO.setDescription("产品交易");
            addPointsFlowByRule(addPointsFlowDTO);
            return true;
        } catch (Exception e) {
            log.error("扣减用户积分失败", e);
            throw new BusinessException("扣减用户积分失败:" + e.getMessage());
        }
    }
    /**
     * 仅更新提供者(单位)积分账户
     */
    private void updateProviderUnitPoints(String providerUnitId, Integer pointsValue) {
        QueryWrapper<UserPoints> unitWrapper = new QueryWrapper<>();
        unitWrapper.eq("deleted", 0)
                  .eq("unit_id", providerUnitId);
        UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper);
        if (unitPoints == null) {
            if (pointsValue < 0) {
                throw new BusinessException("提供者积分余额不足,无法扣除积分");
            }
            unitPoints = new UserPoints();
            unitPoints.setUserId(null);
            unitPoints.setUnitId(providerUnitId);
            unitPoints.setBalance(pointsValue);
            unitPoints.setTotalEarned(pointsValue > 0 ? pointsValue : 0);
            unitPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(unitPoints);
        } else {
            if (pointsValue < 0 && unitPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("提供者积分余额不足,当前余额: " + unitPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            unitPoints.setBalance(unitPoints.getBalance() + pointsValue);
            if (pointsValue > 0) {
                unitPoints.setTotalEarned(unitPoints.getTotalEarned() != null ?
                        unitPoints.getTotalEarned() + pointsValue : pointsValue);
            }
            if (pointsValue < 0) {
                unitPoints.setTotalConsumed(unitPoints.getTotalConsumed() != null ?
                        unitPoints.getTotalConsumed() + Math.abs(pointsValue) : Math.abs(pointsValue));
            }
            unitPoints.setUpdateTime(LocalDateTime.now());
            userPointsMapper.updateById(unitPoints);
        }
    }
    /**
     * 仅更新个人积分账户(不操作单位账户)
     */
    private void updateUserPointsOnly(String userId, Integer pointsValue) {
        // 更新个人积分账户
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
                  .eq("user_id", userId);
        UserPoints userPoints = userPointsMapper.selectOne(userWrapper);
        if (userPoints == null) {
            if (pointsValue < 0) {
                throw new BusinessException("个人积分余额不足,无法扣除积分");
            }
            userPoints = new UserPoints();
            userPoints.setUserId(userId);
            userPoints.setUnitId(null);
            userPoints.setBalance(pointsValue);
            userPoints.setTotalEarned(pointsValue > 0 ? pointsValue : 0);
            userPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(userPoints);
        } else {
            if (pointsValue < 0 && userPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("个人积分余额不足,当前余额: " + userPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            userPoints.setBalance(userPoints.getBalance() + pointsValue);
            if (pointsValue > 0) {
                userPoints.setTotalEarned(userPoints.getTotalEarned() != null ? userPoints.getTotalEarned() + pointsValue : pointsValue);
            }
            if (pointsValue < 0) {
                userPoints.setTotalConsumed(userPoints.getTotalConsumed() != null ? userPoints.getTotalConsumed() + Math.abs(pointsValue) : Math.abs(pointsValue));
            }
            userPoints.setUpdateTime(LocalDateTime.now());
            userPointsMapper.updateById(userPoints);
        }
    }
}