Преглед изворни кода

fix: 修正结算公式,提现手续费在平台费之前扣除

微信提现手续费是钱从微信商户转出时先扣的通道费,应该在计算平台费之前先扣除:
netInflow → 扣微信手续费(0.6%) → 加上期结转 → 扣平台费(10%) → 结算金额

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline пре 7 часа
родитељ
комит
4b820dc9ca

+ 6 - 4
CLAUDE.md

@@ -50,12 +50,14 @@ car-wash-java/
 
 **月结公式**:
 ```
-feeBase = totalRecharge - totalRefund - totalCrossExpend + totalCrossIncome
-platformFee = feeBase × 10%
-available = openingBalance + feeBase - platformFee
+netInflow     = totalRecharge - totalRefund - totalCrossExpend + totalCrossIncome
+withdrawalFee = netInflow × 0.6%(微信先扣,仅对货物流转净额)
+afterWechat   = openingBalance + netInflow - withdrawalFee
+platformFee   = afterWechat × 10%
+settlementAmount = afterWechat - platformFee
 ```
 
-`available > 0` 时正常结算,转入站点可提现余额,同时记录平台服务费。负数则结转下期。
+`settlementAmount > 0` 时正常结算,转入站点可提现余额,同时记录平台服务费。负数则结转下期。
 
 ## 关键业务链路
 

+ 28 - 23
car-wash-service/src/main/java/com/kym/service/impl/SettlementServiceImpl.java

@@ -111,12 +111,23 @@ public class SettlementServiceImpl extends MyBaseServiceImpl<SettlementRecordMap
         // 读取上期期末余额作为本期期初
         int openingBalance = getOpeningBalance(stationId, period);
 
-        // 平台服务费基数(仅基于本期流入,不含上期结转)
-        int feeBase = totalRecharge - totalRefund - totalCrossExpend + totalCrossIncome;
-        int platformFee = feeBase > 0 ? new BigDecimal(feeBase).multiply(PLATFORM_FEE_RATE).setScale(0, RoundingMode.DOWN).intValue() : 0;
+        // 本期货物流转净额
+        int netInflow = totalRecharge - totalRefund - totalCrossExpend + totalCrossIncome;
 
-        // 可结算总额 = 期初结转 + 本期流入 - 平台费
-        int available = openingBalance + feeBase - platformFee;
+        // 微信提现手续费 0.6% — 钱从微信商户转出时先扣除,仅对货物流转净额计算
+        int withdrawalFee = netInflow > 0
+                ? new BigDecimal(netInflow).multiply(WITHDRAWAL_FEE_RATE).setScale(0, RoundingMode.DOWN).intValue()
+                : 0;
+
+        // 扣掉微信手续费后加上期结转,才是实际可分配金额
+        int afterWechat = openingBalance + netInflow - withdrawalFee;
+
+        // 平台服务费 10% — 基于微信扣完手续费后可分配的金额
+        int platformFee = afterWechat > 0
+                ? new BigDecimal(afterWechat).multiply(PLATFORM_FEE_RATE).setScale(0, RoundingMode.DOWN).intValue()
+                : 0;
+
+        int settlementAmount = afterWechat - platformFee;
 
         SettlementRecord record = new SettlementRecord()
                 .setStationId(stationId)
@@ -126,23 +137,18 @@ public class SettlementServiceImpl extends MyBaseServiceImpl<SettlementRecordMap
                 .setTotalCrossIncome(totalCrossIncome)
                 .setTotalCrossExpend(totalCrossExpend)
                 .setOpeningPendingBalance(openingBalance)
-                .setPlatformFeeBase(feeBase)
-                .setPlatformFee(platformFee);
-
-        if (available > 0) {
-            // 微信提现手续费 = 可结算金额 × 0.6%,向下取整
-            int withdrawalFee = new BigDecimal(available).multiply(WITHDRAWAL_FEE_RATE).setScale(0, RoundingMode.DOWN).intValue();
-            int finalSettlement = available - withdrawalFee;
+                .setPlatformFeeBase(afterWechat)
+                .setPlatformFee(platformFee)
+                .setWithdrawalFee(withdrawalFee);
 
-            // 正常结算
-            record.setWithdrawalFee(withdrawalFee)
-                    .setSettlementAmount(finalSettlement)
+        if (settlementAmount > 0) {
+            record.setSettlementAmount(settlementAmount)
                     .setClosingPendingBalance(0)
                     .setStatus(SettlementRecord.STATUS_待结算);
 
-            // 增加站点可提现金额(扣除提现手续费后的净额)
+            // 增加站点可提现金额
             stationAccountService.lambdaUpdate()
-                    .setSql("available_balance = available_balance + {0}", finalSettlement)
+                    .setSql("available_balance = available_balance + {0}", settlementAmount)
                     .eq(StationAccount::getStationId, stationId)
                     .update();
 
@@ -154,18 +160,17 @@ public class SettlementServiceImpl extends MyBaseServiceImpl<SettlementRecordMap
                 platformAccountService.addRevenue(platformFee);
             }
 
-            log.info("站点 {} 结算成功,金额:{} 分,平台费:{} 分,提现手续费:{} 分", stationId, finalSettlement, platformFee, withdrawalFee);
+            log.info("站点 {} 结算成功,金额:{} 分,平台费:{} 分,提现手续费:{} 分",
+                    stationId, settlementAmount, platformFee, withdrawalFee);
         } else {
-            // 异常结算
-            record.setWithdrawalFee(0)
-                    .setSettlementAmount(0)
-                    .setClosingPendingBalance(available)
+            record.setSettlementAmount(0)
+                    .setClosingPendingBalance(settlementAmount)
                     .setStatus(SettlementRecord.STATUS_异常结算)
                     .setRemark("结算金额为负,结转至下期");
 
             save(record);
 
-            log.warn("站点 {} 异常结算,结转金额:{} 分", stationId, available);
+            log.warn("站点 {} 异常结算,结转金额:{} 分", stationId, settlementAmount);
         }
     }