import com.red.circle.OtherServiceApplication; import com.red.circle.other.domain.gateway.user.UserProfileGateway; import com.red.circle.other.domain.model.user.UserProfile; import com.red.circle.other.infra.common.team.decay.ListMemberWorkDecay; import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget; import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService; import com.red.circle.other.inner.model.cmd.team.TeamMemberWorkQryCmd; import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkDTO; import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkDailyTargetDTO; import com.red.circle.tool.core.date.TimestampUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.test.context.junit4.SpringRunner; import java.util.*; import java.util.stream.Collectors; @SpringBootTest(classes = OtherServiceApplication.class) @RunWith(SpringRunner.class) public class AnchorTargetTest { @Autowired private TeamMemberTargetService teamMemberTargetService; @Autowired private ListMemberWorkDecay listMemberWorkDecay; @Autowired private MongoTemplate mongoTemplate; @Autowired private UserProfileGateway userProfileGateway; /** * 扣除主播目标 */ @Test public void AnchorTargetTest(){ Long userId = 1987522531364773890L; Long deductValue = 300000L; // 要扣除的目标值 TeamMemberWorkQryCmd cmd = new TeamMemberWorkQryCmd(); cmd.setMemberUserId(userId); cmd.setSysOrigin("BZIZI"); List execute = listMemberWorkDecay.execute(cmd); // 1. 筛选 billStatus = UNPAID 的数据 List unpaidList = execute.stream() .filter(work -> "UNPAID".equals(work.getBillStatus())) .limit(1) .toList(); System.out.println("未结算的工单数量: " + unpaidList.size()); for (TeamMemberWorkDTO work : unpaidList) { // 2. 统计 dailyTargets 的 acceptGiftValue 的和 Long totalAcceptGiftValue = work.getTarget().getDailyTargets().stream() .mapToLong(TeamMemberWorkDailyTargetDTO::getAcceptGiftValue) .sum(); System.out.println("工单ID: " + work.getId() + ", 总收礼物价值: " + totalAcceptGiftValue); // 3. 检查目标值够不够扣 if (totalAcceptGiftValue < deductValue) { System.out.println("目标值不足,无法扣除。需要: " + deductValue + ", 当前: " + totalAcceptGiftValue); continue; } // 4. 从第一天开始扣除 Long remainingDeduct = deductValue; List dailyTargets = work.getTarget().getDailyTargets(); boolean hasModified = false; // 标记是否有修改 for (int i = 0; i < dailyTargets.size(); i++) { TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i); Long currentValue = dailyTarget.getAcceptGiftValue(); if (remainingDeduct <= 0) { break; } if (currentValue > 0) { // 只有当前值大于0时才可能修改 hasModified = true; // 标记为已修改 if (currentValue >= remainingDeduct) { // 当前天的值足够扣除剩余部分 dailyTarget.setAcceptGiftValue(currentValue - remainingDeduct); System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + remainingDeduct + ", 剩余: " + (currentValue - remainingDeduct)); remainingDeduct = 0L; } else { // 当前天的值不够,全部扣除 dailyTarget.setAcceptGiftValue(0L); remainingDeduct -= currentValue; System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + currentValue + ", 剩余需扣除: " + remainingDeduct); } } } // 5. 只有当有修改时才更新 MongoDB if (hasModified) { updateTeamMemberTarget(work.getId(), dailyTargets); System.out.println("工单 " + work.getId() + " 扣除完成,已更新到MongoDB"); } else { System.out.println("工单 " + work.getId() + " 无需修改,跳过更新"); } } } /** * 批量扣除主播目标 */ @Test public void batchAnchorTargetDeduct() { Map map = Map.ofEntries( Map.entry(22222L, 3750000L), Map.entry(8846195L, 1125000L), Map.entry(8846188L, 150000L), Map.entry(8846174L, 750000L), Map.entry(8846185L, 750000L), Map.entry(8848862L, 6000000L), Map.entry(8849422L, 300000L), Map.entry(8846353L, 300000L) ); // 将account转换为userId并构建batchDeductMap Map batchDeductMap = new HashMap<>(); map.forEach((account, amount) -> { UserProfile userProfile = userProfileGateway.getByAccount("BZIZI", String.valueOf(account)); if (Objects.nonNull(userProfile)) { batchDeductMap.put(userProfile.getId(), amount); } else { throw new RuntimeException("账号不存在:" + account); } }); // 定义批量扣除的用户和金额列表 // Map batchDeductMap = new HashMap<>(); // batchDeductMap.put(1957345312961527809L, 1L); // batchDeductMap.put(1989287471839113218L, 1L); // 可以继续添加更多用户... System.out.println("========== 开始批量扣除 =========="); System.out.println("批量扣除总数: " + batchDeductMap.size()); System.out.println(); // 统计数据 int successCount = 0; // 成功扣除的数量 int failCount = 0; // 失败的数量 int skipCount = 0; // 跳过的数量(目标值不足) long totalDeductValue = 0L; // 总扣除金额 List failedUsers = new ArrayList<>(); // 失败的用户列表 // 循环批量扣除 for (Map.Entry entry : batchDeductMap.entrySet()) { Long userId = entry.getKey(); Long deductValue = entry.getValue(); System.out.println("---------- 处理用户: " + userId + " ----------"); System.out.println("扣除金额: " + deductValue); try { boolean result = deductSingleAnchorTarget(userId, deductValue); if (result) { successCount++; totalDeductValue += deductValue; System.out.println("✓ 用户 " + userId + " 扣除成功"); } else { skipCount++; System.out.println("⊘ 用户 " + userId + " 跳过(目标值不足或无未结算工单)"); } } catch (Exception e) { failCount++; failedUsers.add(userId + " (错误: " + e.getMessage() + ")"); System.out.println("✗ 用户 " + userId + " 扣除失败: " + e.getMessage()); e.printStackTrace(); } System.out.println(); } // 打印统计结果 System.out.println("========== 批量扣除完成 =========="); System.out.println("总处理数: " + batchDeductMap.size()); System.out.println("成功数: " + successCount); System.out.println("跳过数: " + skipCount); System.out.println("失败数: " + failCount); System.out.println("总扣除金额: " + totalDeductValue); System.out.println("成功率: " + String.format("%.2f%%", (successCount * 100.0 / batchDeductMap.size()))); if (!failedUsers.isEmpty()) { System.out.println("\n失败用户列表:"); failedUsers.forEach(user -> System.out.println(" - " + user)); } System.out.println("========================================"); } /** * 单个主播目标扣除(从原方法提取出来) * @param userId 用户ID * @param deductValue 扣除金额 * @return true-成功扣除, false-跳过(目标值不足或无未结算工单) */ private boolean deductSingleAnchorTarget(Long userId, Long deductValue) { TeamMemberWorkQryCmd cmd = new TeamMemberWorkQryCmd(); cmd.setMemberUserId(userId); cmd.setSysOrigin("BZIZI"); List execute = listMemberWorkDecay.execute(cmd); // 1. 筛选 billStatus = UNPAID 的数据 List unpaidList = execute.stream() .filter(work -> "UNPAID".equals(work.getBillStatus())) .limit(1) .toList(); System.out.println("未结算的工单数量: " + unpaidList.size()); if (unpaidList.isEmpty()) { return false; } for (TeamMemberWorkDTO work : unpaidList) { // 2. 统计 dailyTargets 的 acceptGiftValue 的和 Long totalAcceptGiftValue = work.getTarget().getDailyTargets().stream() .mapToLong(TeamMemberWorkDailyTargetDTO::getAcceptGiftValue) .sum(); System.out.println("工单ID: " + work.getId() + ", 总收礼物价值: " + totalAcceptGiftValue); // 3. 检查目标值够不够扣 if (totalAcceptGiftValue < deductValue) { System.out.println("目标值不足,无法扣除。需要: " + deductValue + ", 当前: " + totalAcceptGiftValue); return false; } // 4. 从第一天开始扣除 Long remainingDeduct = deductValue; List dailyTargets = work.getTarget().getDailyTargets(); boolean hasModified = false; // 标记是否有修改 for (int i = 0; i < dailyTargets.size(); i++) { TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i); Long currentValue = dailyTarget.getAcceptGiftValue(); if (remainingDeduct <= 0) { break; } if (currentValue > 0) { // 只有当前值大于0时才可能修改 hasModified = true; // 标记为已修改 if (currentValue >= remainingDeduct) { // 当前天的值足够扣除剩余部分 dailyTarget.setAcceptGiftValue(currentValue - remainingDeduct); System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + remainingDeduct + ", 剩余: " + (currentValue - remainingDeduct)); remainingDeduct = 0L; } else { // 当前天的值不够,全部扣除 dailyTarget.setAcceptGiftValue(0L); remainingDeduct -= currentValue; System.out.println("日期 " + dailyTarget.getDateNumber() + " 扣除: " + currentValue + ", 剩余需扣除: " + remainingDeduct); } } } // 5. 只有当有修改时才更新 MongoDB if (hasModified) { updateTeamMemberTarget(work.getId(), dailyTargets); System.out.println("工单 " + work.getId() + " 扣除完成,已更新到MongoDB"); return true; } else { System.out.println("工单 " + work.getId() + " 无需修改,跳过更新"); return false; } } return false; } /** * 更新 MongoDB 中的 TeamMemberTarget * @param timeId 工单ID * @param dailyTargets 更新后的每日目标列表 */ private void updateTeamMemberTarget(Long timeId, List dailyTargets) { Query query = new Query(Criteria.where("timeId").is(timeId)); // 更新 target.dailyTargets 数组 for (int i = 0; i < dailyTargets.size(); i++) { TeamMemberWorkDailyTargetDTO dailyTarget = dailyTargets.get(i); mongoTemplate.updateFirst(query, new Update() .set("updateTime", TimestampUtils.now()) .set("dailyTargets.$[i].acceptGiftValue", dailyTarget.getAcceptGiftValue()) .set("dailyTargets.$[i].updateTime", TimestampUtils.now()) .filterArray(Criteria.where("i.dateNumber").is(dailyTarget.getDateNumber())), TeamMemberTarget.class); } } }