longz
2026-07-14 b50e57bf7e17d696ddb4e9785c909052da034ef4
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -5,6 +5,7 @@
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.dto.SendMessageDTO;
@@ -51,6 +52,7 @@
import com.ruoyi.order.api.vo.PlatformStopChargingReplyVO;
import com.ruoyi.order.dto.*;
import com.ruoyi.order.mapper.TChargingOrderMapper;
import com.ruoyi.order.mapper.TChargingOrderShareRecordMapper;
import com.ruoyi.order.mapper.TSettlementConfirmMapper;
import com.ruoyi.order.service.TChargingOrderAccountingStrategyService;
import com.ruoyi.order.service.TChargingOrderRefundService;
@@ -61,6 +63,8 @@
import com.ruoyi.order.util.mongodb.service.TransactionRecordService;
import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService;
import com.ruoyi.order.vo.EndOfChargePageInfo;
import com.ruoyi.order.vo.ChargingSimulationVO;
import com.ruoyi.order.vo.IcbcAdminSubOrderVO;
import com.ruoyi.order.vo.OrderCountByDate;
import com.ruoyi.order.vo.StatisticsOfBatteryVO;
import com.ruoyi.other.api.domain.*;
@@ -71,11 +75,13 @@
import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO;
import com.ruoyi.payment.api.feignClient.AliPaymentClient;
import com.ruoyi.payment.api.feignClient.H5AliPaymentClient;
import com.ruoyi.payment.api.feignClient.IcbcPaymentClient;
import com.ruoyi.payment.api.feignClient.WxPaymentClient;
import com.ruoyi.payment.api.model.*;
import com.ruoyi.payment.api.vo.*;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
@@ -150,6 +156,12 @@
   private AliPaymentClient aliPaymentClient;
   @Resource
   private H5AliPaymentClient h5AliPaymentClient;
   @Resource
   private IcbcPaymentClient icbcPaymentClient;
   @Resource
   private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper;
   @Resource
   private ChargingOrderSettlementExecutor chargingOrderSettlementExecutor;
   
   @Resource
   private AppCouponClient appCouponClient;
