Jelajahi Sumber

fix: 充值归属站点改为服务端确定,客户端传值不再生效

- wxPay/promotionPay 移除客户端 stationId 参数,归属站点由服务端取用户归属
  (KymCache 优先,查库兜底),防止恶意篡改充值分账归属虚增站点收入
- 前端继续传 stationId 参数会被 Spring 忽略,兼容现有客户端

Co-Authored-By: Claude <noreply@anthropic.com>
skyline 3 minggu lalu
induk
melakukan
f229ed8cf6

+ 6 - 7
car-wash-miniapp/src/main/java/com/kym/miniapp/controller/PaymentController.java

@@ -27,7 +27,7 @@ public class PaymentController {
     }
 
     /**
-     * 充值
+     * 充值(归属站点由服务端按用户归属确定,客户端传值无效)
      *
      * @param rechargeConfigId
      * @return
@@ -35,8 +35,8 @@ public class PaymentController {
     @ApiLog("用户充值微信支付")
     @GetMapping("/wxPay")
     @ResponseBody
-    R<?> prepay(@RequestParam Long rechargeConfigId, @RequestParam(value = "stationId", required = false) String stationId) {
-        return R.success(wxPayService.wxPay(rechargeConfigId, stationId));
+    R<?> prepay(@RequestParam Long rechargeConfigId) {
+        return R.success(wxPayService.wxPay(rechargeConfigId));
     }
 
     @ApiLog(value = "微信回调", ignoreParams = true)
@@ -49,14 +49,13 @@ public class PaymentController {
 
 
     /**
-     * 专属优惠活动充值
+     * 专属优惠活动充值(归属站点由服务端按用户归属确定,客户端传值无效)
      */
     @ApiLog("用户优惠活动充值微信支付")
     @GetMapping("/promotionPay")
     @ResponseBody
-    R<?> promotionPay(@RequestParam String promotionToken,
-                      @RequestParam(value = "stationId", required = false) String stationId) {
-        return R.success(wxPayService.promotionPay(promotionToken, stationId));
+    R<?> promotionPay(@RequestParam String promotionToken) {
+        return R.success(wxPayService.promotionPay(promotionToken));
     }
 
     @ApiLog("用户申请退款")

+ 2 - 2
car-wash-service/src/main/java/com/kym/service/wechat/WxPayService.java

@@ -26,12 +26,12 @@ public interface WxPayService {
     ResponseEntity<Object> wxRefundNotify(HttpServletRequest request);
 
     @Transactional
-    PrepayWithRequestPaymentResponse wxPay(Long rechargeConfigId, String stationId);
+    PrepayWithRequestPaymentResponse wxPay(Long rechargeConfigId);
 
     ResponseEntity<Object> wxNotify(HttpServletRequest request) throws IOException;
 
     @Transactional
-    PrepayWithRequestPaymentResponse promotionPay(String promotionToken, String stationId);
+    PrepayWithRequestPaymentResponse promotionPay(String promotionToken);
 
     void offlineRecharge(Long userId, Integer amount, Integer grantsAmount, String remark);
 

+ 22 - 3
car-wash-service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

@@ -91,6 +91,7 @@ public class WxPayServiceImpl implements WxPayService {
     private final WashOrderService washOrderService;
     private final MpMsgTemplateService mpMsgTemplateService;
     private final RechargePromotionService rechargePromotionService;
+    private final UserService userService;
 
 
     /**
@@ -105,7 +106,8 @@ public class WxPayServiceImpl implements WxPayService {
                             ActivityService activityService,
                             RechargeConfigService rechargeConfigService, SplitRecordService splitRecordService,
                             WashOrderService washOrderService, MpMsgTemplateService mpMsgTemplateService,
-                            RechargePromotionService rechargePromotionService) {
+                            RechargePromotionService rechargePromotionService,
+                            UserService userService) {
         this.conf = conf;
         this.walletDetailService = walletDetailService;
         this.payLogService = payLogService;
@@ -116,6 +118,7 @@ public class WxPayServiceImpl implements WxPayService {
         this.washOrderService = washOrderService;
         this.mpMsgTemplateService = mpMsgTemplateService;
         this.rechargePromotionService = rechargePromotionService;
+        this.userService = userService;
     }
 
     /**
@@ -214,7 +217,7 @@ public class WxPayServiceImpl implements WxPayService {
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public PrepayWithRequestPaymentResponse wxPay(Long rechargeConfigId, String stationId) {
+    public PrepayWithRequestPaymentResponse wxPay(Long rechargeConfigId) {
         // 充值配置
         var rechargeConfig = rechargeConfigService.getById(rechargeConfigId);
 
@@ -225,6 +228,8 @@ public class WxPayServiceImpl implements WxPayService {
         var rechargeAmount = rechargeConfig.getRechargeAmount();
         var openid = StpUtil.getSession().getString("openid");
         var userId = StpUtil.getLoginIdAsLong();
+        // 充值归属站点以服务端用户归属为准,不信任客户端传值(防止分账归属被篡改)
+        var stationId = getUserStationId(userId);
         // 生成订单号
         String outTradeNo = OrderUtils.getOrderNo();
         // 创建钱包流水
@@ -262,7 +267,7 @@ public class WxPayServiceImpl implements WxPayService {
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public PrepayWithRequestPaymentResponse promotionPay(String promotionToken, String stationId) {
+    public PrepayWithRequestPaymentResponse promotionPay(String promotionToken) {
         var promotion = rechargePromotionService.getByToken(promotionToken);
         if (promotion == null) {
             throw new BusinessException("优惠活动不存在或已过期");
@@ -274,6 +279,8 @@ public class WxPayServiceImpl implements WxPayService {
         }
 
         var openid = StpUtil.getSession().getString("openid");
+        // 充值归属站点以服务端用户归属为准,不信任客户端传值(防止分账归属被篡改)
+        var stationId = getUserStationId(userId);
         var outTradeNo = OrderUtils.getOrderNo();
 
         var walletDetail = new WalletDetail()
@@ -315,6 +322,18 @@ public class WxPayServiceImpl implements WxPayService {
         return jsapiService.queryOrderById(request);
     }
 
+    /**
+     * 服务端获取用户归属站点(KymCache 优先,未命中查库兜底),用于充值分账归属
+     */
+    private String getUserStationId(Long userId) {
+        var stationId = KymCache.INSTANCE.getUserStationId(userId);
+        if (stationId == null) {
+            var user = userService.getById(userId);
+            stationId = user != null ? user.getStationId() : null;
+        }
+        return stationId;
+    }
+
     /**
      * 关闭订单
      *