diff --git a/play-admin/src/main/java/com/starry/admin/modules/order/service/impl/PlayOrderInfoServiceImpl.java b/play-admin/src/main/java/com/starry/admin/modules/order/service/impl/PlayOrderInfoServiceImpl.java index e1d9576..89d308f 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/order/service/impl/PlayOrderInfoServiceImpl.java +++ b/play-admin/src/main/java/com/starry/admin/modules/order/service/impl/PlayOrderInfoServiceImpl.java @@ -241,7 +241,6 @@ public class PlayOrderInfoServiceImpl extends ServiceImpl listByEndTime(String clerkId, LocalDateTime endTime) { MPJLambdaWrapper lambdaQueryWrapper = new MPJLambdaWrapper<>(); lambdaQueryWrapper.eq(PlayOrderInfoEntity::getAcceptBy, clerkId); - lambdaQueryWrapper.eq(PlayOrderInfoEntity::getOrderStatus, OrderStatus.COMPLETED.getCode()); lambdaQueryWrapper.lt(PlayOrderInfoEntity::getOrderEndTime, endTime); lambdaQueryWrapper.eq(PlayOrderInfoEntity::getOrderSettlementState, "0"); return this.baseMapper.selectList(lambdaQueryWrapper); diff --git a/play-admin/src/main/java/com/starry/admin/modules/statistics/controller/PlayClerkPerformanceController.java b/play-admin/src/main/java/com/starry/admin/modules/statistics/controller/PlayClerkPerformanceController.java index e578243..4bc84d6 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/statistics/controller/PlayClerkPerformanceController.java +++ b/play-admin/src/main/java/com/starry/admin/modules/statistics/controller/PlayClerkPerformanceController.java @@ -5,6 +5,7 @@ import com.starry.admin.modules.clerk.module.entity.PlayClerkLevelInfoEntity; import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity; import com.starry.admin.modules.clerk.service.IPlayClerkLevelInfoService; import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService; +import com.starry.admin.modules.order.module.constant.OrderConstant; import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity; import com.starry.admin.modules.order.service.IPlayOrderInfoService; import com.starry.admin.modules.personnel.module.entity.PlayPersonnelGroupInfoEntity; @@ -209,6 +210,7 @@ public class PlayClerkPerformanceController { int orderContinueNumber = 0; int orderRefundNumber = 0; int ordersExpiredNumber = 0; + int completedOrders = 0; BigDecimal orderMoney = BigDecimal.ZERO; BigDecimal finalAmount = BigDecimal.ZERO; BigDecimal orderFirstAmount = BigDecimal.ZERO; @@ -217,6 +219,10 @@ public class PlayClerkPerformanceController { BigDecimal orderRefundAmount = BigDecimal.ZERO; BigDecimal estimatedRevenue = BigDecimal.ZERO; for (PlayOrderInfoEntity orderInfoEntity : orderInfoEntities) { + if (!isCompletedOrder(orderInfoEntity)) { + continue; + } + completedOrders++; customIds.add(orderInfoEntity.getPurchaserBy()); finalAmount = finalAmount.add(orderInfoEntity.getFinalAmount()); orderMoney = orderMoney.add(orderInfoEntity.getOrderMoney()); @@ -238,7 +244,7 @@ public class PlayClerkPerformanceController { } } PlayClerkPerformanceInfoReturnVo returnVo = new PlayClerkPerformanceInfoReturnVo(); - returnVo.setOrderNumber(orderInfoEntities.size()); + returnVo.setOrderNumber(completedOrders); returnVo.setOrderContinueNumber(orderContinueNumber); returnVo.setOrderRefundNumber(orderRefundNumber); returnVo.setOrdersExpiredNumber(ordersExpiredNumber); @@ -281,6 +287,7 @@ public class PlayClerkPerformanceController { int orderContinueNumber = 0; int orderRefundNumber = 0; int ordersExpiredNumber = 0; + int completedOrders = 0; BigDecimal orderMoney = BigDecimal.ZERO; BigDecimal finalAmount = BigDecimal.ZERO; BigDecimal orderFirstAmount = BigDecimal.ZERO; @@ -289,6 +296,10 @@ public class PlayClerkPerformanceController { BigDecimal orderRefundAmount = BigDecimal.ZERO; BigDecimal estimatedRevenue = BigDecimal.ZERO; for (PlayOrderInfoEntity orderInfoEntity : itemOrderInfo) { + if (!isCompletedOrder(orderInfoEntity)) { + continue; + } + completedOrders++; customIds.add(orderInfoEntity.getPurchaserBy()); finalAmount = finalAmount.add(orderInfoEntity.getFinalAmount()); orderMoney = orderMoney.add(orderInfoEntity.getOrderMoney()); @@ -311,7 +322,7 @@ public class PlayClerkPerformanceController { } PlayClerkPerformanceInfoReturnVo returnVo = new PlayClerkPerformanceInfoReturnVo(); returnVo.setPerformanceDate(performanceDate); - returnVo.setOrderNumber(itemOrderInfo.size()); + returnVo.setOrderNumber(completedOrders); returnVo.setOrderContinueNumber(orderContinueNumber); returnVo.setOrderRefundNumber(orderRefundNumber); returnVo.setOrdersExpiredNumber(ordersExpiredNumber); @@ -326,4 +337,9 @@ public class PlayClerkPerformanceController { return returnVo; } + private boolean isCompletedOrder(PlayOrderInfoEntity orderInfoEntity) { + return orderInfoEntity != null + && OrderConstant.OrderStatus.COMPLETED.getCode().equals(orderInfoEntity.getOrderStatus()); + } + } diff --git a/play-admin/src/main/java/com/starry/admin/modules/statistics/service/impl/PlayClerkPerformanceServiceImpl.java b/play-admin/src/main/java/com/starry/admin/modules/statistics/service/impl/PlayClerkPerformanceServiceImpl.java index 5b38ec8..2c326f3 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/statistics/service/impl/PlayClerkPerformanceServiceImpl.java +++ b/play-admin/src/main/java/com/starry/admin/modules/statistics/service/impl/PlayClerkPerformanceServiceImpl.java @@ -77,6 +77,7 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer int orderContinueNumber = 0; int orderRefundNumber = 0; int ordersExpiredNumber = 0; + int completedOrderCount = 0; BigDecimal finalAmount = BigDecimal.ZERO; BigDecimal orderFirstAmount = BigDecimal.ZERO; BigDecimal orderTotalAmount = BigDecimal.ZERO; @@ -84,6 +85,10 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer BigDecimal orderRefundAmount = BigDecimal.ZERO; for (PlayOrderInfoEntity orderInfoEntity : orderInfoEntities) { + if (!isCompletedOrder(orderInfoEntity)) { + continue; + } + completedOrderCount++; customIds.add(orderInfoEntity.getPurchaserBy()); finalAmount = finalAmount.add(defaultZero(orderInfoEntity.getFinalAmount())); if (OrderConstant.YesNoFlag.YES.getCode().equals(orderInfoEntity.getFirstOrder())) { @@ -121,7 +126,7 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer returnVo.setGroupName(infoEntity.getGroupName()); } } - returnVo.setOrderNumber(orderInfoEntities.size()); + returnVo.setOrderNumber(completedOrderCount); returnVo.setOrderContinueNumber(orderContinueNumber); returnVo.setOrderRefundNumber(orderRefundNumber); returnVo.setOrdersExpiredNumber(ordersExpiredNumber); @@ -223,7 +228,10 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer private List buildTrend(List orders, DateRange range, int trendDays) { - if (CollectionUtil.isEmpty(orders)) { + List completedOrders = orders.stream() + .filter(this::isCompletedOrder) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(completedOrders)) { return buildEmptyTrend(range, trendDays); } LocalDate end = range.endDate; @@ -231,7 +239,7 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer if (start.isBefore(range.startDate)) { start = range.startDate; } - Map> grouped = orders.stream() + Map> grouped = completedOrders.stream() .filter(order -> order.getPurchaserTime() != null) .collect(Collectors.groupingBy(order -> order.getPurchaserTime().toLocalDate())); List points = new ArrayList<>(); @@ -421,6 +429,7 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer return BigDecimal.ZERO; } List orderIds = orders.stream() + .filter(this::isCompletedOrder) .map(PlayOrderInfoEntity::getId) .filter(StrUtil::isNotBlank) .collect(Collectors.toList()); @@ -453,7 +462,12 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer int refundCount = 0; int expiredCount = 0; Map userOrderMap = new HashMap<>(); + int orderCount = 0; for (PlayOrderInfoEntity order : orders) { + if (!isCompletedOrder(order)) { + continue; + } + orderCount++; BigDecimal finalAmount = defaultZero(order.getFinalAmount()); gmv = gmv.add(finalAmount); userOrderMap.merge(order.getPurchaserBy(), 1, Integer::sum); @@ -475,7 +489,6 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer expiredCount++; } } - int orderCount = orders.size(); int userCount = userOrderMap.size(); int continuedUserCount = (int) userOrderMap.values().stream().filter(cnt -> cnt > 1).count(); BigDecimal estimatedRevenue = calculateEarningsAmount(clerk.getId(), orders, startTime, endTime); @@ -568,6 +581,10 @@ public class PlayClerkPerformanceServiceImpl implements IPlayClerkPerformanceSer return value == null ? BigDecimal.ZERO : value; } + private boolean isCompletedOrder(PlayOrderInfoEntity order) { + return order != null && OrderConstant.OrderStatus.COMPLETED.getCode().equals(order.getOrderStatus()); + } + private static final class DateRange { private final String startTime; private final String endTime; diff --git a/play-admin/src/test/java/com/starry/admin/modules/statistics/service/PlayClerkPerformanceServiceImplTest.java b/play-admin/src/test/java/com/starry/admin/modules/statistics/service/PlayClerkPerformanceServiceImplTest.java index adc4033..c86d05f 100644 --- a/play-admin/src/test/java/com/starry/admin/modules/statistics/service/PlayClerkPerformanceServiceImplTest.java +++ b/play-admin/src/test/java/com/starry/admin/modules/statistics/service/PlayClerkPerformanceServiceImplTest.java @@ -11,6 +11,7 @@ import com.starry.admin.modules.clerk.module.entity.PlayClerkLevelInfoEntity; import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity; import com.starry.admin.modules.clerk.service.IPlayClerkLevelInfoService; import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService; +import com.starry.admin.modules.order.module.constant.OrderConstant; import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity; import com.starry.admin.modules.order.service.IPlayOrderInfoService; import com.starry.admin.modules.personnel.module.entity.PlayPersonnelGroupInfoEntity; @@ -21,6 +22,7 @@ import com.starry.admin.modules.statistics.module.vo.ClerkPerformanceOverviewQue import com.starry.admin.modules.statistics.module.vo.ClerkPerformanceOverviewResponseVo; import com.starry.admin.modules.statistics.module.vo.ClerkPerformanceOverviewSummaryVo; import com.starry.admin.modules.statistics.module.vo.ClerkPerformanceSnapshotVo; +import com.starry.admin.modules.statistics.module.vo.PlayClerkPerformanceInfoReturnVo; import com.starry.admin.modules.statistics.service.impl.PlayClerkPerformanceServiceImpl; import com.starry.admin.modules.withdraw.mapper.EarningsLineMapper; import java.math.BigDecimal; @@ -231,6 +233,121 @@ class PlayClerkPerformanceServiceImplTest { assertEquals("2024-08-02 23:59:59", endCaptor.getValue()); } + @Test + @DisplayName("queryOverview ignores non-completed orders when computing summary/GMV") + void queryOverviewSkipsNonCompletedOrders() { + ClerkPerformanceOverviewQueryVo vo = new ClerkPerformanceOverviewQueryVo(); + vo.setIncludeSummary(true); + vo.setIncludeRankings(true); + vo.setEndOrderTime(Arrays.asList("2024-08-01 00:00:00", "2024-08-10 23:59:59")); + + PlayClerkUserInfoEntity clerk = buildClerk("c10", "Neo", "g10", "l10"); + when(playPersonnelGroupInfoService.getValidClerkIdList(any(), any())) + .thenReturn(Collections.singletonList("c10")); + when(clerkUserInfoService.list((Wrapper) any())) + .thenReturn(Collections.singletonList(clerk)); + when(playClerkLevelInfoService.selectAll()).thenReturn(Collections.singletonList(level("l10", "至尊"))); + when(playPersonnelGroupInfoService.selectAll()).thenReturn(Collections.singletonList(group("g10", "十组"))); + + PlayOrderInfoEntity o1 = order("c10", "user1", "1", "0", "0", new BigDecimal("100.00"), + new BigDecimal("60.00"), LocalDateTime.of(2024, Month.AUGUST, 1, 10, 0)); + PlayOrderInfoEntity o2 = order("c10", "user2", "0", "0", "0", new BigDecimal("80.00"), + new BigDecimal("40.00"), LocalDateTime.of(2024, Month.AUGUST, 2, 11, 0)); + PlayOrderInfoEntity o3 = withRefund( + order("c10", "user3", "0", "0", "1", new BigDecimal("60.00"), new BigDecimal("35.00"), + LocalDateTime.of(2024, Month.AUGUST, 3, 9, 30)), + new BigDecimal("15.00")); + PlayOrderInfoEntity o4 = order("c10", "user4", "0", "2", "0", new BigDecimal("40.00"), + new BigDecimal("20.00"), LocalDateTime.of(2024, Month.AUGUST, 4, 16, 45)); + PlayOrderInfoEntity o5 = order("c10", "user5", "1", "0", "0", new BigDecimal("20.00"), + new BigDecimal("10.00"), LocalDateTime.of(2024, Month.AUGUST, 5, 13, 15)); + PlayOrderInfoEntity o6 = withStatus( + order("c10", "user6", "0", "0", "0", new BigDecimal("70.00"), new BigDecimal("30.00"), + LocalDateTime.of(2024, Month.AUGUST, 6, 14, 0)), + OrderConstant.OrderStatus.CANCELLED.getCode()); + PlayOrderInfoEntity o7 = withStatus( + order("c10", "user7", "0", "0", "0", new BigDecimal("50.00"), new BigDecimal("25.00"), + LocalDateTime.of(2024, Month.AUGUST, 6, 18, 20)), + OrderConstant.OrderStatus.IN_PROGRESS.getCode()); + PlayOrderInfoEntity o8 = withStatus( + order("c10", "user8", "0", "0", "0", new BigDecimal("45.00"), new BigDecimal("22.00"), + LocalDateTime.of(2024, Month.AUGUST, 7, 15, 5)), + OrderConstant.OrderStatus.ACCEPTED.getCode()); + PlayOrderInfoEntity o9 = withStatus( + order("c10", "user9", "0", "0", "0", new BigDecimal("30.00"), new BigDecimal("15.00"), + LocalDateTime.of(2024, Month.AUGUST, 8, 17, 40)), + OrderConstant.OrderStatus.PENDING.getCode()); + PlayOrderInfoEntity o10 = withStatus( + order("c10", "user10", "1", "0", "0", new BigDecimal("25.00"), new BigDecimal("12.00"), + LocalDateTime.of(2024, Month.AUGUST, 9, 19, 10)), + OrderConstant.OrderStatus.CANCELLED.getCode()); + + List mixedOrders = + Arrays.asList(o1, o2, o3, o4, o5, o6, o7, o8, o9, o10); + when(playOrderInfoService.clerkSelectOrderInfoList(eq("c10"), anyString(), anyString())) + .thenReturn(mixedOrders); + when(earningsLineMapper.sumAmountByClerkAndOrderIds(eq("c10"), anyCollection(), anyString(), anyString())) + .thenReturn(new BigDecimal("210.00")); + + setAuthentication(); + ClerkPerformanceOverviewResponseVo response; + try { + response = service.queryOverview(vo); + } finally { + clearAuthentication(); + } + + assertEquals(1, response.getRankings().size()); + ClerkPerformanceSnapshotVo snapshot = response.getRankings().get(0); + assertEquals(5, snapshot.getOrderCount()); + assertEquals(new BigDecimal("300.00"), snapshot.getGmv()); + assertEquals(new BigDecimal("40.00"), snapshot.getRewardAmount()); + assertEquals(new BigDecimal("15.00"), snapshot.getRefundAmount()); + assertEquals(new BigDecimal("210.00"), snapshot.getEstimatedRevenue()); + + ClerkPerformanceOverviewSummaryVo summary = response.getSummary(); + assertEquals(5, summary.getTotalOrderCount()); + assertEquals(new BigDecimal("300.00"), summary.getTotalGmv()); + assertEquals(1, summary.getTotalRefundOrderCount()); + + ArgumentCaptor> idCaptor = ArgumentCaptor.forClass(Collection.class); + verify(earningsLineMapper).sumAmountByClerkAndOrderIds(eq("c10"), idCaptor.capture(), + anyString(), anyString()); + assertEquals(5, idCaptor.getValue().size()); + assertTrue(idCaptor.getValue().containsAll( + Arrays.asList(o1.getId(), o2.getId(), o3.getId(), o4.getId(), o5.getId()))); + } + @Test + @DisplayName("getClerkPerformanceInfo should ignore non-completed orders when aggregating GMV") + void getClerkPerformanceInfoSkipsNonCompletedOrders() { + PlayClerkUserInfoEntity clerk = buildClerk("c9", "Nine", "gX", "lX"); + List levels = Collections.singletonList(level("lX", "钻石")); + List groups = Collections.singletonList(group("gX", "特战组")); + + PlayOrderInfoEntity completed = order("c9", "userA", "1", "0", "0", new BigDecimal("120.00"), + new BigDecimal("60.00"), LocalDateTime.of(2024, Month.AUGUST, 1, 10, 0)); + PlayOrderInfoEntity cancelled = withStatus( + order("c9", "userB", "0", "0", "0", new BigDecimal("200.00"), new BigDecimal("100.00"), + LocalDateTime.of(2024, Month.AUGUST, 1, 12, 0)), + OrderConstant.OrderStatus.CANCELLED.getCode()); + + when(earningsLineMapper.sumAmountByClerkAndOrderIds(eq("c9"), anyCollection(), anyString(), anyString())) + .thenReturn(new BigDecimal("60.00")); + + PlayClerkPerformanceInfoReturnVo result = service.getClerkPerformanceInfo(clerk, + Arrays.asList(completed, cancelled), levels, groups, "2024-08-01 00:00:00", "2024-08-02 23:59:59"); + + assertEquals(new BigDecimal("120.00"), result.getFinalAmount()); + assertEquals(1, result.getOrderNumber()); + assertEquals(1, result.getCustomNumber()); + + ArgumentCaptor> idCaptor = ArgumentCaptor.forClass(Collection.class); + verify(earningsLineMapper).sumAmountByClerkAndOrderIds(eq("c9"), idCaptor.capture(), + eq("2024-08-01 00:00:00"), eq("2024-08-02 23:59:59")); + assertEquals(1, idCaptor.getValue().size()); + assertTrue(idCaptor.getValue().contains(completed.getId())); + } + private PlayClerkUserInfoEntity buildClerk(String id, String name, String groupId, String levelId) { PlayClerkUserInfoEntity entity = new PlayClerkUserInfoEntity(); entity.setId(id); @@ -270,6 +387,7 @@ class PlayClerkPerformanceServiceImplTest { order.setOrdersExpiredState("1".equals(refundType) ? "1" : "0"); order.setPurchaserTime(purchaserTime); order.setId(clerkId + "-" + purchaser + "-" + purchaserTime.toString()); + order.setOrderStatus(OrderConstant.OrderStatus.COMPLETED.getCode()); return order; } @@ -288,4 +406,9 @@ class PlayClerkPerformanceServiceImplTest { order.setRefundAmount(refundAmount); return order; } + + private PlayOrderInfoEntity withStatus(PlayOrderInfoEntity order, String status) { + order.setOrderStatus(status); + return order; + } }