diff --git a/play-admin/src/main/java/com/starry/admin/modules/clerk/service/impl/PlayClerkUserInfoServiceImpl.java b/play-admin/src/main/java/com/starry/admin/modules/clerk/service/impl/PlayClerkUserInfoServiceImpl.java index 6152dbe..ce4ac52 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/clerk/service/impl/PlayClerkUserInfoServiceImpl.java +++ b/play-admin/src/main/java/com/starry/admin/modules/clerk/service/impl/PlayClerkUserInfoServiceImpl.java @@ -134,7 +134,16 @@ public class PlayClerkUserInfoServiceImpl extends ServiceImpl placementStrategies; @PostConstruct @@ -515,6 +520,10 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService { throw new CustomException("每个订单只能退款一次~"); } + if (isBalancePaidOrder(order) && !playBalanceDetailsInfoService.existsCustomerConsumeRecord(order.getPurchaserBy(), order.getId())) { + throw new CustomException("订单未发生余额扣款,无法退款"); + } + UpdateWrapper refundUpdate = new UpdateWrapper<>(); refundUpdate.eq("id", order.getId()) .eq("refund_type", OrderRefundFlag.NOT_REFUNDED.getCode()) @@ -581,6 +590,19 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService { refundOperationType); } + private boolean isBalancePaidOrder(PlayOrderInfoEntity order) { + String sourceCode = order.getPaymentSource(); + if (StrUtil.isBlank(sourceCode)) { + return true; + } + try { + return PaymentSource.fromCode(sourceCode) == PaymentSource.BALANCE; + } catch (IllegalArgumentException ex) { + log.warn("Unknown payment source {}, defaulting to balance for refund guard", sourceCode); + return true; + } + } + private void validateOrderCreationRequest(OrderCreationContext context) { if (context == null) { throw new CustomException("订单创建请求不能为空"); diff --git a/play-admin/src/main/java/com/starry/admin/modules/order/service/support/ClerkRevenueCalculator.java b/play-admin/src/main/java/com/starry/admin/modules/order/service/support/ClerkRevenueCalculator.java index 997371a..2b17829 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/order/service/support/ClerkRevenueCalculator.java +++ b/play-admin/src/main/java/com/starry/admin/modules/order/service/support/ClerkRevenueCalculator.java @@ -37,6 +37,13 @@ public class ClerkRevenueCalculator { BigDecimal baseAmount = orderAmount == null ? BigDecimal.ZERO : orderAmount; ClerkEstimatedRevenueVo estimatedRevenueVo = new ClerkEstimatedRevenueVo(); + if (levelInfo == null) { + log.warn("店员{}缺少等级提成配置,预计收益按0处理", clerkId); + estimatedRevenueVo.setRevenueRatio(0); + estimatedRevenueVo.setRevenueAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); + return estimatedRevenueVo; + } + boolean fallbackToOther = false; OrderConstant.PlaceType placeTypeEnum; try { @@ -49,13 +56,13 @@ public class ClerkRevenueCalculator { switch (placeTypeEnum) { case SPECIFIED: // 指定单 - fillRegularOrderRevenue(firstOrder, baseAmount, levelInfo, estimatedRevenueVo); + fillRegularOrderRevenue(clerkId, firstOrder, baseAmount, levelInfo, estimatedRevenueVo); break; case RANDOM: // 随机单 - fillRandomOrderRevenue(firstOrder, baseAmount, levelInfo, estimatedRevenueVo); + fillRandomOrderRevenue(clerkId, firstOrder, baseAmount, levelInfo, estimatedRevenueVo); break; case REWARD: // 打赏单 - fillRewardOrderRevenue(firstOrder, baseAmount, levelInfo, estimatedRevenueVo); + fillRewardOrderRevenue(clerkId, firstOrder, baseAmount, levelInfo, estimatedRevenueVo); break; case OTHER: default: @@ -71,42 +78,56 @@ public class ClerkRevenueCalculator { return estimatedRevenueVo; } - private void fillRegularOrderRevenue(String firstOrder, BigDecimal orderAmount, + private void fillRegularOrderRevenue(String clerkId, String firstOrder, BigDecimal orderAmount, PlayClerkLevelInfoEntity levelInfo, ClerkEstimatedRevenueVo vo) { if ("1".equals(firstOrder)) { - vo.setRevenueRatio(levelInfo.getFirstRegularRatio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getFirstRegularRatio())); + int ratio = safeRatio(levelInfo.getFirstRegularRatio(), "firstRegularRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } else { - vo.setRevenueRatio(levelInfo.getNotFirstRegularRatio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getNotFirstRegularRatio())); + int ratio = safeRatio(levelInfo.getNotFirstRegularRatio(), "notFirstRegularRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } } - private void fillRandomOrderRevenue(String firstOrder, BigDecimal orderAmount, + private void fillRandomOrderRevenue(String clerkId, String firstOrder, BigDecimal orderAmount, PlayClerkLevelInfoEntity levelInfo, ClerkEstimatedRevenueVo vo) { if ("1".equals(firstOrder)) { - vo.setRevenueRatio(levelInfo.getFirstRandomRadio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getFirstRandomRadio())); + int ratio = safeRatio(levelInfo.getFirstRandomRadio(), "firstRandomRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } else { - vo.setRevenueRatio(levelInfo.getNotFirstRandomRadio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getNotFirstRandomRadio())); + int ratio = safeRatio(levelInfo.getNotFirstRandomRadio(), "notFirstRandomRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } } - private void fillRewardOrderRevenue(String firstOrder, BigDecimal orderAmount, + private void fillRewardOrderRevenue(String clerkId, String firstOrder, BigDecimal orderAmount, PlayClerkLevelInfoEntity levelInfo, ClerkEstimatedRevenueVo vo) { if ("1".equals(firstOrder)) { - vo.setRevenueRatio(levelInfo.getFirstRewardRatio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getFirstRewardRatio())); + int ratio = safeRatio(levelInfo.getFirstRewardRatio(), "firstRewardRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } else { - vo.setRevenueRatio(levelInfo.getNotFirstRewardRatio()); - vo.setRevenueAmount(scaleAmount(orderAmount, levelInfo.getNotFirstRewardRatio())); + int ratio = safeRatio(levelInfo.getNotFirstRewardRatio(), "notFirstRewardRatio", clerkId); + vo.setRevenueRatio(ratio); + vo.setRevenueAmount(scaleAmount(orderAmount, ratio)); } } - private BigDecimal scaleAmount(BigDecimal baseAmount, Integer ratio) { + private int safeRatio(Integer ratio, String ratioField, String clerkId) { + if (ratio == null) { + log.warn("店员{}的等级配置字段{}缺失,已按0%处理", clerkId, ratioField); + return 0; + } + return ratio; + } + + private BigDecimal scaleAmount(BigDecimal baseAmount, int ratio) { return baseAmount - .multiply(new BigDecimal(ratio).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)) + .multiply(BigDecimal.valueOf(ratio).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)) .setScale(2, RoundingMode.HALF_UP); } diff --git a/play-admin/src/main/java/com/starry/admin/modules/personnel/module/enums/BalanceDetailsUserType.java b/play-admin/src/main/java/com/starry/admin/modules/personnel/module/enums/BalanceDetailsUserType.java new file mode 100644 index 0000000..20e3926 --- /dev/null +++ b/play-admin/src/main/java/com/starry/admin/modules/personnel/module/enums/BalanceDetailsUserType.java @@ -0,0 +1,18 @@ +package com.starry.admin.modules.personnel.module.enums; + +import lombok.Getter; + +/** + * 用户类型枚举(0:陪聊;1:顾客) + */ +@Getter +public enum BalanceDetailsUserType { + CLERK("0"), + CUSTOMER("1"); + + private final String code; + + BalanceDetailsUserType(String code) { + this.code = code; + } +} diff --git a/play-admin/src/main/java/com/starry/admin/modules/personnel/service/IPlayBalanceDetailsInfoService.java b/play-admin/src/main/java/com/starry/admin/modules/personnel/service/IPlayBalanceDetailsInfoService.java index f0ed76f..82c62da 100644 --- a/play-admin/src/main/java/com/starry/admin/modules/personnel/service/IPlayBalanceDetailsInfoService.java +++ b/play-admin/src/main/java/com/starry/admin/modules/personnel/service/IPlayBalanceDetailsInfoService.java @@ -69,6 +69,17 @@ public interface IPlayBalanceDetailsInfoService extends IService lifecycleService.refundOrder(context)); + verify(orderInfoMapper, never()).update(isNull(), any()); + verify(customUserInfoService, never()).updateAccountBalanceById(any(), any(), any(), any(), any(), any(), any(), any()); + verify(orderRefundInfoService, never()).add(anyString(), anyString(), anyString(), anyString(), anyString(), any(), anyString(), anyString(), anyString(), anyString(), anyString()); + } + private PlayOrderInfoEntity buildOrder(String orderId, String status) { PlayOrderInfoEntity entity = new PlayOrderInfoEntity(); entity.setId(orderId);