diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index 7065b4c1e..6b48c614e 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java @@ -806,21 +806,43 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { } } - // 退保险 - ApplyRefundDTO applyRefundDTO = new ApplyRefundDTO(); - applyRefundDTO.setOrderCode(orderBasicInfo.getOrderCode()); - applyRefundDTO.setRefundType(Constants.ONE); - applyRefundDTO.setRefundAmount(insuranceAmount); - applyRefundDTO.setMemberId(orderBasicInfo.getMemberId()); - applyRefundDTO.setScenarioType(ScenarioEnum.INSURANCE.getValue()); - - // 汇付退款需要一级运营商的小程序appId, 否则会退款失败 - String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(orderBasicInfo.getMerchantId()); - if (StringUtils.isNotBlank(wechatAppId)) { - applyRefundDTO.setWechatAppId(wechatAppId); + // 判断订单的支付方式 + String payMode = orderBasicInfo.getPayMode(); + if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_PRINCIPAL_BALANCE.getValue())) { + BigDecimal returnPrincipal = BigDecimal.ZERO; + BigDecimal returnGift = BigDecimal.ZERO; + // 余额支付 + UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder() + .memberId(orderBasicInfo.getMemberId()) + .targetMerchantId(orderBasicInfo.getMerchantId()) + .type(MemberWalletEnum.TYPE_IN.getValue()) // 进账 + .subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款 + .updatePrincipalBalance(orderBasicInfo.getInsuranceAmount()) + .updateGiftBalance(returnGift) + .relatedOrderCode(orderBasicInfo.getOrderCode()) + .build(); + // 更新会员钱包/余额退回到钱包 + memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); + } else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) + || StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_ALIPAY.getValue())) { + // 在线支付 + // 退保险 + ApplyRefundDTO applyRefundDTO = new ApplyRefundDTO(); + applyRefundDTO.setOrderCode(orderBasicInfo.getOrderCode()); + applyRefundDTO.setRefundType(Constants.ONE); + applyRefundDTO.setRefundAmount(insuranceAmount); + applyRefundDTO.setMemberId(orderBasicInfo.getMemberId()); + applyRefundDTO.setScenarioType(ScenarioEnum.INSURANCE.getValue()); + // 汇付退款需要一级运营商的小程序appId, 否则会退款失败 + String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(orderBasicInfo.getMerchantId()); + if (StringUtils.isNotBlank(wechatAppId)) { + applyRefundDTO.setWechatAppId(wechatAppId); + } + this.refundOrderWithAdapay(applyRefundDTO); + } else { + // 白名单支付或者ETC支付 + logger.debug("订单:{}使用:{},不退保险费", orderBasicInfo.getOrderCode(), OrderPayModeEnum.getPayModeDescription(payMode)); } - - this.refundOrderWithAdapay(applyRefundDTO); } /** 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..b867e849d 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 @@ -38,6 +38,7 @@ import org.springframework.beans.factory.annotation.Value; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -799,6 +800,147 @@ public abstract class AbstractProgramLogic implements InitializingBean { return resultMap; } + /** + * 余额支付 计算需要退回的金额 + * 【公共方法】 + * + * @param principalPay 本金支付金额 + * @param giftPay 赠送金额支付的金额 + * @param orderAmount 订单消费金额 + * @param discountAmount 订单折扣金额 + * @param insuranceAmount 保险金额 + * @return + */ + protected static Map calculateReturnAmount(BigDecimal principalPay, BigDecimal giftPay, BigDecimal orderAmount, BigDecimal discountAmount, BigDecimal insuranceAmount) { + // 创建返回的Map + Map refundMap = new HashMap<>(); + + // 初始化所有返回值为0 + refundMap.put("returnPrincipal", BigDecimal.ZERO); + refundMap.put("returnGift", BigDecimal.ZERO); + refundMap.put("returnPrincipalForInsurance", BigDecimal.ZERO); + refundMap.put("returnGiftForInsurance", BigDecimal.ZERO); + + // 设置精度为2位小数 + RoundingMode roundingMode = RoundingMode.HALF_UP; + int scale = 2; + + // 1. 计算总支付金额和电费预付金额 + BigDecimal totalPay = principalPay.add(giftPay).setScale(scale, roundingMode); + BigDecimal prepaidElectricity = totalPay.subtract(insuranceAmount).setScale(scale, roundingMode); + + // 2. 计算实际电费消费金额(应用折扣) + BigDecimal actualConsume = orderAmount.subtract(discountAmount); + if (actualConsume.compareTo(BigDecimal.ZERO) < 0) { + actualConsume = BigDecimal.ZERO; + } + actualConsume = actualConsume.setScale(scale, roundingMode); + + // 3. 计算电费应退款金额 + BigDecimal electricityRefund = prepaidElectricity.subtract(actualConsume); + if (electricityRefund.compareTo(BigDecimal.ZERO) < 0) { + electricityRefund = BigDecimal.ZERO; + } + electricityRefund = electricityRefund.setScale(scale, roundingMode); + + // 4. 判断保险是否退款(实际电费消费 < 1元时退还保险) + BigDecimal insuranceRefund = BigDecimal.ZERO; + boolean isInsuranceRefund = actualConsume.compareTo(new BigDecimal("1.00")) < 0; + if (isInsuranceRefund) { + insuranceRefund = insuranceAmount.setScale(scale, roundingMode); + } + + // 5. 计算电费退款中本金和赠金的部分(优先使用本金,退款时优先退回赠金) + BigDecimal remainingElectricityRefund = electricityRefund; + BigDecimal principalUsedForElectricity = BigDecimal.ZERO; + BigDecimal giftUsedForElectricity = BigDecimal.ZERO; + + // 5.1 计算本金和赠金在电费预付中的使用情况 + if (prepaidElectricity.compareTo(BigDecimal.ZERO) > 0) { + // 本金优先用于支付电费,最多不超过本金总额且不超过电费预付金额 + principalUsedForElectricity = principalPay.min(prepaidElectricity); + principalUsedForElectricity = principalUsedForElectricity.setScale(scale, roundingMode); + + // 剩余的电费预付由赠金支付 + giftUsedForElectricity = prepaidElectricity.subtract(principalUsedForElectricity); + giftUsedForElectricity = giftUsedForElectricity.setScale(scale, roundingMode); + + // 5.2 分配电费退款(优先退回赠金) + // 先退赠金支付的部分 + if (giftUsedForElectricity.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal giftRefundForElectricity = remainingElectricityRefund.min(giftUsedForElectricity); + giftRefundForElectricity = giftRefundForElectricity.setScale(scale, roundingMode); + refundMap.put("returnGift", giftRefundForElectricity); + remainingElectricityRefund = remainingElectricityRefund.subtract(giftRefundForElectricity); + } + + // 剩余的电费退款退回到本金 + if (remainingElectricityRefund.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal principalRefundForElectricity = remainingElectricityRefund.min(principalUsedForElectricity); + principalRefundForElectricity = principalRefundForElectricity.setScale(scale, roundingMode); + refundMap.put("returnPrincipal", principalRefundForElectricity); + } + } + + // 6. 计算保险退款中本金和赠金的部分 + if (insuranceRefund.compareTo(BigDecimal.ZERO) > 0) { + // 计算支付电费后剩余的本金和赠金 + BigDecimal remainingPrincipalAfterElectricity = principalPay.subtract(refundMap.get("returnPrincipal")); + BigDecimal remainingGiftAfterElectricity = giftPay.subtract(refundMap.get("returnGift")); + + // 保险支付顺序:优先使用剩余本金,不足部分用赠金 + BigDecimal principalUsedForInsurance = remainingPrincipalAfterElectricity.min(insuranceAmount); + BigDecimal giftUsedForInsurance = insuranceAmount.subtract(principalUsedForInsurance); + + // 保险退款(优先退回赠金部分) + BigDecimal remainingInsuranceRefund = insuranceRefund; + + // 先退赠金支付的保险部分 + if (giftUsedForInsurance.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal giftRefundForInsurance = remainingInsuranceRefund.min(giftUsedForInsurance); + giftRefundForInsurance = giftRefundForInsurance.setScale(scale, roundingMode); + refundMap.put("returnGiftForInsurance", giftRefundForInsurance); + remainingInsuranceRefund = remainingInsuranceRefund.subtract(giftRefundForInsurance); + } + + // 剩余的保险退款退回到本金 + if (remainingInsuranceRefund.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal principalRefundForInsurance = remainingInsuranceRefund.min(principalUsedForInsurance); + principalRefundForInsurance = principalRefundForInsurance.setScale(scale, roundingMode); + refundMap.put("returnPrincipalForInsurance", principalRefundForInsurance); + } + } + + return refundMap; + } + + public static void main(String[] args) { + BigDecimal principalPay = new BigDecimal("30"); + BigDecimal giftPay = new BigDecimal("20"); + BigDecimal orderAmount = new BigDecimal("0.8"); + BigDecimal discountAmount = new BigDecimal("0"); + BigDecimal insuranceAmount = new BigDecimal("0.0"); + Map stringBigDecimalMap = calculateReturnAmount(principalPay, giftPay, orderAmount, discountAmount, insuranceAmount); + + // 获取各项退款金额 + BigDecimal returnPrincipal = stringBigDecimalMap.get("returnPrincipal"); + BigDecimal returnGift = stringBigDecimalMap.get("returnGift"); + BigDecimal returnPrincipalForInsurance = stringBigDecimalMap.get("returnPrincipalForInsurance"); + BigDecimal returnGiftForInsurance = stringBigDecimalMap.get("returnGiftForInsurance"); + + // 计算总计 + BigDecimal electricityRefund = returnPrincipal.add(returnGift); + BigDecimal insuranceRefund = returnPrincipalForInsurance.add(returnGiftForInsurance); + BigDecimal totalRefund = electricityRefund.add(insuranceRefund); + BigDecimal totalPrincipalRefund = returnPrincipal.add(returnPrincipalForInsurance); + BigDecimal totalGiftRefund = returnGift.add(returnGiftForInsurance); + + String input = String.format("输入:本金%s元,赠金%s元,消费%s元,折扣%s元,保险%s元", principalPay, giftPay, orderAmount, discountAmount, insuranceAmount); + System.out.println(input); + String output = String.format("输出:%s元,赠金%s元,保险%s元,总退款%s元", returnPrincipal, returnGift, returnPrincipalForInsurance, returnGiftForInsurance, totalRefund); + System.out.println(output); + } + /** * 计算解冻金额 *