| | |
| | | import com.webmanage.common.PageResult; |
| | | import com.webmanage.dto.AddPointsFlowDTO; |
| | | 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 java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 积分流水Service实现类 |
| | |
| | | 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); |
| | | |
| | |
| | | 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); |
| | | |
| | |
| | | |
| | | @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(); |
| | | 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); |
| | | // 根据ruleType、ruleNameCode、category查询生效时间最新的积分规则 |
| | | PointsRule pointsRule = getLatestEffectiveRule(ruleType, ruleNameCode, category); |
| | | if (pointsRule == null) { |
| | | throw new BusinessException("积分规则不存在或未启用: " + ruleName); |
| | | throw new BusinessException("积分规则不存在或未启用: ruleType=" + ruleType + ", ruleNameCode=" + ruleNameCode + ", category=" + category); |
| | | } |
| | | |
| | | // 验证规则类型是否匹配 |
| | |
| | | Integer totalPoints = basePoints * count; |
| | | |
| | | // 如果是消费类型,积分为负数 |
| | | if ("消费".equals(ruleType)) { |
| | | if (ruleType == RuleTypeEnum.CONSUME.getCode()) { // 1表示消费类型 |
| | | totalPoints = -totalPoints; |
| | | } |
| | | |
| | | // 检查每日积分上限 |
| | | if (basePoints > 0 && pointsRule.getPriority() != null && pointsRule.getPriority() > 0) { |
| | | checkDailyLimit(userId, unitId, ruleName, totalPoints, pointsRule.getPriority()); |
| | | if (pointsRule.getIsLimit() != null && pointsRule.getIsLimit() == 0) { // 0表示有每日上限 |
| | | checkDailyLimitByRule(userId, unitId, pointsRule, totalPoints); |
| | | } |
| | | |
| | | // 如果是扣积分操作,先检查余额是否足够 |
| | | if (totalPoints < 0) { |
| | | checkBalanceSufficient(userId, unitId, Math.abs(totalPoints)); |
| | | } |
| | | |
| | | // 创建积分流水记录 |
| | |
| | | pointsFlow.setUserId(userId); |
| | | pointsFlow.setUnitId(unitId); |
| | | pointsFlow.setDataType(ruleType); |
| | | pointsFlow.setDataCategory(ruleName); |
| | | pointsFlow.setDataCategory(addPointsFlowDTO.getCategory()); |
| | | pointsFlow.setPoints(totalPoints); |
| | | pointsFlow.setName(addPointsFlowDTO.getDescription() != null ? addPointsFlowDTO.getDescription() : pointsRule.getRuleDescription()); |
| | | pointsFlow.setFlowTime(LocalDateTime.now()); |
| | | pointsFlow.setRlueId(pointsRule.getId()); |
| | | |
| | | boolean saved = save(pointsFlow); |
| | | if (!saved) { |
| | |
| | | } |
| | | |
| | | // 更新用户积分账户 |
| | | updateUserPointsByRule(userId, unitId, totalPoints, ruleType); |
| | | updateUserPointsByRule(userId, unitId, totalPoints); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public Integer getUserPointsTotal(Long userId) { |
| | | public UserPoints getUserPointsTotal(Long userId) { |
| | | if (userId == null) { |
| | | return 0; |
| | | throw new BusinessException("用户ID不能为null"); |
| | | } |
| | | |
| | | QueryWrapper<UserPoints> wrapper = new QueryWrapper<>(); |
| | |
| | | .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<>(); |
| | |
| | | .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()); |
| | |
| | | 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); |
| | | } |
| | | |
| | | /** |
| | | * 检查每日积分上限(基于规则) |
| | | */ |
| | | private void checkDailyLimitByRule(Long userId, Long 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(Long userId, Long 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); |
| | | } |
| | | |
| | | // 检查单位积分余额 |
| | | QueryWrapper<UserPoints> unitWrapper = new QueryWrapper<>(); |
| | | unitWrapper.eq("deleted", 0) |
| | | .eq("unit_id", unitId); |
| | | |
| | | UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper); |
| | | if (unitPoints == null || unitPoints.getBalance() < requiredPoints) { |
| | | throw new BusinessException("单位积分余额不足,当前余额: " + (unitPoints != null ? unitPoints.getBalance() : 0) + ",需要扣除: " + requiredPoints); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 检查每日积分上限(旧方法,保留兼容性) |
| | | */ |
| | | private void checkDailyLimit(Long userId, Long unitId, String ruleName, Integer currentPoints, Integer priority) { |
| | | // 获取今日开始和结束时间 |
| | |
| | | /** |
| | | * 根据规则更新用户积分账户 |
| | | */ |
| | | private void updateUserPointsByRule(Long userId, Long unitId, Integer pointsValue, String ruleType) { |
| | | private void updateUserPointsByRule(Long userId, Long unitId, Integer pointsValue) { |
| | | // 更新个人积分账户 |
| | | QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>(); |
| | | userWrapper.eq("deleted", 0) |
| | |
| | | |
| | | UserPoints userPoints = userPointsMapper.selectOne(userWrapper); |
| | | if (userPoints == null) { |
| | | // 如果是新用户且是扣积分操作,余额不足 |
| | | if (pointsValue < 0) { |
| | | throw new BusinessException("积分余额不足,无法扣除积分"); |
| | | } |
| | | |
| | | userPoints = new UserPoints(); |
| | | userPoints.setUserId(userId); |
| | | userPoints.setUnitId(unitId); |
| | |
| | | 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); |
| | | |
| | | // 更新累计获取积分 |
| | |
| | | |
| | | UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper); |
| | | if (unitPoints == null) { |
| | | // 如果是新单位且是扣积分操作,余额不足 |
| | | if (pointsValue < 0) { |
| | | throw new BusinessException("单位积分余额不足,无法扣除积分"); |
| | | } |
| | | |
| | | unitPoints = new UserPoints(); |
| | | unitPoints.setUserId(userId); |
| | | unitPoints.setUnitId(unitId); |
| | |
| | | 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); |
| | | |
| | | // 更新累计获取积分 |