package com.ruoyi.order.service.impl; import com.ruoyi.order.api.model.AccountingStrategyDetailOrder; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.vo.TransactionRecordMessageVO; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.List; final class ChargingSimulationSupport { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"); private ChargingSimulationSupport() { } static BigDecimal availableAmount(TChargingOrder order) { if (order == null) { return BigDecimal.ZERO.setScale(2); } BigDecimal chargeAmount = money(order.getChargeAmount()); return chargeAmount.compareTo(BigDecimal.ZERO) > 0 ? chargeAmount : money(order.getRechargeAmount()); } static String paymentMode(TChargingOrder order) { if (order == null) { return "未知"; } if (Integer.valueOf(1).equals(order.getIsWhitelist()) && Integer.valueOf(1).equals(order.getWhitelistBenefitType())) { return "免支付"; } BigDecimal balanceAmount = money(order.getBalancePayAmount()); BigDecimal thirdAmount = thirdPayAmount(order); if (balanceAmount.compareTo(BigDecimal.ZERO) == 0 && thirdAmount.compareTo(BigDecimal.ZERO) == 0) { return "免支付"; } String thirdChannel = thirdChannel(order); if (balanceAmount.compareTo(BigDecimal.ZERO) > 0 && thirdAmount.compareTo(BigDecimal.ZERO) == 0) { return "余额支付"; } if (balanceAmount.compareTo(BigDecimal.ZERO) > 0 && thirdAmount.compareTo(BigDecimal.ZERO) > 0) { return "余额+" + thirdChannel; } return thirdChannel; } static BigDecimal thirdPayAmount(TChargingOrder order) { if (order == null) { return BigDecimal.ZERO.setScale(2); } BigDecimal thirdAmount = money(order.getThirdPayAmount()); if (thirdAmount.compareTo(BigDecimal.ZERO) > 0) { return thirdAmount; } if (Integer.valueOf(1).equals(order.getPayMethod()) && !"ICBC".equalsIgnoreCase(order.getSourceName())) { return thirdAmount; } return money(order.getRechargeAmount()) .subtract(money(order.getBalancePayAmount())) .max(BigDecimal.ZERO) .setScale(2, RoundingMode.HALF_UP); } private static String thirdChannel(TChargingOrder order) { if ("ICBC".equalsIgnoreCase(order.getSourceName())) { return "工行支付"; } if (Integer.valueOf(2).equals(order.getRechargePaymentType())) { return "支付宝支付"; } if (Integer.valueOf(3).equals(order.getRechargePaymentType())) { return "支付宝H5支付"; } return "微信支付"; } private static BigDecimal money(BigDecimal amount) { return amount == null ? BigDecimal.ZERO.setScale(2) : amount.setScale(2, RoundingMode.HALF_UP); } static PreparedSimulation prepare(String orderCode, List tariffs, BigDecimal electricityFee, BigDecimal serviceFee, LocalDateTime endTime) { validate(orderCode, tariffs, electricityFee, serviceFee); if (tariffs.size() > 12) { throw new IllegalArgumentException("模拟计费最多支持12个计费时段"); } int index = findTariffIndex(tariffs, endTime.toLocalTime()); AccountingStrategyDetailOrder tariff = tariffs.get(index); tariff.setElectrovalence(electricityFee); tariff.setServiceCharge(serviceFee); tariff.setCostServiceCharge(serviceFee); TransactionRecordMessageVO record = new TransactionRecordMessageVO(); record.setTransaction_serial_number(orderCode); record.setStart_time(endTime.minusSeconds(1).format(DATE_TIME_FORMATTER)); record.setEnd_time(endTime.format(DATE_TIME_FORMATTER)); record.setTrade_date(endTime.format(DATE_TIME_FORMATTER)); record.setTotal_electricity(BigDecimal.ONE); record.setLoss_total_electricity(BigDecimal.ONE); record.setPayment_amount(electricityFee.add(serviceFee)); record.setMethod(1); record.setStop_reason(1); setPeriodCharge(record, tariff.getType(), index + 1); return new PreparedSimulation(tariff, record); } private static void validate(String orderCode, List tariffs, BigDecimal electricityFee, BigDecimal serviceFee) { if (orderCode == null || orderCode.trim().isEmpty()) { throw new IllegalArgumentException("模拟订单号不能为空"); } if (tariffs == null || tariffs.isEmpty()) { throw new IllegalArgumentException("订单计费策略为空"); } if (electricityFee == null || electricityFee.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("电费不能小于0"); } if (serviceFee == null || serviceFee.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("服务费不能小于0"); } if (electricityFee.add(serviceFee).compareTo(BigDecimal.ZERO) <= 0) { throw new IllegalArgumentException("模拟消费金额必须大于0"); } } private static int findTariffIndex(List tariffs, LocalTime time) { for (int i = 0; i < tariffs.size(); i++) { AccountingStrategyDetailOrder tariff = tariffs.get(i); LocalTime start = parseTime(tariff.getStartTime(), false); LocalTime end = parseTime(tariff.getEndTime(), true); if (!time.isBefore(start) && !time.isAfter(end)) { return i; } } throw new IllegalArgumentException("当前时间未匹配到订单计费时段"); } private static LocalTime parseTime(String value, boolean end) { if ("24:00".equals(value)) { return LocalTime.MAX; } LocalTime time = LocalTime.parse(value, DateTimeFormatter.ofPattern("HH:mm")); return end ? time.withSecond(59).withNano(999999999) : time; } private static void setPeriodCharge(TransactionRecordMessageVO record, Integer type, int index) { String prefix; if (Integer.valueOf(1).equals(type)) { prefix = "Spike"; } else if (Integer.valueOf(2).equals(type)) { prefix = "Peak"; } else if (Integer.valueOf(3).equals(type)) { prefix = "Flat"; } else if (Integer.valueOf(4).equals(type)) { prefix = "Valley"; } else { throw new IllegalArgumentException("不支持的计费时段类型:" + type); } try { Method setter = TransactionRecordMessageVO.class.getMethod("set" + prefix + "_charge" + index, BigDecimal.class); setter.invoke(record, BigDecimal.ONE); } catch (Exception e) { throw new IllegalStateException("构造模拟计费时段失败", e); } } static final class PreparedSimulation { private final AccountingStrategyDetailOrder tariff; private final TransactionRecordMessageVO record; PreparedSimulation(AccountingStrategyDetailOrder tariff, TransactionRecordMessageVO record) { this.tariff = tariff; this.record = record; } AccountingStrategyDetailOrder getTariff() { return tariff; } TransactionRecordMessageVO getRecord() { return record; } } }