longz
2026-05-30 73df73c66bc540fbeb1c47d14debcd38649a2c25
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -50,6 +50,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;
@@ -70,6 +71,7 @@
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.*;
@@ -149,6 +151,10 @@
   private AliPaymentClient aliPaymentClient;
   @Resource
   private H5AliPaymentClient h5AliPaymentClient;
   @Resource
   private IcbcPaymentClient icbcPaymentClient;
   @Resource
   private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper;
   
   @Resource
   private AppCouponClient appCouponClient;
@@ -552,7 +558,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());
   }
    /**
     * 判断订单是否为白名单订单
@@ -641,7 +678,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();
@@ -651,7 +694,7 @@
               }
            }
         }
         if (2 == rechargePaymentType) {
         if (!"ICBC".equals(tChargingOrder.getSourceName()) && 2 == rechargePaymentType) {
            AliQueryOrder data = aliPaymentClient.query(tChargingOrder.getCode()).getData();
            if (null != data) {
               //支付失败,删除无效的订单
@@ -661,7 +704,7 @@
               }
            }
         }
         if (3 == rechargePaymentType) {
         if (!"ICBC".equals(tChargingOrder.getSourceName()) && 3 == rechargePaymentType) {
            AliQueryOrder data = h5AliPaymentClient.query(tChargingOrder.getCode()).getData();
            if (null != data) {
               //支付失败,删除无效的订单
@@ -684,7 +727,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();
@@ -698,7 +749,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();
@@ -713,7 +764,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();
@@ -766,6 +817,9 @@
      chargingOrder.setWhitelistServiceRefundAmount(BigDecimal.ZERO);
      chargingOrder.setVipDiscountAmount(BigDecimal.ZERO);
      chargingOrder.setOrderSource(1);
      if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0) {
         chargingOrder.setSourceName("ICBC");
      }
      chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪");
      
      Site site = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData().get(0);
@@ -826,44 +880,21 @@
      }
      //会员优惠折扣将其计入增加充电时长(增加总充电金额)
      //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额)
      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();
      IcbcPaymentReq req = new IcbcPaymentReq();
      req.setOutTradeNo(chargingOrder.getCode());
      req.setAmount(thirdPayAmount);
      req.setSubject("充电充值");
      req.setBody("充电充值");
      req.setPaymentType(addChargingOrder.getPaymentType());
      req.setNotifyUrl("/payment/icbc/callBack");
      req.setReturnUrl(addChargingOrder.getReturnUrl());
      req.setOpenId(Integer.valueOf(1).equals(addChargingOrder.getPaymentType()) ? appUser.getWxOpenid() : appUser.getAliOpenid());
      req.setProfitSharing(buildIcbcProfitSharing(site));
      IcbcPaymentResp data = icbcPaymentClient.payment(req).getData();
      if (isIcbcPaymentCreated(data)) {
         return AjaxResult.success(data);
      }
      if (2 == addChargingOrder.getPaymentType()) {
         AliPaymentReq req = new AliPaymentReq();
         req.setOutTradeNo(chargingOrder.getCode());
         req.setTotalAmount(thirdPayAmount.toString());
         req.setSubject("充电充值");
         req.setBuyerOpenId(appUser.getAliOpenid());
         req.setBody("充电充值");
         req.setNotifyUrl("/payment/ali/callBack");
         AliPaymentResp data = aliPaymentClient.payment(req).getData();
         if (null != data) {
            return AjaxResult.success(data);
         }
      }
      if (3 == addChargingOrder.getPaymentType()) {
         AliPaymentReq req = new AliPaymentReq();
         req.setOutTradeNo(chargingOrder.getCode());
         req.setTotalAmount(thirdPayAmount.toString());
         req.setSubject("充电充值");
         req.setBuyerOpenId(appUser.getAliOpenid());
         req.setBody("充电充值");
         req.setNotifyUrl("/payment/aliH5/callBack");
         req.setReturnUrl(addChargingOrder.getReturnUrl());
         String data = h5AliPaymentClient.payment(req).getData();
         if (StringUtils.hasLength(data)) {
            return AjaxResult.success("操作成功", data);
         }
      }
      throw new RuntimeException("无效的支付方式");
      throw new RuntimeException("调起工行支付失败");
   }
   
   
@@ -1337,6 +1368,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());
@@ -1488,6 +1524,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());
@@ -1592,6 +1633,7 @@
                chargingOrder.setRefundSerialNumber(refund_id);
                chargingOrder.setRefundTime(LocalDateTime.now());
                this.updateById(chargingOrder);
                triggerChargingOrderShare(this.getById(order.getId()));
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
@@ -3487,6 +3529,10 @@
                            chargingOrder.setRefundStatus(2);
                            chargingOrder.setRefundTime(LocalDateTime.now());
                            this.updateById(chargingOrder);
                            triggerChargingOrderShare(chargingOrder);
                        } else if (isIcbcOrder(chargingOrder)) {
                            refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount, "充电完成退款", false,
                                    refundAmount, balanceRefundAmount);
                        } else if (1 == rechargePaymentType) {
                            WxPaymentRefundModel model = new WxPaymentRefundModel();
                            model.setOut_trade_no(chargingOrder.getCode());
@@ -3556,6 +3602,7 @@
                        chargingOrder.setRefundStatus(2);
                        chargingOrder.setRefundTime(LocalDateTime.now());
                        this.updateById(chargingOrder);
                        triggerChargingOrderShare(chargingOrder);
                    } else {
                        //构建退款明细
                        TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
@@ -3584,6 +3631,7 @@
                        chargingOrder.setRefundStatus(2);
                        chargingOrder.setRefundTime(LocalDateTime.now());
                        this.updateById(chargingOrder);
                        triggerChargingOrderShare(chargingOrder);
                    }
                }
@@ -3616,6 +3664,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();
@@ -3767,6 +3818,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();
@@ -5904,4 +5959,406 @@
            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;
      }
      return "SUCCESS".equals(resp.getStatus());
   }
   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("ICBCS" + 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 "";
   }
}