@@ -593,7 +605,38 @@
            changeUserBalance(chargingOrder.getAppUserId(), balanceRefundAmount);
            recordBalanceRefund(chargingOrder, balanceRefundAmount, refund.getRefundCode());
        }
        triggerChargingOrderShare(chargingOrder);
    }
   private boolean refundByIcbcAndFinish(TChargingOrder chargingOrder, TChargingOrderRefund refund, BigDecimal thirdRefundAmount,
                                         String reason, boolean finishManual, BigDecimal refundAmount, BigDecimal balanceRefundAmount) {
      IcbcRefundReq req = new IcbcRefundReq();
      req.setOutTradeNo(chargingOrder.getCode());
      req.setOrderId(chargingOrder.getRechargeSerialNumber());
      req.setOutRefundNo(refund.getRefundCode());
      req.setRefundAmount(thirdRefundAmount);
      req.setTotalAmount(getRefundableThirdPayAmount(chargingOrder));
      req.setReason(reason);
      R<IcbcRefundResp> result = icbcPaymentClient.refund(req);
      IcbcRefundResp resp = result == null ? null : result.getData();
      if (result == null || result.getCode() != 200 || resp == null || !"SUCCESS".equals(resp.getStatus())) {
         log.error("工行退款失败,订单号:{},退款单号:{},返回:{}", chargingOrder.getCode(), refund.getRefundCode(), result == null ? null : result.getMsg());
         return false;
      }
      if (finishManual) {
         refund.setRefundSerialNumber(firstNotBlank(resp.getRefundId(), resp.getOutRefundNo()));
         refund.setRefundTime(LocalDateTime.now());
         finishManualChargingRefund(chargingOrder, refund, refundAmount, balanceRefundAmount, thirdRefundAmount);
      } else {
         chargingOrderRefundService.save(refund);
         chargingOrderStartupFailureWxRefund(refund.getRefundCode(), firstNotBlank(resp.getRefundId(), resp.getOutRefundNo()), "SUCCESS", resp.getRefundTime());
      }
      return true;
   }
   private boolean isIcbcOrder(TChargingOrder chargingOrder) {
      return chargingOrder != null && "ICBC".equals(chargingOrder.getSourceName());
   }
    /**
     * 判断订单是否为白名单订单
@@ -696,7 +739,13 @@
            .eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0));
      for (TChargingOrder tChargingOrder : list) {
         Integer rechargePaymentType = tChargingOrder.getRechargePaymentType();
         if (1 == rechargePaymentType) {
         if ("ICBC".equals(tChargingOrder.getSourceName())) {
            IcbcPaymentResp data = icbcPaymentClient.query(tChargingOrder.getCode()).getData();
            if (null != data && isIcbcRemovableStatus(data.getStatus(), tChargingOrder)) {
               this.removeById(tChargingOrder.getId());
            }
         }
         if (!"ICBC".equals(tChargingOrder.getSourceName()) && 1 == rechargePaymentType) {
            NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(tChargingOrder.getCode()).getData();
            if (null != data) {
               String trade_state = data.getTrade_state();
@@ -706,7 +755,7 @@
               }
            }
         }
         if (2 == rechargePaymentType) {
         if (!"ICBC".equals(tChargingOrder.getSourceName()) && 2 == rechargePaymentType) {
            AliQueryOrder data = aliPaymentClient.query(tChargingOrder.getCode()).getData();
            if (null != data) {
               //支付失败,删除无效的订单
@@ -716,7 +765,7 @@
               }
            }
         }
         if (3 == rechargePaymentType) {
         if (!"ICBC".equals(tChargingOrder.getSourceName()) && 3 == rechargePaymentType) {
            AliQueryOrder data = h5AliPaymentClient.query(tChargingOrder.getCode()).getData();
            if (null != data) {
               //支付失败,删除无效的订单
@@ -739,7 +788,15 @@
            .eq(TChargingOrder::getAppUserCarId, userId).eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0));
      if (null != one) {
         //查询三方支付数据,支付中直接结束三方订单
         if (1 == one.getRechargePaymentType()) {
         if ("ICBC".equals(one.getSourceName())) {
            IcbcPaymentResp data = icbcPaymentClient.query(one.getCode()).getData();
            if (null != data && isIcbcRemovableStatus(data.getStatus(), one)) {
               this.removeById(one.getId());
            } else {
               return AjaxResult.error("存在支付中订单,请稍后再试");
            }
         }
         if (!"ICBC".equals(one.getSourceName()) && 1 == one.getRechargePaymentType()) {
            NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(one.getCode()).getData();
            if (null != data) {
               String trade_state = data.getTrade_state();
@@ -753,7 +810,7 @@
               }
            }
         }
         if (2 == one.getRechargePaymentType()) {
         if (!"ICBC".equals(one.getSourceName()) && 2 == one.getRechargePaymentType()) {
            AliQueryOrder data = aliPaymentClient.query(one.getCode()).getData();
            if (null != data) {
               String trade_state = data.getTradeStatus();
@@ -768,7 +825,7 @@
               }
            }
         }
         if (3 == one.getRechargePaymentType()) {
         if (!"ICBC".equals(one.getSourceName()) && 3 == one.getRechargePaymentType()) {
            AliQueryOrder data = h5AliPaymentClient.query(one.getCode()).getData();
            if (null != data) {
               String trade_state = data.getTradeStatus();
@@ -820,6 +877,9 @@
      chargingOrder.setWhitelistServiceRefundAmount(BigDecimal.ZERO);
      chargingOrder.setVipDiscountAmount(BigDecimal.ZERO);
      chargingOrder.setOrderSource(1);
      if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0 && Integer.valueOf(1).equals(addChargingOrder.getPaymentType())) {
         chargingOrder.setSourceName("ICBC");
      }
      chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪");
      
      Site site = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData().get(0);
@@ -884,17 +944,28 @@
      }
      //会员优惠折扣将其计入增加充电时长(增加总充电金额)
      //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额)
      if (1 == addChargingOrder.getPaymentType()) {
         PaymentOrder paymentOrder = new PaymentOrder();
         paymentOrder.setCode(chargingOrder.getCode());
         paymentOrder.setAmount(thirdPayAmount);
         paymentOrder.setOpenId(appUser.getWxOpenid());
         paymentOrder.setDescription("充电充值");
         paymentOrder.setNotifyUrl("/payment/wx/pay/notify");
         Map<String, Object> data = wxPaymentClient.orderPay(paymentOrder).getData();
         return AjaxResult.success(data);
      if (Integer.valueOf(1).equals(addChargingOrder.getPaymentType())) {
         IcbcPaymentReq req = new IcbcPaymentReq();
         req.setOutTradeNo(chargingOrder.getCode());
         req.setAmount(thirdPayAmount);
         req.setSubject("充电充值");
         req.setBody("充电充值");
         req.setPaymentType(1);
         req.setNotifyUrl("/payment/icbc/callBack");
         req.setReturnUrl(addChargingOrder.getReturnUrl());
         req.setOpenId(appUser.getWxOpenid());
         req.setProfitSharing(buildIcbcProfitSharing(site));
         IcbcPaymentResp data = icbcPaymentClient.payment(req).getData();
         if (isIcbcPaymentCreated(data)) {
            if (StringUtils.hasLength(data.getTradeNo())) {
               chargingOrder.setRechargeSerialNumber(data.getTradeNo());
               this.updateById(chargingOrder);
            }
            return AjaxResult.success(data);
         }
         throw new RuntimeException("调起工行支付失败");
      }
      if (2 == addChargingOrder.getPaymentType()) {
      if (Integer.valueOf(2).equals(addChargingOrder.getPaymentType())) {
         AliPaymentReq req = new AliPaymentReq();
         req.setOutTradeNo(chargingOrder.getCode());
         req.setTotalAmount(thirdPayAmount.toString());
@@ -903,11 +974,12 @@
         req.setBody("充电充值");
         req.setNotifyUrl("/payment/ali/callBack");
         AliPaymentResp data = aliPaymentClient.payment(req).getData();
         if (null != data) {
         if (data != null) {
            return AjaxResult.success(data);
         }
         throw new RuntimeException("调起支付宝支付失败");
      }
      if (3 == addChargingOrder.getPaymentType()) {
      if (Integer.valueOf(3).equals(addChargingOrder.getPaymentType())) {
         AliPaymentReq req = new AliPaymentReq();
         req.setOutTradeNo(chargingOrder.getCode());
         req.setTotalAmount(thirdPayAmount.toString());
@@ -922,6 +994,321 @@
         }
      }
      throw new RuntimeException("无效的支付方式");
   }
   @Override
   public ChargingSimulationVO getCurrentSimulationOrder(Integer gunId) {
      if (gunId == null) {
         throw new ServiceException("充电枪不能为空");
      }
      Long userId = tokenService.getLoginUserApplet().getUserId();
      return buildSimulationVO(findSimulationOrder(userId, gunId));
   }
   @Override
   public ChargingSimulationVO completeSimulation(ChargingSimulationReq request) {
      if (request == null || request.getGunId() == null) {
         throw new ServiceException("充电枪不能为空");
      }
      Long userId = tokenService.getLoginUserApplet().getUserId();
      TChargingOrder order = findSimulationOrder(userId, request.getGunId());
      List<UploadRealTimeMonitoringData> monitoringData = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
      if (monitoringData != null && !monitoringData.isEmpty()) {
         throw new ServiceException("订单已存在真实充电监控数据,禁止模拟结算");
      }
      BigDecimal electricityFee = money(request.getElectricityFee());
      BigDecimal serviceFee = money(request.getServiceFee());
      BigDecimal simulationTotal = electricityFee.add(serviceFee).setScale(2, RoundingMode.HALF_UP);
      BigDecimal availableAmount = money(order.getChargeAmount()).compareTo(BigDecimal.ZERO) > 0
            ? money(order.getChargeAmount()) : money(order.getRechargeAmount());
      if (simulationTotal.compareTo(availableAmount) > 0) {
         throw new ServiceException("模拟消费金额不能超过订单可消费金额" + availableAmount.toPlainString() + "元");
      }
      List<AccountingStrategyDetailOrder> tariffs = accountingStrategyDetailOrderService.list(
            new LambdaQueryWrapper<AccountingStrategyDetailOrder>()
                  .eq(AccountingStrategyDetailOrder::getChargingOrderId, order.getId())
                  .orderByAsc(AccountingStrategyDetailOrder::getStartTime));
      ChargingSimulationSupport.PreparedSimulation prepared;
      try {
         prepared = ChargingSimulationSupport.prepare(order.getCode(), tariffs, electricityFee, serviceFee, LocalDateTime.now());
      } catch (IllegalArgumentException e) {
         throw new ServiceException(e.getMessage());
      }
      accountingStrategyDetailOrderService.updateById(prepared.getTariff());
      TChargingGun gun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData();
      TChargingPile pile = chargingPileClient.getChargingPileById(order.getChargingPileId()).getData();
      TransactionRecordMessageVO record = prepared.getRecord();
      record.setCharging_gun_code(gun == null ? null : gun.getCode());
      record.setCharging_pile_code(pile == null ? null : pile.getCode());
      if (Integer.valueOf(2).equals(order.getStatus())) {
         TChargingOrder charging = new TChargingOrder();
         charging.setId(order.getId());
         charging.setStatus(3);
         charging.setStartTime(LocalDateTime.now().minusSeconds(1));
         this.updateById(charging);
      }
      R settlement = chargingOrderSettlementExecutor.settle(record);
      if (R.isError(settlement)) {
         throw new ServiceException(StringUtils.hasLength(settlement.getMsg()) ? settlement.getMsg() : "模拟结算失败");
      }
      return buildSimulationVO(this.getById(order.getId()));
   }
   private TChargingOrder findSimulationOrder(Long userId, Integer gunId) {
      TChargingOrder order = this.getOne(new LambdaQueryWrapper<TChargingOrder>()
            .eq(TChargingOrder::getAppUserId, userId)
            .eq(TChargingOrder::getChargingGunId, gunId)
            .eq(TChargingOrder::getSourceName, "ICBC")
            .eq(TChargingOrder::getRechargePaymentStatus, 2)
            .in(TChargingOrder::getStatus, Arrays.asList(2, 3, 4))
            .eq(TChargingOrder::getDelFlag, 0)
            .isNull(TChargingOrder::getRefundStatus)
            .orderByDesc(TChargingOrder::getId)
            .last("limit 1"));
      if (order == null) {
         throw new ServiceException("当前枪没有属于你的可模拟ICBC已支付订单");
      }
      return order;
   }
   private ChargingSimulationVO buildSimulationVO(TChargingOrder order) {
      ChargingSimulationVO result = new ChargingSimulationVO();
      result.setOrderId(order.getId());
      result.setOrderCode(order.getCode());
      result.setOrderStatus(order.getStatus());
      result.setRechargeAmount(order.getRechargeAmount());
      result.setChargeAmount(order.getChargeAmount());
      result.setElectricityFee(order.getElectrovalence());
      result.setServiceFee(order.getServiceCharge());
      result.setPaymentAmount(order.getPaymentAmount());
      result.setRefundAmount(order.getRefundAmount());
      result.setRefundStatus(order.getRefundStatus());
      result.setIcbcOrderId(order.getRechargeSerialNumber());
      TChargingOrderShareRecord shareRecord = chargingOrderShareRecordMapper.selectOne(
            new LambdaQueryWrapper<TChargingOrderShareRecord>()
                  .eq(TChargingOrderShareRecord::getChargingOrderId, order.getId())
                  .eq(TChargingOrderShareRecord::getPayChannel, "ICBC")
                  .eq(TChargingOrderShareRecord::getDelFlag, false)
                  .orderByDesc(TChargingOrderShareRecord::getId)
                  .last("limit 1"));
      if (shareRecord != null) {
         result.setShareAmount(shareRecord.getShareAmount());
         result.setShareStatus(shareRecord.getOnlineShareStatus());
         result.setSubOrderId(shareRecord.getSubOrderId());
         result.setSubOrderSeq(shareRecord.getSubOrderSeq());
         result.setSubOrderTrxid(shareRecord.getSubOrderTrxid());
      }
      return result;
   }
   @Override
   public IcbcPaymentResp queryIcbcAdminPayment(String orderCode) {
      TChargingOrder order = loadIcbcAdminOrder(orderCode);
      return requireFeignData(icbcPaymentClient.query(order.getCode()), "工行支付查询失败");
   }
   @Override
   public IcbcRefundResp refundIcbcAdminPayment(IcbcAdminFundOperationReq request) {
      if (request == null) {
         throw new ServiceException("请求参数不能为空");
      }
      TChargingOrder order = loadIcbcAdminOrder(request.getOrderCode());
      BigDecimal amount;
      try {
         amount = IcbcAdminFundOperationSupport.requireAmount(request.getAmount());
      } catch (IllegalArgumentException e) {
         throw new ServiceException(e.getMessage());
      }
      BigDecimal paidAmount = money(order.getThirdPayAmount()).compareTo(BigDecimal.ZERO) > 0
            ? money(order.getThirdPayAmount()) : money(order.getRechargeAmount());
      if (amount.compareTo(paidAmount) > 0) {
         throw new ServiceException("退款金额不能超过订单第三方支付金额" + paidAmount.toPlainString() + "元");
      }
      RLock lock = redissonClient.getLock("icbcAdminFund:order:" + order.getCode());
      if (!lock.tryLock()) {
         throw new ServiceException("该订单正在执行工行资金操作,请勿重复提交");
      }
      try {
         IcbcPaymentResp payment = requireFeignData(icbcPaymentClient.query(order.getCode()), "工行支付查询失败");
         String orderId = extractIcbcOrderId(payment);
         order.setRechargeSerialNumber(orderId);
         RBucket<String> pendingRefund = redissonClient.getBucket("icbcAdminFund:pending:main:" + order.getCode());
         String generatedRefundNo = "ICBCADMINREFUND" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
         String pendingValue = pendingRefund.get();
         boolean reusingPending = StringUtils.hasLength(pendingValue);
         String refundNo;
         try {
            refundNo = IcbcAdminFundOperationSupport.resolveRefundNo(pendingValue, amount, generatedRefundNo);
         } catch (IllegalArgumentException e) {
            throw new ServiceException(e.getMessage());
         }
         IcbcRefundReq refundRequest = IcbcAdminFundOperationSupport.buildRefundRequest(order, amount, refundNo);
         if (!reusingPending) {
            pendingRefund.set(IcbcAdminFundOperationSupport.buildPendingRefundValue(refundNo, amount));
         }
         IcbcRefundResp response = requireFeignData(icbcPaymentClient.refund(refundRequest), "工行退款调用失败");
         if (IcbcAdminFundOperationSupport.shouldClearPendingRefund(
               reusingPending, response.getStatus(), isDefinitiveIcbcResponse(response.getRawResponse()))) {
            pendingRefund.delete();
         }
         return response;
      } finally {
         if (lock.isHeldByCurrentThread()) {
            lock.unlock();
         }
      }
   }
   @Override
   public List<IcbcAdminSubOrderVO> queryIcbcAdminSubOrders(String orderCode) {
      TChargingOrder order = loadIcbcAdminOrder(orderCode);
      List<TChargingOrderShareRecord> records = chargingOrderShareRecordMapper.selectList(
            new LambdaQueryWrapper<TChargingOrderShareRecord>()
                  .eq(TChargingOrderShareRecord::getChargingOrderId, order.getId())
                  .eq(TChargingOrderShareRecord::getPayChannel, "ICBC")
                  .eq(TChargingOrderShareRecord::getDelFlag, false)
                  .orderByAsc(TChargingOrderShareRecord::getId));
      List<IcbcAdminSubOrderVO> result = new ArrayList<>();
      for (TChargingOrderShareRecord record : records) {
         IcbcAdminSubOrderVO item = buildIcbcAdminSubOrderVO(record);
         try {
            IcbcSubOrderQueryReq query = IcbcAdminFundOperationSupport.buildSubOrderQueryRequest(order, record);
            item.applyQuery(requireFeignData(icbcPaymentClient.querySubOrder(query), "工行子订单查询失败"));
         } catch (Exception e) {
            item.setQueryStatus("FAIL");
            item.setErrorMessage(e.getMessage());
         }
         result.add(item);
      }
      return result;
   }
   @Override
   public IcbcSubOrderRefundResp refundIcbcAdminSubOrder(IcbcAdminFundOperationReq request) {
      if (request == null || request.getShareRecordId() == null) {
         throw new ServiceException("请选择需要退款的分账子订单");
      }
      TChargingOrder order = loadIcbcAdminOrder(request.getOrderCode());
      TChargingOrderShareRecord shareRecord = chargingOrderShareRecordMapper.selectById(request.getShareRecordId());
      if (shareRecord == null || !order.getId().equals(shareRecord.getChargingOrderId())) {
         throw new ServiceException("分账记录不属于当前订单");
      }
      BigDecimal amount;
      try {
         amount = IcbcAdminFundOperationSupport.requireAmount(request.getAmount());
      } catch (IllegalArgumentException e) {
         throw new ServiceException(e.getMessage());
      }
      if (shareRecord.getShareAmount() != null && amount.compareTo(shareRecord.getShareAmount()) > 0) {
         throw new ServiceException("分账退款金额不能超过分账金额" + shareRecord.getShareAmount().toPlainString() + "元");
      }
      RLock lock = redissonClient.getLock("icbcAdminFund:order:" + order.getCode());
      if (!lock.tryLock()) {
         throw new ServiceException("该分账子订单正在退款,请勿重复提交");
      }
      try {
         String suffix = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
         RBucket<String> pendingRefund = redissonClient.getBucket("icbcAdminFund:pending:sub:" + shareRecord.getId());
         String generatedToken = "ICBCSUBREFUND" + suffix + ":ICBCSUBREFUNDNO" + suffix;
         String pendingValue = pendingRefund.get();
         boolean reusingPending = StringUtils.hasLength(pendingValue);
         String operationToken;
         try {
            operationToken = IcbcAdminFundOperationSupport.resolveRefundNo(pendingValue, amount, generatedToken);
         } catch (IllegalArgumentException e) {
            throw new ServiceException(e.getMessage());
         }
         String[] refundNumbers = operationToken.split(":", 2);
         if (refundNumbers.length != 2) {
            throw new ServiceException("工行分账退款幂等记录格式错误");
         }
         IcbcSubOrderRefundReq refundRequest;
         try {
            refundRequest = IcbcAdminFundOperationSupport.buildSubOrderRefundRequest(
                  order, shareRecord, amount, refundNumbers[0], refundNumbers[1]);
         } catch (IllegalArgumentException e) {
            throw new ServiceException(e.getMessage());
         }
         if (!reusingPending) {
            pendingRefund.set(IcbcAdminFundOperationSupport.buildPendingRefundValue(operationToken, amount));
         }
         IcbcSubOrderRefundResp response = requireFeignData(
               icbcPaymentClient.refundSubOrder(refundRequest), "工行分账退款调用失败");
         if (IcbcAdminFundOperationSupport.shouldClearPendingRefund(
               reusingPending, response.getStatus(), isDefinitiveIcbcResponse(response.getRawResponse()))) {
            pendingRefund.delete();
         }
         return response;
      } finally {
         if (lock.isHeldByCurrentThread()) {
            lock.unlock();
         }
      }
   }
   private TChargingOrder loadIcbcAdminOrder(String orderCode) {
      if (!StringUtils.hasLength(orderCode)) {
         throw new ServiceException("订单号不能为空");
      }
      TChargingOrder order = this.getOne(new LambdaQueryWrapper<TChargingOrder>()
            .eq(TChargingOrder::getCode, orderCode)
            .eq(TChargingOrder::getDelFlag, 0)
            .last("limit 1"));
      try {
         IcbcAdminFundOperationSupport.validateOrder(order);
      } catch (IllegalArgumentException e) {
         throw new ServiceException(e.getMessage());
      }
      return order;
   }
   private String extractIcbcOrderId(IcbcPaymentResp payment) {
      try {
         JSONObject response = JSON.parseObject(payment.getRawResponse());
         String orderId = response == null ? null : response.getString("order_id");
         if (StringUtils.hasLength(orderId)) {
            return orderId;
         }
      } catch (Exception ignored) {
      }
      throw new ServiceException("工行支付查询未返回真实order_id,禁止退款");
   }
   private boolean isDefinitiveIcbcResponse(String rawResponse) {
      if (!StringUtils.hasLength(rawResponse)) {
         return false;
      }
      try {
         JSONObject response = JSON.parseObject(rawResponse);
         return response != null && (response.containsKey("returnCode") || response.containsKey("return_code"));
      } catch (Exception ignored) {
         return false;
      }
   }
   private IcbcAdminSubOrderVO buildIcbcAdminSubOrderVO(TChargingOrderShareRecord record) {
      IcbcAdminSubOrderVO item = new IcbcAdminSubOrderVO();
      item.setShareRecordId(record.getId());
      item.setOrderCode(record.getChargingOrderCode());
      item.setShareAmount(record.getShareAmount());
      item.setOnlineShareStatus(record.getOnlineShareStatus());
      item.setSubOrderId(record.getSubOrderId());
      item.setSubMerId(record.getSubMerId());
      item.setSubMerPrtclNo(record.getSubMerPrtclNo());
      item.setOriTrxDate(record.getOriTrxDate());
      item.setBankOrderId(record.getIcbcOrderId());
      item.setSubOrderSeq(record.getSubOrderSeq());
      item.setSubOrderTrxid(record.getSubOrderTrxid());
      return item;
   }
   private <T> T requireFeignData(R<T> result, String message) {
      if (result == null || R.isError(result) || result.getData() == null) {
         throw new ServiceException(result != null && StringUtils.hasLength(result.getMsg()) ? result.getMsg() : message);
      }
      return result.getData();
   }
   
   
@@ -938,7 +1325,26 @@
   @Override
   public AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach) {
      TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, out_trade_no));
      if (chargingOrder == null) {
         return AjaxResult.error("支付回调订单不存在");
      }
      if (chargingOrder.getRechargePaymentStatus() == 2) {
         if (isIcbcOrder(chargingOrder) && StringUtils.hasLength(transaction_id)
               && !transaction_id.equals(chargingOrder.getRechargeSerialNumber())) {
            chargingOrder.setRechargeSerialNumber(transaction_id);
            this.updateById(chargingOrder);
         }
         return AjaxResult.success();
      }
      LocalDateTime callbackPayTime = LocalDateTime.now();
      int claimed = this.baseMapper.update(null, new LambdaUpdateWrapper<TChargingOrder>()
            .eq(TChargingOrder::getId, chargingOrder.getId())
            .eq(TChargingOrder::getRechargePaymentStatus, 1)
            .set(TChargingOrder::getRechargePaymentStatus, 2)
            .set(TChargingOrder::getRechargeSerialNumber, transaction_id)
            .set(TChargingOrder::getStatus, 2)
            .set(TChargingOrder::getPayTime, callbackPayTime));
      if (claimed == 0) {
         return AjaxResult.success();
      }
      if (isBalancePayMode(chargingOrder.getPayMethod())
@@ -954,7 +1360,7 @@
      chargingOrder.setRechargePaymentStatus(2);
      chargingOrder.setRechargeSerialNumber(transaction_id);
      chargingOrder.setStatus(2);
      chargingOrder.setPayTime(LocalDateTime.now());
      chargingOrder.setPayTime(callbackPayTime);
      
      //添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据
      PreChargeCheck preChargeCheck = new PreChargeCheck();
@@ -1509,6 +1915,11 @@
                        return;
                    }
                    this.updateById(chargingOrder);
                    if (isIcbcOrder(chargingOrder)) {
                        refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount, "充电失败,取消充电订单", false,
                                recordedRefundAmount, balanceRefundAmount);
                        return;
                    }
                    if (thirdRefundAmount.compareTo(BigDecimal.ZERO) > 0 && 1 == rechargePaymentType) {
                        WxPaymentRefundModel model = new WxPaymentRefundModel();
                        model.setOut_trade_no(chargingOrder.getCode());
@@ -1660,6 +2071,11 @@
            finishManualChargingRefund(chargingOrder, chargingOrderRefund, money, balanceRefundAmount, thirdRefundAmount);
            return;
         }
         if (isIcbcOrder(chargingOrder)) {
            refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount, "充电完成退款", true,
                  money, balanceRefundAmount);
            return;
         }
         if (1 == rechargePaymentType) {
            WxPaymentRefundModel model = new WxPaymentRefundModel();
            model.setOut_trade_no(chargingOrder.getCode());
@@ -1764,6 +2180,7 @@
                chargingOrder.setRefundSerialNumber(refund_id);
                chargingOrder.setRefundTime(LocalDateTime.now());
                this.updateById(chargingOrder);
                triggerChargingOrderShare(this.getById(order.getId()));
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
@@ -2089,6 +2506,7 @@
         List<Integer> siteIds = dto.getSiteIds();
         List<ChargingOrderVO> list = this.baseMapper.chargingOrder(pageInfo, dto, startTime1, startTime2, endTime1, endTime2);
         fillChargingOrderBalanceIncome(list);
         fillChargingOrderShareIncome(list);
         List<TChargingOrderAccountingStrategy> list3 = chargingOrderAccountingStrategyService.list();
      for (ChargingOrderVO chargingOrderVO : list) {
         if (roleType == 2) {
@@ -2164,13 +2582,14 @@
      }
      Map<String, Object> fundMap = this.baseMapper.chargingOrderFundSummary(dto, startTime1, startTime2, endTime1, endTime2);
      if (null != fundMap) {
         tCharingOrderVO.setPlatformIncomeTotal(getSummaryDecimal(fundMap, "platformIncomeTotal"));
         tCharingOrderVO.setPartnerIncomeTotal(getSummaryDecimal(fundMap, "partnerIncomeTotal"));
         tCharingOrderVO.setWechatIncome(getSummaryDecimal(fundMap, "wechatIncome"));
         tCharingOrderVO.setAlipayIncome(getSummaryDecimal(fundMap, "alipayIncome"));
         tCharingOrderVO.setWhitelistChargingIncome(getSummaryDecimal(fundMap, "whitelistChargingIncome"));
         tCharingOrderVO.setWhitelistRefund(getSummaryDecimal(fundMap, "whitelistRefund"));
      }
      Map<String, Object> shareIncomeMap = getChargingOrderShareIncomeSummary(dto, startTime1, startTime2, endTime1, endTime2);
      tCharingOrderVO.setPlatformIncomeTotal(getSummaryDecimal(shareIncomeMap, "platformIncomeTotal"));
      tCharingOrderVO.setPartnerIncomeTotal(getSummaryDecimal(shareIncomeMap, "partnerIncomeTotal"));
      Map<String, Object> balanceMap = getExchangeCodeBalanceSummary(dto, startTime1, startTime2, endTime1, endTime2);
      tCharingOrderVO.setBalanceIncome(getSummaryDecimal(balanceMap, "balanceIncome"));
      tCharingOrderVO.setBalanceGiftIncome(getSummaryDecimal(balanceMap, "balanceGiftIncome"));
@@ -2351,6 +2770,30 @@
      return totalMap;
   }
   private Map<String, Object> getChargingOrderShareIncomeSummary(ChargingOrderQuery dto, String startTime1, String startTime2, String endTime1, String endTime2) {
      Map<String, Object> totalMap = new HashMap<>();
      totalMap.put("platformIncomeTotal", BigDecimal.ZERO);
      totalMap.put("partnerIncomeTotal", BigDecimal.ZERO);
      List<Long> orderIds = this.baseMapper.chargingOrderSummaryOrderIds(dto, startTime1, startTime2, endTime1, endTime2);
      if (orderIds == null || orderIds.isEmpty()) {
         return totalMap;
      }
      BigDecimal platformIncomeTotal = BigDecimal.ZERO;
      BigDecimal partnerIncomeTotal = BigDecimal.ZERO;
      int batchSize = 500;
      for (int i = 0; i < orderIds.size(); i += batchSize) {
         List<Long> batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size()));
         Map<String, Object> batchMap = this.baseMapper.chargingOrderShareIncomeSummaryByOrderIds(batchIds);
         if (batchMap != null) {
            platformIncomeTotal = platformIncomeTotal.add(getSummaryDecimal(batchMap, "platformIncomeTotal"));
            partnerIncomeTotal = partnerIncomeTotal.add(getSummaryDecimal(batchMap, "partnerIncomeTotal"));
         }
      }
      totalMap.put("platformIncomeTotal", platformIncomeTotal);
      totalMap.put("partnerIncomeTotal", partnerIncomeTotal);
      return totalMap;
   }
      private BigDecimal getSummaryDecimal(Map<String, Object> map, String key) {
         if (map == null) {
            return BigDecimal.ZERO;
@@ -2471,27 +2914,30 @@
   }
   
   @Override
   public List<SixChargingDto> charge(LocalDate sixBefore, List<Integer> siteIds) {
      return this.baseMapper.charge(sixBefore, siteIds);
   public List<SixChargingDto> charge(LocalDate sixBefore, List<Integer> siteIds, Boolean partnerView) {
      return this.baseMapper.charge(sixBefore, siteIds, partnerView);
   }
   
   @Override
   public List<SixCircleDto> circle(List<Integer> siteIds, LocalDate sixBefore) {
      return this.baseMapper.circle(siteIds, sixBefore);
   public List<SixCircleDto> circle(List<Integer> siteIds, LocalDate sixBefore, Boolean partnerView) {
      return this.baseMapper.circle(siteIds, sixBefore, partnerView);
   }
   
   @Override
   public Map<String, Object> countAll(List<Integer> siteIds) {
      return this.baseMapper.countAll(siteIds);
   public Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView) {
      return this.baseMapper.countAll(siteIds, partnerView);
   }
   /**
    * 统计近六月订单收入支付方式占比;服务层聚合避免复杂CASE SQL在当前数据库驱动中转换异常。
    */
   @Override
   public List<SixIncomeCircleDto> payTypeCircle(LocalDate sixBefore, List<Integer> siteIds) {
   public List<SixIncomeCircleDto> payTypeCircle(LocalDate sixBefore, List<Integer> siteIds, Boolean partnerView) {
      if (siteIds == null || siteIds.isEmpty()) {
         return buildPayTypeCircleData(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
      }
      if (Boolean.TRUE.equals(partnerView)) {
         return buildPartnerShareCircleData(this.baseMapper.chargingOrderShareIncomeByPayChannel(sixBefore, siteIds));
      }
      List<TChargingOrder> orders = this.lambdaQuery()
            .select(TChargingOrder::getRechargePaymentType, TChargingOrder::getPayMethod,
@@ -2521,6 +2967,28 @@
         Integer payMethod = order.getPayMethod();
         if (Integer.valueOf(1).equals(payMethod) || Integer.valueOf(2).equals(payMethod)) {
            balanceAmount = balanceAmount.add(balancePayAmount);
         }
      }
      return buildPayTypeCircleData(wechatAmount, alipayAmount, balanceAmount);
   }
   private List<SixIncomeCircleDto> buildPartnerShareCircleData(List<Map<String, Object>> rows) {
      BigDecimal wechatAmount = BigDecimal.ZERO;
      BigDecimal alipayAmount = BigDecimal.ZERO;
      BigDecimal balanceAmount = BigDecimal.ZERO;
      if (rows != null) {
         for (Map<String, Object> row : rows) {
            String channel = row.get("payChannel") == null ? "" : row.get("payChannel").toString();
            BigDecimal shareAmount = getSummaryDecimal(row, "shareAmount");
            if ("WECHAT".equalsIgnoreCase(channel) || "WX".equalsIgnoreCase(channel)) {
               wechatAmount = wechatAmount.add(shareAmount);
            } else if ("ALIPAY".equalsIgnoreCase(channel) || "ALI".equalsIgnoreCase(channel)) {
               alipayAmount = alipayAmount.add(shareAmount);
            } else if ("BALANCE".equalsIgnoreCase(channel) || "WHITELIST".equalsIgnoreCase(channel)) {
               balanceAmount = balanceAmount.add(shareAmount);
            } else {
               wechatAmount = wechatAmount.add(shareAmount);
            }
         }
      }
      return buildPayTypeCircleData(wechatAmount, alipayAmount, balanceAmount);
@@ -2717,6 +3185,7 @@
      PageInfo<ChargingOrderListVO> pageInfo = new PageInfo<>(dto.getPageCurr(), dto.getPageSize());
      List<ChargingOrderListVO> list = new ArrayList<>();
      Map<Integer, BigDecimal> siteServiceShareRatioMap = loadSiteServiceShareRatioMap();
      List<Map<String, Object>> maps = this.baseMapper.chargingList1(pageInfo, dto, startTime1, startTime2, endTime1, endTime2);
      for (Map<String, Object> map : maps) {
         if(null == map){
@@ -2730,34 +3199,36 @@
         }
         chargingOrderListVO.setUid(map.get("id").toString());
         chargingOrderListVO.setCode(map.get("code").toString());
         chargingOrderListVO.setId(Long.valueOf(map.get("id").toString()));
         chargingOrderListVO.setSiteId(Integer.valueOf(map.get("siteId").toString()));
         chargingOrderListVO.setOrderSource(Integer.valueOf(map.get("orderSource").toString()));
         chargingOrderListVO.setSiteName(map.get("siteName").toString());
         chargingOrderListVO.setOrderType(map.get("orderType").toString());
         chargingOrderListVO.setTerminalName(map.get("terminalName").toString());
         chargingOrderListVO.setElectricity(null == map.get("electricity") ? BigDecimal.ZERO : new BigDecimal(map.get("electricity").toString()));
         chargingOrderListVO.setChargingCapacity(chargingOrderListVO.getElectricity());
         Object periodElectricPrice = map.get("periodElectricPrice");
         Object periodServicePrice = map.get("periodServicePrice");
         if(null != periodServicePrice){
            Integer orderSource = Integer.valueOf(map.get("orderSource").toString());
         BigDecimal periodElectricPrice = getSummaryDecimal(map, "periodElectricPrice");
         BigDecimal periodServicePrice = getSummaryDecimal(map, "periodServicePrice");
         if(periodServicePrice.compareTo(BigDecimal.ZERO) != 0){
            Integer orderSource = chargingOrderListVO.getOrderSource();
            if(2 == orderSource){
               BigDecimal bigDecimal = new BigDecimal(periodServicePrice.toString()).multiply(new BigDecimal(0.8)).setScale(2, RoundingMode.HALF_EVEN);
               chargingOrderListVO.setPaymentAmount(new BigDecimal(periodElectricPrice.toString()).add(bigDecimal));
               BigDecimal sharingAmount = new BigDecimal(periodServicePrice.toString()).multiply(new BigDecimal(0.2)).setScale(2, RoundingMode.HALF_EVEN);
               BigDecimal bigDecimal = periodServicePrice.multiply(new BigDecimal("0.8")).setScale(2, RoundingMode.HALF_EVEN);
               chargingOrderListVO.setServiceCharge(bigDecimal);
               chargingOrderListVO.setPaymentAmount(periodElectricPrice.add(bigDecimal).setScale(2, RoundingMode.HALF_EVEN));
               BigDecimal sharingAmount = periodServicePrice.multiply(new BigDecimal("0.2")).setScale(2, RoundingMode.HALF_EVEN);
               chargingOrderListVO.setSharingAmount(sharingAmount);
            }else{
               chargingOrderListVO.setPaymentAmount(new BigDecimal(periodElectricPrice.toString()).add(new BigDecimal(periodServicePrice.toString())).setScale(2, RoundingMode.HALF_EVEN));
               chargingOrderListVO.setServiceCharge(periodServicePrice);
               chargingOrderListVO.setPaymentAmount(periodElectricPrice.add(periodServicePrice).setScale(2, RoundingMode.HALF_EVEN));
               chargingOrderListVO.setSharingAmount(BigDecimal.ZERO);
            }
         }else{
            chargingOrderListVO.setServiceCharge(BigDecimal.ZERO);
            chargingOrderListVO.setPaymentAmount(BigDecimal.ZERO);
            chargingOrderListVO.setSharingAmount(BigDecimal.ZERO);
         }
         chargingOrderListVO.setElectrovalence(null == map.get("electrovalence") ? BigDecimal.ZERO : new BigDecimal(map.get("electrovalence").toString()));
         chargingOrderListVO.setServiceCharge(null == map.get("serviceCharge") ? BigDecimal.ZERO : new BigDecimal(map.get("serviceCharge").toString()));
         BigDecimal bigDecimal = new BigDecimal("0.006");
         if (!"0".equals(map.get("rechargePaymentType").toString())) {
            chargingOrderListVO.setCommissionAmount(new BigDecimal(map.get("rechargeAmount").toString()).multiply(bigDecimal));
         }
         fillChargingPeriodIncome(chargingOrderListVO, siteServiceShareRatioMap);
         if(null != map.get("tripartitePlatformName")){
            chargingOrderListVO.setTripartitePlatformName(map.get("tripartitePlatformName").toString());
         }
@@ -2854,21 +3325,41 @@
        Map<String, Object> map = this.baseMapper.chargingListSum1(dto, startTime1, startTime2, endTime1, endTime2);
        System.err.println("充电时段统计-查询参数:" + JSON.toJSONString(dto));
        System.err.println("充电时段统计-汇总数据:" + JSON.toJSONString(map));
      if (map == null) {
         map = new HashMap<>();
      }
        //订单数量
        int orderCount = Integer.parseInt(map.get("orderCount").toString());
        int orderCount = Integer.parseInt(String.valueOf(map.getOrDefault("orderCount", "0")));
        // 计算充电总度数
        BigDecimal electronic = new BigDecimal(map.get("electronic").toString());
        BigDecimal electronic = new BigDecimal(String.valueOf(map.getOrDefault("electronic", "0")));
        // 支付金额
        BigDecimal paymentAmount = new BigDecimal(map.get("paymentAmount").toString());
        BigDecimal paymentAmount = new BigDecimal(String.valueOf(map.getOrDefault("paymentAmount", "0")));
        // 电费
        BigDecimal electrovalence = new BigDecimal(map.get("electrovalence").toString());
        BigDecimal electrovalence = new BigDecimal(String.valueOf(map.getOrDefault("electrovalence", "0")));
        // 服务费
        BigDecimal serviceCharge = new BigDecimal(map.get("serviceCharge").toString());
        chargingOrderTimeVO.setOrderCount(orderCount);
      BigDecimal serviceCharge = new BigDecimal(String.valueOf(map.getOrDefault("serviceCharge", "0")));
      chargingOrderTimeVO.setOrderCount(orderCount);
      chargingOrderTimeVO.setChargingCapacity(electronic.setScale(2, BigDecimal.ROUND_HALF_EVEN));
      chargingOrderTimeVO.setPaymentAmount(paymentAmount.setScale(2, BigDecimal.ROUND_HALF_EVEN));
      chargingOrderTimeVO.setElectrovalence(electrovalence.setScale(2, BigDecimal.ROUND_HALF_EVEN));
      chargingOrderTimeVO.setServiceCharge(serviceCharge.setScale(2, BigDecimal.ROUND_HALF_EVEN));
      BigDecimal platformIncome = BigDecimal.ZERO;
      BigDecimal partnerIncome = BigDecimal.ZERO;
      for (Map<String, Object> sumMap : list1) {
         if (sumMap == null) {
            continue;
         }
         ChargingOrderListVO item = new ChargingOrderListVO();
         item.setSiteId(getSummaryLong(sumMap, "siteId").intValue());
         item.setOrderSource(getSummaryLong(sumMap, "orderSource").intValue());
         item.setPaymentAmount(getSummaryDecimal(sumMap, "paymentAmount"));
         item.setServiceCharge(getSummaryDecimal(sumMap, "serviceCharge"));
         fillChargingPeriodIncome(item, siteServiceShareRatioMap);
         platformIncome = platformIncome.add(nullToZero(item.getPlatformIncome()));
         partnerIncome = partnerIncome.add(nullToZero(item.getPartnerIncome()));
      }
      chargingOrderTimeVO.setPlatformIncome(platformIncome.setScale(2, RoundingMode.HALF_UP));
      chargingOrderTimeVO.setPartnerIncome(partnerIncome.setScale(2, RoundingMode.HALF_UP));
      // 计算尖峰平谷充电到账占比
      BigDecimal add = jianElectronic.add(fengElectronic).add(pingElectronic).add(guElectronic);
      // 计算尖峰平谷服务费占比
@@ -2998,7 +3489,60 @@
      dto.setSiteIds(siteIds);
      List<ChargingOrderListVO> list1 = this.baseMapper.chargingList(dto, startTime1, startTime2, endTime1, endTime2);
      fillChargingPeriodExportBalanceIncome(list1);
      fillChargingPeriodIncome(list1);
      return list1;
   }
   private void fillChargingPeriodIncome(List<ChargingOrderListVO> list) {
      if (list == null || list.isEmpty()) {
         return;
      }
      Map<Integer, BigDecimal> siteServiceShareRatioMap = loadSiteServiceShareRatioMap();
      for (ChargingOrderListVO item : list) {
         fillChargingPeriodIncome(item, siteServiceShareRatioMap);
      }
   }
   private void fillChargingPeriodIncome(ChargingOrderListVO item, Map<Integer, BigDecimal> siteServiceShareRatioMap) {
      if (item == null) {
         return;
      }
      BigDecimal paymentAmount = nullToZero(item.getPaymentAmount());
      BigDecimal partnerIncome = BigDecimal.ZERO;
      if (!Integer.valueOf(2).equals(item.getOrderSource())) {
         BigDecimal serviceShareRatio = siteServiceShareRatioMap.get(item.getSiteId());
         if (serviceShareRatio != null && serviceShareRatio.compareTo(BigDecimal.ZERO) > 0) {
            partnerIncome = nullToZero(item.getServiceCharge())
                  .multiply(serviceShareRatio)
                  .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
         }
      }
      item.setPartnerIncome(partnerIncome);
      item.setPlatformIncome(paymentAmount.subtract(partnerIncome).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP));
   }
   private Map<Integer, BigDecimal> loadSiteServiceShareRatioMap() {
      Map<Integer, BigDecimal> ratioMap = new HashMap<>();
      R<List<Site>> siteResult = siteClient.getSiteAll();
      R<List<Partner>> partnerResult = siteClient.getAllPartner();
      List<Site> sites = siteResult == null ? Collections.emptyList() : siteResult.getData();
      List<Partner> partners = partnerResult == null ? Collections.emptyList() : partnerResult.getData();
      if (sites == null || sites.isEmpty() || partners == null || partners.isEmpty()) {
         return ratioMap;
      }
      Map<Integer, Partner> partnerMap = partners.stream()
            .filter(partner -> partner != null && partner.getId() != null)
            .collect(Collectors.toMap(Partner::getId, partner -> partner, (left, right) -> left));
      for (Site site : sites) {
         if (site == null || site.getId() == null || site.getPartnerId() == null) {
            continue;
         }
         Partner partner = partnerMap.get(site.getPartnerId());
         if (partner != null && partner.getServiceShareRatio() != null) {
            ratioMap.put(site.getId(), partner.getServiceShareRatio());
         }
      }
      return ratioMap;
   }
   /**
@@ -3026,6 +3570,31 @@
         Map<String, Object> row = incomeMap.get(item.getId());
         item.setBalanceIncome(getSummaryDecimal(row, "balanceIncome"));
         item.setBalanceGiftIncome(getSummaryDecimal(row, "balanceGiftIncome"));
      }
   }
   private void fillChargingOrderShareIncome(List<ChargingOrderVO> list) {
      if (list == null || list.isEmpty()) {
         return;
      }
      List<Long> orderIds = list.stream().map(ChargingOrderVO::getId).filter(Objects::nonNull).collect(Collectors.toList());
      if (orderIds.isEmpty()) {
         return;
      }
      Map<Long, Map<String, Object>> incomeMap = new HashMap<>();
      List<Map<String, Object>> rows = this.baseMapper.chargingOrderShareIncomeByOrderIds(orderIds);
      if (rows != null) {
         for (Map<String, Object> row : rows) {
            Long orderId = getSummaryLong(row, "orderId");
            if (orderId != null) {
               incomeMap.put(orderId, row);
            }
         }
      }
      for (ChargingOrderVO item : list) {
         Map<String, Object> row = incomeMap.get(item.getId());
         item.setPlatformIncome(getSummaryDecimal(row, "platformIncome"));
         item.setPartnerIncome(getSummaryDecimal(row, "partnerIncome"));
      }
   }
@@ -3220,15 +3789,19 @@
    @Transactional
   public R endChargeBillingCharge(TransactionRecordMessageVO vo) {
      RLock lock = redissonClient.getLock("endOrder:" + vo.getTransaction_serial_number());
      boolean locked = false;
      try {
            boolean tryLock = lock.tryLock(60, 60, TimeUnit.SECONDS);
            locked = lock.tryLock(60, 60, TimeUnit.SECONDS);
            if (!locked) {
                return R.fail("订单正在结算,请勿重复操作");
            }
            //添加redis缓存数据,过期时间,用于防止处理缓慢且硬件重复发送报文导致的重复退款
            Boolean hasKey = redisService.hasKey("END_ORDER:" + vo.getTransaction_serial_number());
            if(hasKey){
                return R.fail("不能重复退款");
            }
            redisService.setCacheObject("END_ORDER:" + vo.getTransaction_serial_number(), System.currentTimeMillis() + "", 10L, TimeUnit.MINUTES);
            if(tryLock){
            if(locked){
                TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, vo.getTransaction_serial_number()));
                if (null == chargingOrder) {
                    log.error("订单不存在,订单号:{}", vo.getTransaction_serial_number());
@@ -3724,6 +4297,17 @@
                            chargingOrder.setRefundStatus(2);
                            chargingOrder.setRefundTime(LocalDateTime.now());
                            this.updateById(chargingOrder);
                            triggerChargingOrderShare(chargingOrder);
                        } else if (isIcbcOrder(chargingOrder)) {
                            boolean refundSuccess = refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount,
                                    "充电完成退款", false, refundAmount, balanceRefundAmount);
                            if (!refundSuccess) {
                                chargingOrderRefund.setRefundStatus(1);
                                chargingOrderRefundService.save(chargingOrderRefund);
                                chargingOrder.setRefundStatus(1);
                                this.updateById(chargingOrder);
                                throw new ServiceException("工行退款失败,结算未完成,请检查支付流水后重试退款");
                            }
                        } else if (1 == rechargePaymentType) {
                            WxPaymentRefundModel model = new WxPaymentRefundModel();
                            model.setOut_trade_no(chargingOrder.getCode());
@@ -3793,6 +4377,7 @@
                        chargingOrder.setRefundStatus(2);
                        chargingOrder.setRefundTime(LocalDateTime.now());
                        this.updateById(chargingOrder);
                        triggerChargingOrderShare(chargingOrder);
                    } else {
                        //构建退款明细
                        TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
@@ -3821,6 +4406,7 @@
                        chargingOrder.setRefundStatus(2);
                        chargingOrder.setRefundTime(LocalDateTime.now());
                        this.updateById(chargingOrder);
                        triggerChargingOrderShare(chargingOrder);
                    }
                }
@@ -3853,6 +4439,9 @@
                summaryData.setElectricPrice(electronic_reduce.setScale(2, BigDecimal.ROUND_HALF_EVEN));
                summaryData.setServicePrice(serviceMoney.setScale(2, BigDecimal.ROUND_HALF_EVEN));
                chargingOrderSummaryDataService.save(summaryData);
                if (channelRefundAmount.compareTo(BigDecimal.ZERO) == 0 && Integer.valueOf(2).equals(chargingOrder.getRefundStatus())) {
                    triggerChargingOrderShare(chargingOrder, site);
                }
                //推送监管平台订单状态和订单详情
                ChargingOrderVo chargingOrderVo = new ChargingOrderVo();
@@ -3861,9 +4450,12 @@
                chargingMessageClient.pushOrderStatus(chargingOrderVo);
            }
      } catch (Exception e) {
         e.printStackTrace();
         log.error("充电订单结算失败,订单号:{}", vo == null ? null : vo.getTransaction_serial_number(), e);
         return R.fail("充电订单结算失败:" + firstNotBlank(e.getMessage(), "未知异常"));
      } finally {
         lock.unlock();
         if (locked && lock.isHeldByCurrentThread()) {
            lock.unlock();
         }
      }
      return R.ok();
   }
@@ -4004,6 +4596,10 @@
         if (thirdRefundAmount.compareTo(BigDecimal.ZERO) == 0) {
            chargingOrderRefund.setRefundSerialNumber("BALANCE");
            finishManualChargingRefund(tChargingOrder, chargingOrderRefund, manualRefundAmount, balanceRefundAmount, thirdRefundAmount);
         }
         else if (isIcbcOrder(tChargingOrder)) {
            refundByIcbcAndFinish(tChargingOrder, chargingOrderRefund, thirdRefundAmount, "取消订单", true,
                  manualRefundAmount, balanceRefundAmount);
         }
         else if (1 == tChargingOrder.getRechargePaymentType()) {
            WxPaymentRefundModel model = new WxPaymentRefundModel();
@@ -6143,4 +6739,414 @@
            e.printStackTrace();
        }
    }
   private boolean isIcbcRemovableStatus(String status, TChargingOrder order) {
      if (!StringUtils.hasLength(status)) {
         return false;
      }
      if (Arrays.asList("FAIL", "FAILED", "CLOSED", "TRADE_CLOSED", "REVOKED", "PAYERROR").contains(status)) {
         return true;
      }
      // 工行B2C不支持主动关单;NOTPAY超时仅释放本地待支付订单,不代表远端订单已关闭。
      return "NOTPAY".equals(status) && isLocalPendingOrderExpired(order);
   }
   private boolean isLocalPendingOrderExpired(TChargingOrder order) {
      return order != null && order.getCreateTime() != null && order.getCreateTime().plusMinutes(30).isBefore(LocalDateTime.now());
   }
   private boolean isIcbcPaymentCreated(IcbcPaymentResp resp) {
      if (resp == null || !StringUtils.hasLength(resp.getStatus())) {
         return false;
      }
      if (!"SUCCESS".equals(resp.getStatus()) || !StringUtils.hasLength(resp.getPayData())) {
         return false;
      }
      try {
         JSONObject payData = JSON.parseObject(resp.getPayData());
         return StringUtils.hasLength(payData.getString("wxDataPackage")) || StringUtils.hasLength(payData.getString("package"));
      } catch (Exception e) {
         return false;
      }
   }
   private void triggerChargingOrderShare(TChargingOrder chargingOrder, Site site) {
      try {
         if (!isNeedChargingOrderShare(chargingOrder)) {
            return;
         }
         Partner partner = loadPartner(site);
         for (TChargingOrderShareRecord shareRecord : buildChargingOrderShareRecords(chargingOrder, site, partner)) {
            TChargingOrderShareRecord exist = chargingOrderShareRecordMapper.selectOne(new LambdaQueryWrapper<TChargingOrderShareRecord>()
                  .eq(TChargingOrderShareRecord::getChargingOrderCode, shareRecord.getChargingOrderCode())
                  .eq(TChargingOrderShareRecord::getPayChannel, shareRecord.getPayChannel())
                  .eq(TChargingOrderShareRecord::getDelFlag, false)
                  .last("limit 1"));
            if (exist != null && ("SUCCESS".equals(exist.getOnlineShareStatus()) || "PROCESSING".equals(exist.getOnlineShareStatus()))) {
               continue;
            }
            shareRecord = mergeChargingOrderShareRecord(exist, shareRecord);
            saveOrUpdateChargingOrderShareRecord(shareRecord);
            if (Boolean.TRUE.equals(shareRecord.getNeedOnlineShare())) {
               processIcbcOnlineShare(shareRecord, partner);
            }
         }
      } catch (Exception e) {
         log.error("充电订单分账记录触发失败,订单号:{}", chargingOrder == null ? null : chargingOrder.getCode(), e);
         recordChargingOrderShareFailure(chargingOrder, site, e);
      }
   }
   private void triggerChargingOrderShare(TChargingOrder chargingOrder) {
      try {
         if (chargingOrder == null || chargingOrder.getSiteId() == null) {
            return;
         }
         R<List<Site>> siteResult = siteClient.getSiteByIds(Arrays.asList(chargingOrder.getSiteId()));
         List<Site> sites = siteResult == null ? null : siteResult.getData();
         Site site = sites == null || sites.isEmpty() ? null : sites.get(0);
         triggerChargingOrderShare(chargingOrder, site);
      } catch (Exception e) {
         log.error("充电订单分账站点加载失败,订单号:{}", chargingOrder == null ? null : chargingOrder.getCode(), e);
      }
   }
   private boolean isNeedChargingOrderShare(TChargingOrder chargingOrder) {
      return chargingOrder != null
            && Integer.valueOf(5).equals(chargingOrder.getStatus())
            && Integer.valueOf(2).equals(chargingOrder.getRechargePaymentStatus())
            && Integer.valueOf(2).equals(chargingOrder.getRefundStatus())
            && getChargingOrderShareBaseAmount(chargingOrder).compareTo(BigDecimal.ZERO) > 0;
   }
   private Partner loadPartner(Site site) {
      if (site == null || site.getPartnerId() == null) {
         return null;
      }
      R<Partner> partnerResult = partnerClient.getPartnerById(site.getPartnerId());
      return partnerResult == null ? null : partnerResult.getData();
   }
   private List<TChargingOrderShareRecord> buildChargingOrderShareRecords(TChargingOrder chargingOrder, Site site, Partner partner) {
      BigDecimal actualThirdPay = getActualThirdPayAmount(chargingOrder);
      BalanceShareAmount balanceShareAmount = getBalanceShareAmount(chargingOrder);
      BigDecimal actualBalancePay = balanceShareAmount.getPrincipalAmount();
      BigDecimal actualTotalPay = actualThirdPay.add(actualBalancePay).setScale(2, RoundingMode.HALF_UP);
      BigDecimal shareElectricityAmount = getChargingOrderShareElectricityAmount(chargingOrder);
      BigDecimal shareServiceAmount = getChargingOrderShareServiceAmount(chargingOrder);
      BigDecimal shareBaseAmount = shareElectricityAmount.add(shareServiceAmount).setScale(2, RoundingMode.HALF_UP);
      if (actualTotalPay.compareTo(BigDecimal.ZERO) <= 0 && isWhitelistOrder(chargingOrder)) {
         actualTotalPay = shareBaseAmount;
      }
      if (actualTotalPay.compareTo(BigDecimal.ZERO) <= 0) {
         return Collections.emptyList();
      }
      if (!isWhitelistOrder(chargingOrder) && shareBaseAmount.compareTo(BigDecimal.ZERO) > 0 && actualTotalPay.compareTo(shareBaseAmount) < 0) {
         BigDecimal effectiveRatio = actualTotalPay.divide(shareBaseAmount, 6, RoundingMode.HALF_UP);
         shareElectricityAmount = shareElectricityAmount.multiply(effectiveRatio).setScale(2, RoundingMode.HALF_UP);
         shareServiceAmount = shareServiceAmount.multiply(effectiveRatio).setScale(2, RoundingMode.HALF_UP);
      }
      List<TChargingOrderShareRecord> records = new ArrayList<>();
      if (actualBalancePay.compareTo(BigDecimal.ZERO) > 0) {
         records.add(buildChargingOrderShareRecord(chargingOrder, site, partner, "BALANCE", actualBalancePay,
               balanceShareAmount.getGiftAmount(), actualTotalPay, shareElectricityAmount, shareServiceAmount));
      }
      if (actualThirdPay.compareTo(BigDecimal.ZERO) > 0) {
         records.add(buildChargingOrderShareRecord(chargingOrder, site, partner, resolveThirdPayChannel(chargingOrder), actualThirdPay,
               BigDecimal.ZERO, actualTotalPay, shareElectricityAmount, shareServiceAmount));
      }
      if (records.isEmpty() && isWhitelistOrder(chargingOrder)) {
         records.add(buildChargingOrderShareRecord(chargingOrder, site, partner, "WHITELIST", actualTotalPay,
               BigDecimal.ZERO, actualTotalPay, shareElectricityAmount, shareServiceAmount));
      }
      return records;
   }
   private TChargingOrderShareRecord buildChargingOrderShareRecord(TChargingOrder chargingOrder, Site site, Partner partner,
                                                                    String payChannel, BigDecimal channelPayAmount, BigDecimal channelGiftAmount,
                                                                    BigDecimal actualTotalPay, BigDecimal shareElectricityAmount,
                                                                    BigDecimal shareServiceAmount) {
      TChargingOrderShareRecord record = new TChargingOrderShareRecord();
      record.setChargingOrderId(chargingOrder.getId());
      record.setChargingOrderCode(chargingOrder.getCode());
      record.setSiteId(chargingOrder.getSiteId());
      record.setPartnerId(site == null ? null : site.getPartnerId());
      record.setPayChannel(payChannel);
      record.setChannelPayAmount(money(channelPayAmount));
      record.setChannelGiftAmount(money(channelGiftAmount));
      BigDecimal channelRatio = channelPayAmount.divide(actualTotalPay, 6, RoundingMode.HALF_UP);
      record.setChannelPayRatio(channelRatio);
      BigDecimal channelElectricityAmount = shareElectricityAmount.multiply(channelRatio).setScale(2, RoundingMode.HALF_UP);
      BigDecimal channelServiceAmount = shareServiceAmount.multiply(channelRatio).setScale(2, RoundingMode.HALF_UP);
      record.setChannelElectricityAmount(channelElectricityAmount);
      record.setChannelServiceAmount(channelServiceAmount);
      record.setElectricityShareRatio(partner == null ? null : partner.getElectricityShareRatio());
      record.setServiceShareRatio(partner == null ? null : partner.getServiceShareRatio());
      BigDecimal electricityShareAmount = calculateShareAmount(channelElectricityAmount, record.getElectricityShareRatio());
      BigDecimal serviceShareAmount = calculateShareAmount(channelServiceAmount, record.getServiceShareRatio());
      record.setElectricityShareAmount(electricityShareAmount);
      record.setServiceShareAmount(serviceShareAmount);
      record.setShareAmount(electricityShareAmount.add(serviceShareAmount).setScale(2, RoundingMode.HALF_UP));
      record.setNeedOnlineShare("ICBC".equals(payChannel) && record.getShareAmount().compareTo(BigDecimal.ZERO) > 0);
      record.setOnlineShareStatus(Boolean.TRUE.equals(record.getNeedOnlineShare()) ? "INIT" : "RECORDED");
      if ("ICBC".equals(payChannel)) {
         record.setSeqNo(chargingOrder.getCode());
         record.setBusiType("1");
         record.setOriTrxDate(chargingOrder.getPayTime() == null ? LocalDate.now() : chargingOrder.getPayTime().toLocalDate());
         record.setSubOrderId(chargingOrder.getCode());
      }
      if ("ICBC".equals(payChannel) && partner != null) {
         record.setSubMerId(partner.getIcbcSubMerId());
         record.setSubMerPrtclNo(partner.getIcbcSubMerPrtclNo());
         record.setMerAcct(partner.getIcbcMerAcct());
      }
      record.setRetryCount(0);
      record.setDelFlag(false);
      return record;
   }
   private TChargingOrderShareRecord mergeChargingOrderShareRecord(TChargingOrderShareRecord exist, TChargingOrderShareRecord fresh) {
      if (exist == null) {
         return fresh;
      }
      fresh.setId(exist.getId());
      fresh.setRetryCount(exist.getRetryCount() == null ? 0 : exist.getRetryCount());
      fresh.setRequestJson(exist.getRequestJson());
      fresh.setResponseJson(exist.getResponseJson());
      fresh.setIcbcOrderId(exist.getIcbcOrderId());
      fresh.setSubOrderSeq(exist.getSubOrderSeq());
      fresh.setSubOrderTrxid(exist.getSubOrderTrxid());
      fresh.setRecResult(exist.getRecResult());
      fresh.setLastRetryTime(exist.getLastRetryTime());
      return fresh;
   }
   private BigDecimal getActualThirdPayAmount(TChargingOrder chargingOrder) {
      return getRefundableThirdPayAmount(chargingOrder).subtract(money(chargingOrder.getThirdRefundAmount())).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
   }
   private BigDecimal getActualBalancePayAmount(TChargingOrder chargingOrder) {
      return money(chargingOrder.getBalancePayAmount()).subtract(money(chargingOrder.getBalanceRefundAmount())).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
   }
   private BalanceShareAmount getBalanceShareAmount(TChargingOrder chargingOrder) {
      if (chargingOrder == null || chargingOrder.getId() == null) {
         return new BalanceShareAmount(BigDecimal.ZERO, BigDecimal.ZERO);
      }
      BigDecimal fallbackBalancePay = getActualBalancePayAmount(chargingOrder);
      if (fallbackBalancePay.compareTo(BigDecimal.ZERO) <= 0) {
         return new BalanceShareAmount(BigDecimal.ZERO, BigDecimal.ZERO);
      }
      List<Map<String, Object>> rows = this.baseMapper.exchangeCodeBalanceIncomeByOrderIds(Collections.singletonList(chargingOrder.getId()));
      if (rows == null || rows.isEmpty()) {
         return new BalanceShareAmount(fallbackBalancePay, BigDecimal.ZERO);
      }
      Map<String, Object> row = rows.get(0);
      BigDecimal principalAmount = getSummaryDecimal(row, "balanceIncome").max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
      BigDecimal giftAmount = getSummaryDecimal(row, "balanceGiftIncome").max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
      return new BalanceShareAmount(principalAmount, giftAmount);
   }
   private BigDecimal getChargingOrderShareElectricityAmount(TChargingOrder chargingOrder) {
      if (chargingOrder == null) {
         return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
      }
      return money(chargingOrder.getElectrovalence()).add(money(chargingOrder.getWhitelistElectricRefundAmount())).setScale(2, RoundingMode.HALF_UP);
   }
   private BigDecimal getChargingOrderShareServiceAmount(TChargingOrder chargingOrder) {
      if (chargingOrder == null) {
         return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
      }
      return money(chargingOrder.getServiceCharge()).add(money(chargingOrder.getWhitelistServiceRefundAmount())).setScale(2, RoundingMode.HALF_UP);
   }
   private BigDecimal getChargingOrderShareBaseAmount(TChargingOrder chargingOrder) {
      return getChargingOrderShareElectricityAmount(chargingOrder).add(getChargingOrderShareServiceAmount(chargingOrder)).setScale(2, RoundingMode.HALF_UP);
   }
   private String resolveThirdPayChannel(TChargingOrder chargingOrder) {
      if ("ICBC".equals(chargingOrder.getSourceName())) {
         return "ICBC";
      }
      if (Integer.valueOf(1).equals(chargingOrder.getRechargePaymentType())) {
         return "WECHAT";
      }
      if (Integer.valueOf(2).equals(chargingOrder.getRechargePaymentType()) || Integer.valueOf(3).equals(chargingOrder.getRechargePaymentType())) {
         return "ALIPAY";
      }
      return "OTHER";
   }
   private void processIcbcOnlineShare(TChargingOrderShareRecord record, Partner partner) {
      try {
         String invalidReason = validateIcbcShareRecord(record, partner);
         if (StringUtils.hasLength(invalidReason)) {
            markChargingOrderShare(record, "FAIL", invalidReason);
            return;
         }
         IcbcSubOrderSplitReq req = buildIcbcSubOrderSplitReq(record);
         record.setRequestJson(JSON.toJSONString(req));
         record.setOnlineShareStatus("PROCESSING");
         record.setRetryCount(record.getRetryCount() == null ? 1 : record.getRetryCount() + 1);
         record.setLastRetryTime(LocalDateTime.now());
         saveOrUpdateChargingOrderShareRecord(record);
         R<IcbcSubOrderSplitResp> result = icbcPaymentClient.splitSubOrder(req);
         IcbcSubOrderSplitResp resp = result == null ? null : result.getData();
         record.setResponseJson(resp == null ? (result == null ? null : JSON.toJSONString(result)) : resp.getRawResponse());
         if (result == null || result.getCode() != 200 || resp == null) {
            markChargingOrderShare(record, "FAIL", result == null ? "工行拆分接口无响应" : result.getMsg());
            return;
         }
         record.setIcbcOrderId(resp.getOrderId());
         record.setSubOrderSeq(resp.getSubOrderSeq());
         record.setSubOrderTrxid(resp.getSubOrderTrxid());
         record.setRecResult(resp.getRecResult());
         if ("SUCCESS".equals(resp.getStatus()) && ("0".equals(resp.getRecResult()) || !StringUtils.hasLength(resp.getRecResult()))) {
            markChargingOrderShare(record, "SUCCESS", null);
         } else {
            markChargingOrderShare(record, "FAIL", "工行拆分未成功:" + firstNotBlank(resp.getRecResult(), resp.getStatus()));
         }
      } catch (Exception e) {
         log.error("工行线上分账处理失败,订单号:{},渠道:{}", record == null ? null : record.getChargingOrderCode(), record == null ? null : record.getPayChannel(), e);
         if (record != null) {
            markChargingOrderShare(record, "FAIL", firstNotBlank(e.getMessage(), "工行线上分账处理异常"));
         }
      }
   }
   private void recordChargingOrderShareFailure(TChargingOrder chargingOrder, Site site, Exception e) {
      try {
         if (chargingOrder == null || !"ICBC".equals(chargingOrder.getSourceName()) || getActualThirdPayAmount(chargingOrder).compareTo(BigDecimal.ZERO) <= 0) {
            return;
         }
         TChargingOrderShareRecord record = chargingOrderShareRecordMapper.selectOne(new LambdaQueryWrapper<TChargingOrderShareRecord>()
               .eq(TChargingOrderShareRecord::getChargingOrderCode, chargingOrder.getCode())
               .eq(TChargingOrderShareRecord::getPayChannel, "ICBC")
               .eq(TChargingOrderShareRecord::getDelFlag, false)
               .last("limit 1"));
         if (record == null) {
            BigDecimal actualThirdPay = getActualThirdPayAmount(chargingOrder);
            BigDecimal actualTotalPay = actualThirdPay.add(getBalanceShareAmount(chargingOrder).getPrincipalAmount()).setScale(2, RoundingMode.HALF_UP);
            BigDecimal shareElectricityAmount = getChargingOrderShareElectricityAmount(chargingOrder);
            BigDecimal shareServiceAmount = getChargingOrderShareServiceAmount(chargingOrder);
            record = buildChargingOrderShareRecord(chargingOrder, site, null, "ICBC", actualThirdPay, BigDecimal.ZERO,
                  actualTotalPay.compareTo(BigDecimal.ZERO) > 0 ? actualTotalPay : actualThirdPay, shareElectricityAmount, shareServiceAmount);
         }
         record.setNeedOnlineShare(true);
         markChargingOrderShare(record, "FAIL", firstNotBlank(e.getMessage(), "充电订单分账记录触发异常"));
      } catch (Exception ex) {
         log.error("充电订单分账失败补偿记录落库失败,订单号:{}", chargingOrder == null ? null : chargingOrder.getCode(), ex);
      }
   }
   private String validateIcbcShareRecord(TChargingOrderShareRecord record, Partner partner) {
      if (partner == null) {
         return "站点未配置合作商,无法工行拆分";
      }
      if (partner.getElectricityShareRatio() == null && partner.getServiceShareRatio() == null) {
         return "合作商未配置分成比例,跳过工行拆分";
      }
      if (!StringUtils.hasLength(partner.getIcbcSubMerId())) {
         return "合作商未配置工行二级商户编号";
      }
      if (!StringUtils.hasLength(partner.getIcbcSubMerPrtclNo())) {
         return "合作商未配置工行二级商户协议编号";
      }
      if (money(record.getShareAmount()).compareTo(BigDecimal.ZERO) <= 0) {
         return "工行拆分金额为0";
      }
      return null;
   }
   private BigDecimal calculateShareAmount(BigDecimal amount, BigDecimal ratio) {
      if (amount == null || ratio == null) {
         return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
      }
      return amount.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
   }
   private IcbcSubOrderSplitReq buildIcbcSubOrderSplitReq(TChargingOrderShareRecord record) {
      IcbcSubOrderSplitReq req = new IcbcSubOrderSplitReq();
      req.setChargingOrderCode(record.getChargingOrderCode());
      req.setSeqNo(record.getSeqNo());
      req.setBusiType(record.getBusiType());
      req.setOriMerId(record.getOriMerId());
      req.setOriTrxDate(record.getOriTrxDate() == null ? null : record.getOriTrxDate().toString());
      req.setSubOrderId(record.getSubOrderId());
      req.setSubMerId(record.getSubMerId());
      req.setSubMerPrtclNo(record.getSubMerPrtclNo());
      req.setClassifyAmt(record.getShareAmount());
      req.setMerAcct(record.getMerAcct());
      req.setMerSpInfor("充电订单分账:" + record.getChargingOrderCode());
      return req;
   }
   private void markChargingOrderShare(TChargingOrderShareRecord record, String status, String reason) {
      record.setOnlineShareStatus(status);
      record.setFailReason(reason);
      saveOrUpdateChargingOrderShareRecord(record);
   }
   private void saveOrUpdateChargingOrderShareRecord(TChargingOrderShareRecord record) {
      if (record.getId() == null) {
         chargingOrderShareRecordMapper.insert(record);
      } else {
         chargingOrderShareRecordMapper.updateById(record);
      }
   }
   private String buildIcbcProfitSharing(Site site) {
      if (site == null || site.getPartnerId() == null) {
         return null;
      }
      R<Partner> partnerResult = partnerClient.getPartnerById(site.getPartnerId());
      Partner partner = partnerResult == null ? null : partnerResult.getData();
      if (partner == null || !StringUtils.hasLength(partner.getIcbcSubMerId()) || !StringUtils.hasLength(partner.getIcbcSubMerPrtclNo())) {
         return null;
      }
      if (partner.getElectricityShareRatio() == null && partner.getServiceShareRatio() == null) {
         return null;
      }
      JSONObject data = new JSONObject();
      data.put("icbcPartnerId", partner.getIcbcPartnerId());
      data.put("icbcSubMerId", partner.getIcbcSubMerId());
      data.put("icbcSubMerPrtclNo", partner.getIcbcSubMerPrtclNo());
      data.put("icbcMerAcct", partner.getIcbcMerAcct());
      if (partner.getElectricityShareRatio() != null) {
         data.put("electricityShareRatio", partner.getElectricityShareRatio());
      }
      if (partner.getServiceShareRatio() != null) {
         data.put("serviceShareRatio", partner.getServiceShareRatio());
      }
      return data.toJSONString();
   }
   private static class BalanceShareAmount {
      private final BigDecimal principalAmount;
      private final BigDecimal giftAmount;
      private BalanceShareAmount(BigDecimal principalAmount, BigDecimal giftAmount) {
         this.principalAmount = principalAmount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : principalAmount.setScale(2, RoundingMode.HALF_UP);
         this.giftAmount = giftAmount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : giftAmount.setScale(2, RoundingMode.HALF_UP);
      }
      private BigDecimal getPrincipalAmount() {
         return principalAmount;
      }
      private BigDecimal getGiftAmount() {
         return giftAmount;
      }
   }
   private String firstNotBlank(String... values) {
      for (String value : values) {
         if (StringUtils.hasLength(value)) {
            return value;
         }
      }
      return "";
   }
}