From b130b955456c444c09f5e532872bc1144b8a3aa8 Mon Sep 17 00:00:00 2001 From: Guoqs <123@jsowell.com> Date: Tue, 16 Dec 2025 16:55:39 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=80=80=E6=AC=BE=E9=87=91?= =?UTF-8?q?=E9=A2=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TestCalculateBalanceRefund.java | 122 ++++++++++++++++++ .../programlogic/AbstractProgramLogic.java | 109 +++++++++++++++- 2 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 TestCalculateBalanceRefund.java diff --git a/TestCalculateBalanceRefund.java b/TestCalculateBalanceRefund.java new file mode 100644 index 000000000..7821e95e7 --- /dev/null +++ b/TestCalculateBalanceRefund.java @@ -0,0 +1,122 @@ +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +public class TestCalculateBalanceRefund { + + /** + * 计算余额退款(包含电费和保险费) + *

+ * 业务规则: + * 1. 总支付金额 = principalPay + giftPay + * 2. 电费预付款 = 总支付金额 - insuranceAmount + * 3. 实际电费消费金额 = orderAmount - discountAmount + * 4. 支付时优先使用本金,消费时也优先扣除本金 + * 5. 保险费优先从本金中扣除 + * 6. 电费实际消费金额 > 1 时,保险费不退;否则需要退保险费 + * + * @param principalPay 本金支付金额 + * @param giftPay 赠金支付金额 + * @param orderAmount 消费金额 + * @param discountAmount 折扣金额 + * @param insuranceAmount 保险费金额 + * @return Map包含:returnPrincipal(本金退款for电费),returnGift(赠金退款for电费), + * returnPrincipalForInsurance(本金退款for保险费),returnGiftForInsurance(赠金退款for保险费) + */ + protected static Map calculateBalanceRefund(BigDecimal principalPay, BigDecimal giftPay, + BigDecimal orderAmount, BigDecimal discountAmount, + BigDecimal insuranceAmount) { + Map resultMap = new HashMap<>(); + + // 参数校验,null值处理为0 + principalPay = principalPay == null ? BigDecimal.ZERO : principalPay; + giftPay = giftPay == null ? BigDecimal.ZERO : giftPay; + orderAmount = orderAmount == null ? BigDecimal.ZERO : orderAmount; + discountAmount = discountAmount == null ? BigDecimal.ZERO : discountAmount; + insuranceAmount = insuranceAmount == null ? BigDecimal.ZERO : insuranceAmount; + + // 总支付金额 + BigDecimal totalPay = principalPay.add(giftPay); + + // 电费预付款 = 总支付金额 - 保险费 + BigDecimal electricityPrepayment = totalPay.subtract(insuranceAmount); + + // 实际电费消费金额 = 消费金额 - 折扣金额 + BigDecimal actualElectricityConsumption = orderAmount.subtract(discountAmount); + if (actualElectricityConsumption.compareTo(BigDecimal.ZERO) < 0) { + actualElectricityConsumption = BigDecimal.ZERO; + } + + // 支付时优先用本金,保险费全部从本金中扣除 + // 本金用于保险费的部分(优先从本金扣除保险费) + BigDecimal principalForInsurance = principalPay.min(insuranceAmount); + // 赠金用于保险费的部分(如果本金不够支付保险费,从赠金中扣除) + BigDecimal giftForInsurance = insuranceAmount.subtract(principalForInsurance); + if (giftForInsurance.compareTo(BigDecimal.ZERO) < 0) { + giftForInsurance = BigDecimal.ZERO; + } + // 本金用于电费的部分 = 总本金 - 本金用于保险费的部分 + BigDecimal principalForElectricity = principalPay.subtract(principalForInsurance); + // 赠金用于电费的部分 = 总赠金 - 赠金用于保险费的部分 + BigDecimal giftForElectricity = giftPay.subtract(giftForInsurance); + + // 计算电费退款(消费时优先扣除本金) + BigDecimal principalConsumed = principalForElectricity.min(actualElectricityConsumption); + BigDecimal giftConsumed = actualElectricityConsumption.subtract(principalConsumed); + if (giftConsumed.compareTo(BigDecimal.ZERO) < 0) { + giftConsumed = BigDecimal.ZERO; + } + + // 电费退款 + BigDecimal returnPrincipal = principalForElectricity.subtract(principalConsumed); + BigDecimal returnGift = giftForElectricity.subtract(giftConsumed); + if (returnPrincipal.compareTo(BigDecimal.ZERO) < 0) { + returnPrincipal = BigDecimal.ZERO; + } + if (returnGift.compareTo(BigDecimal.ZERO) < 0) { + returnGift = BigDecimal.ZERO; + } + + // 计算保险费退款:电费实际消费金额 > 1 时,保险费不退;否则需要退保险费 + BigDecimal returnPrincipalForInsurance = BigDecimal.ZERO; + BigDecimal returnGiftForInsurance = BigDecimal.ZERO; + + if (actualElectricityConsumption.compareTo(BigDecimal.ONE) <= 0) { + // 需要退保险费 + returnPrincipalForInsurance = principalForInsurance; + returnGiftForInsurance = giftForInsurance; + } + + resultMap.put("returnPrincipal", returnPrincipal); + resultMap.put("returnGift", returnGift); + resultMap.put("returnPrincipalForInsurance", returnPrincipalForInsurance); + resultMap.put("returnGiftForInsurance", returnGiftForInsurance); + + System.out.println("计算余额退款: 本金支付=" + principalPay + ", 赠金支付=" + giftPay + + ", 消费金额=" + orderAmount + ", 折扣金额=" + discountAmount + + ", 保险费=" + insuranceAmount + ", 实际电费消费=" + actualElectricityConsumption + + ", 电费退款(本金=" + returnPrincipal + ", 赠金=" + returnGift + + "), 保险费退款(本金=" + returnPrincipalForInsurance + ", 赠金=" + returnGiftForInsurance + ")"); + + return resultMap; + } + + public static void main(String[] args) { + System.out.println("测试用例1: 本金30.5, 赠金20, 消费10, 折扣0, 保险费0.5"); + BigDecimal principalPay = new BigDecimal("30.5"); + BigDecimal giftPay = new BigDecimal("20"); + BigDecimal orderAmount = new BigDecimal("10"); + BigDecimal discountAmount = new BigDecimal("0"); + BigDecimal insuranceAmount = new BigDecimal("0.5"); + + Map result = calculateBalanceRefund(principalPay, giftPay, orderAmount, discountAmount, insuranceAmount); + System.out.println("结果: " + result); + System.out.println(); + + System.out.println("期望结果: 电费退款(本金=20.5, 赠金=19.5), 保险费退款(本金=0, 赠金=0)"); + System.out.println("实际结果: 电费退款(本金=" + result.get("returnPrincipal") + + ", 赠金=" + result.get("returnGift") + + "), 保险费退款(本金=" + result.get("returnPrincipalForInsurance") + + ", 赠金=" + result.get("returnGiftForInsurance") + ")"); + } +} \ No newline at end of file diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/AbstractProgramLogic.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/AbstractProgramLogic.java index bf4e803bb..8902d1a5c 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/AbstractProgramLogic.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/AbstractProgramLogic.java @@ -47,7 +47,7 @@ import java.util.stream.Collectors; * 描述订单逻辑 */ public abstract class AbstractProgramLogic implements InitializingBean { - protected Logger logger = LoggerFactory.getLogger(this.getClass()); + protected static Logger logger = LoggerFactory.getLogger(AbstractProgramLogic.class); @Value("${adapay.callback}") protected String ADAPAY_CALLBACK_URL; @@ -1164,6 +1164,113 @@ public abstract class AbstractProgramLogic implements InitializingBean { return valid1.compareTo(valid2) < 0 ? valid1 : valid2; } + /** + * 计算余额退款(包含电费和保险费) + *

+ * 业务规则: + * 1. 总支付金额 = principalPay + giftPay + * 2. 电费预付款 = 总支付金额 - insuranceAmount + * 3. 实际电费消费金额 = orderAmount - discountAmount + * 4. 支付时优先使用本金,消费时也优先扣除本金 + * 5. 电费实际消费金额 > 1 时,保险费不退;否则需要退保险费 + * + * @param principalPay 本金支付金额 + * @param giftPay 赠金支付金额 + * @param orderAmount 消费金额 + * @param discountAmount 折扣金额 + * @param insuranceAmount 保险费金额 + * @return Map包含:returnPrincipal(本金退款for电费),returnGift(赠金退款for电费), + * returnPrincipalForInsurance(本金退款for保险费),returnGiftForInsurance(赠金退款for保险费) + */ + protected static Map calculateBalanceRefund(BigDecimal principalPay, BigDecimal giftPay, + BigDecimal orderAmount, BigDecimal discountAmount, + BigDecimal insuranceAmount) { + Map resultMap = Maps.newHashMap(); + + // 参数校验,null值处理为0 + principalPay = principalPay == null ? BigDecimal.ZERO : principalPay; + giftPay = giftPay == null ? BigDecimal.ZERO : giftPay; + orderAmount = orderAmount == null ? BigDecimal.ZERO : orderAmount; + discountAmount = discountAmount == null ? BigDecimal.ZERO : discountAmount; + insuranceAmount = insuranceAmount == null ? BigDecimal.ZERO : insuranceAmount; + + // 总支付金额 + BigDecimal totalPay = principalPay.add(giftPay); + + // 电费预付款 = 总支付金额 - 保险费 + BigDecimal electricityPrepayment = totalPay.subtract(insuranceAmount); + + // 实际电费消费金额 = 消费金额 - 折扣金额 + BigDecimal actualElectricityConsumption = orderAmount.subtract(discountAmount); + if (actualElectricityConsumption.compareTo(BigDecimal.ZERO) < 0) { + actualElectricityConsumption = BigDecimal.ZERO; + } + + // 支付时优先用本金,保险费全部从本金中扣除 + // 本金用于保险费的部分(优先从本金扣除保险费) + BigDecimal principalForInsurance = principalPay.min(insuranceAmount); + // 赠金用于保险费的部分(如果本金不够支付保险费,从赠金中扣除) + BigDecimal giftForInsurance = insuranceAmount.subtract(principalForInsurance); + if (giftForInsurance.compareTo(BigDecimal.ZERO) < 0) { + giftForInsurance = BigDecimal.ZERO; + } + // 本金用于电费的部分 = 总本金 - 本金用于保险费的部分 + BigDecimal principalForElectricity = principalPay.subtract(principalForInsurance); + // 赠金用于电费的部分 = 总赠金 - 赠金用于保险费的部分 + BigDecimal giftForElectricity = giftPay.subtract(giftForInsurance); + + // 计算电费退款(消费时优先扣除本金) + BigDecimal principalConsumed = principalForElectricity.min(actualElectricityConsumption); + BigDecimal giftConsumed = actualElectricityConsumption.subtract(principalConsumed); + if (giftConsumed.compareTo(BigDecimal.ZERO) < 0) { + giftConsumed = BigDecimal.ZERO; + } + + // 电费退款 + BigDecimal returnPrincipal = principalForElectricity.subtract(principalConsumed); + BigDecimal returnGift = giftForElectricity.subtract(giftConsumed); + if (returnPrincipal.compareTo(BigDecimal.ZERO) < 0) { + returnPrincipal = BigDecimal.ZERO; + } + if (returnGift.compareTo(BigDecimal.ZERO) < 0) { + returnGift = BigDecimal.ZERO; + } + + // 计算保险费退款:电费实际消费金额 > 1 时,保险费不退;否则需要退保险费 + BigDecimal returnPrincipalForInsurance = BigDecimal.ZERO; + BigDecimal returnGiftForInsurance = BigDecimal.ZERO; + + if (actualElectricityConsumption.compareTo(BigDecimal.ONE) <= 0) { + // 需要退保险费 + returnPrincipalForInsurance = principalForInsurance; + returnGiftForInsurance = giftForInsurance; + } + + resultMap.put("returnPrincipal", returnPrincipal); + resultMap.put("returnGift", returnGift); + resultMap.put("returnPrincipalForInsurance", returnPrincipalForInsurance); + resultMap.put("returnGiftForInsurance", returnGiftForInsurance); + + logger.info("计算余额退款: 本金支付={}, 赠金支付={}, 消费金额={}, 折扣金额={}, 保险费={}, " + + "实际电费消费={}, 电费退款(本金={}, 赠金={}), 保险费退款(本金={}, 赠金={})", + principalPay, giftPay, orderAmount, discountAmount, insuranceAmount, + actualElectricityConsumption, returnPrincipal, returnGift, + returnPrincipalForInsurance, returnGiftForInsurance); + + return resultMap; + } + + public static void main(String[] args) { + BigDecimal principalPay = new BigDecimal("30.5"); + BigDecimal giftPay = new BigDecimal("20"); + BigDecimal orderAmount = new BigDecimal("10"); + BigDecimal discountAmount = new BigDecimal("9.1"); + BigDecimal insuranceAmount = new BigDecimal("0.5"); + + calculateBalanceRefund(principalPay, giftPay, orderAmount, discountAmount, insuranceAmount); + + }// + /** * 计算余额支付下发金额 * xixiao在用