puzhibing
2026-09-29 a70433b2ee5bb37823ab73422a01251343cb5f58
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/task/TaskUtil.java
@@ -1,46 +1,82 @@
package com.ruoyi.order.util.task;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.util.UUIDUtils;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.ruoyi.account.api.feignClient.AppCouponClient;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.account.api.feignClient.AppUserIntegralChangeClient;
import com.ruoyi.account.api.model.TAppCoupon;
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.account.api.model.TAppUserIntegralChange;
import com.ruoyi.chargingPile.api.dto.TBillingTemplateDTO;
import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient;
import com.ruoyi.chargingPile.api.feignClient.SiteClient;
import com.ruoyi.chargingPile.api.model.Partner;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TBillingTemplateDetail;
import com.ruoyi.chargingPile.api.model.TChargingGun;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.integration.api.feignClient.ChargingMessageClient;
import com.ruoyi.integration.api.feignClient.UploadRealTimeMonitoringDataClient;
import com.ruoyi.integration.api.feignClient.ChengDuJianGuanClient;
import com.ruoyi.integration.api.feignClient.TCECClient;
import com.ruoyi.integration.api.model.TransactionRecord;
import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData;
import com.ruoyi.integration.api.vo.ChargingOrderVo;
import com.ruoyi.order.api.model.TChargingBill;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.api.model.TChargingOrderRefund;
import com.ruoyi.integration.api.vo.NotificationConnectorChargeStatusVo;
import com.ruoyi.order.api.model.*;
import com.ruoyi.order.api.vo.TransactionRecordMessageVO;
import com.ruoyi.order.service.TChargingBillService;
import com.ruoyi.order.service.TChargingOrderRefundService;
import com.ruoyi.order.service.TChargingOrderService;
import com.ruoyi.order.service.*;
import com.ruoyi.order.service.impl.ChargingCouponSupport;
import com.ruoyi.order.support.ChargeAccountSupport;
import com.ruoyi.order.util.mongodb.service.TransactionRecordService;
import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService;
import com.ruoyi.other.api.domain.TCoupon;
import com.ruoyi.other.api.domain.TIntegralRule;
import com.ruoyi.other.api.domain.TVip;
import com.ruoyi.other.api.dto.CompanyPreferentialDTO;
import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
import com.ruoyi.other.api.feignClient.IntegralRuleClient;
import com.ruoyi.other.api.feignClient.OtherClient;
import com.ruoyi.other.api.feignClient.VipClient;
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.RefundReq;
import com.ruoyi.payment.api.model.RefundResp;
import com.ruoyi.payment.api.model.WxPaymentRefundModel;
import com.ruoyi.payment.api.vo.IcbcRefundReq;
import com.ruoyi.payment.api.vo.IcbcRefundResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.core.util.UuidUtil;
import org.apache.poi.util.StringUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -50,13 +86,26 @@
@Slf4j
@Component
public class TaskUtil implements ApplicationListener<WebServerInitializedEvent> {
    private static final int WHITELIST_BENEFIT_ALL_FREE = 1;
    @Resource
    private TChargingBillService chargingBillService;
    @Resource
    private ITChargingSettlementBillService chargingSettlementBillService;
    @Resource
    private ITAccountSettlementStatementService accountSettlementStatementService;
    @Resource
    private SiteClient siteClient;
    @Resource
    private TChargingOrderService chargingOrderService;
    @Resource
    private TCardChargingOrderService cardChargingOrderService;
    @Resource
    private TVinChargingOrderService vinChargingOrderService;
    
    @Resource
    private TChargingOrderRefundService chargingOrderRefundService;
@@ -71,202 +120,1423 @@
    private ChargingMessageClient chargingMessageClient;
    
    private Integer port = null;
    @Resource
    private AccountingStrategyDetailOrderService accountingStrategyDetailOrderService;
    @Resource
    private TChargingOrderAccountingStrategyService chargingOrderAccountingStrategyService;
    @Resource
    private AppCouponClient appCouponClient;
    @Resource
    private TCECClient tcecClient;
    @Resource
    private VipClient vipClient;
    @Resource
    private ChargingGunClient chargingGunClient;
    @Resource
    private IntegralRuleClient integralRuleClient;
    @Resource
    private AppUserClient appUserClient;
    @Resource
    private AppUserIntegralChangeClient appUserIntegralChangeClient;
    @Resource
    private OtherClient otherClient;
    @Resource
    private WxPaymentClient wxPaymentClient;
    @Resource
    private IcbcPaymentClient icbcPaymentClient;
    @Resource
    private AliPaymentClient aliPaymentClient;
    @Resource
    private H5AliPaymentClient h5AliPaymentClient;
    @Resource
    private ITChargingOrderSummaryDataService chargingOrderSummaryDataService;
    @Resource
    private ChengDuJianGuanClient chengDuJianGuanClient;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ChargeAccountSupport chargeAccountSupport;
    /**
     * 判断订单是否使用余额或余额组合支付
     *
     * @param payMethod 支付方式
     * @return true=余额相关支付方式
     */
    private boolean isBalancePayMode(Integer payMethod) {
        return payMethod != null && (payMethod == 1 || payMethod == 2);
    }
    /**
     * 将金额空值统一转换为两位小数,避免补偿结算金额计算出现空指针
     *
     * @param amount 原始金额
     * @return 非空两位小数金额
     */
    private BigDecimal money(BigDecimal amount) {
        return amount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : amount.setScale(2, RoundingMode.HALF_UP);
    }
    /**
     * 获取第三方实付金额,兼容早期未写入third_pay_amount的纯第三方支付订单。
     *
     * @param order 充电订单
     * @return 第三方可退款本金
     */
    private BigDecimal getRefundableThirdPayAmount(TChargingOrder order) {
        if (order == null || isWhitelistAllFreeOrder(order)) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        BigDecimal thirdPayAmount = money(order.getThirdPayAmount());
        if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0) {
            return thirdPayAmount;
        }
        if ("ICBC".equalsIgnoreCase(order.getSourceName())) {
            return money(order.getRechargeAmount())
                    .subtract(money(order.getBalancePayAmount()))
                    .max(BigDecimal.ZERO)
                    .setScale(2, RoundingMode.HALF_UP);
        }
        if (Integer.valueOf(3).equals(order.getPayMethod())) {
            return money(order.getRechargeAmount());
        }
        return thirdPayAmount;
    }
    /**
     * 判断订单是否为白名单订单
     *
     * @param order 充电订单
     * @return true=白名单订单
     */
    private boolean isWhitelistOrder(TChargingOrder order) {
        return order != null && Integer.valueOf(1).equals(order.getIsWhitelist());
    }
    /**
     * 判断订单是否为白名单全部免费权益
     *
     * @param order 充电订单
     * @return true=全部免费白名单订单
     */
    private boolean isWhitelistAllFreeOrder(TChargingOrder order) {
        return isWhitelistOrder(order)
                && Integer.valueOf(WHITELIST_BENEFIT_ALL_FREE).equals(order.getWhitelistBenefitType());
    }
    /**
     * 按白名单权益拆分补偿结算的电费和服务费减免金额,确保任务补偿与正常结算口径一致
     *
     * @param order 充电订单
     * @param electrovalence 原始电费
     * @param serviceCharge 原始服务费
     * @return 数组下标0=电费减免,下标1=服务费减免
     */
    private BigDecimal[] calculateWhitelistRefundSplit(TChargingOrder order, BigDecimal electrovalence, BigDecimal serviceCharge) {
        return ChargingCouponSupport.calculateWhitelistRefundSplitByBenefitType(
                isWhitelistOrder(order),
                order == null ? null : order.getWhitelistBenefitType(),
                electrovalence,
                serviceCharge);
    }
    /**
     * 记录兑换码余额退款流水
     *
     * @param order 充电订单
     * @param refundAmount 退款金额
     * @param refundNo 退款单号
     */
    private void recordBalanceRefund(TChargingOrder order, BigDecimal refundAmount, String refundNo) {
        if (order == null || order.getAppUserId() == null || order.getId() == null
                || refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        ExchangeCodeConsumeDTO refundDTO = new ExchangeCodeConsumeDTO();
        refundDTO.setUserId(order.getAppUserId());
        refundDTO.setOrderId(order.getId());
        refundDTO.setAmount(refundAmount);
        refundDTO.setRefundNo(refundNo);
        R<ExchangeCodeConsumeResultVO> result = otherClient.refundExchangeCodeBalance(refundDTO);
        if (result == null || result.getCode() != 200) {
            throw new RuntimeException("退还兑换码余额失败");
        }
    }
    @Scheduled(fixedRate = 1000 * 60)
    public void taskOneMinutes() {
        if (isScheduledTaskPort(port)) {
            List<TChargingOrder> upStatusChargingOrder = chargingOrderService.findUpStatusChargingOrder();
            log.info("定时任务执行,查询需要手动修改状态的订单数量:{}", upStatusChargingOrder.size());
            for (TChargingOrder order : upStatusChargingOrder) {
                if(2 == order.getStatus()){
                    order.setStatus(-1);
                }else{
                    order.setStatus(5);
                }
                chargingOrderService.updateById(order);
            }
        }
    }
    /** 实时监控静默阈值:超过该时间仍无交易记录时按异常断电补偿 */
    private static final long MONITORING_SILENT_MILLIS = TimeUnit.MINUTES.toMillis(10);
    /** 无任何设备数据时的最长保护时间,避免 Mongo 短暂延迟造成误关单 */
    private static final long NO_DEVICE_DATA_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(24);
    /**
     * 刷卡/VIN 订单补偿(10分钟一轮):真实交易记录优先统一结算;启动中有实时数据则恢复充电中;
     * 仅在设备数据缺失或静默达到保护阈值后执行关单/累计电量兜底结算。
     */
    @Scheduled(fixedRate = 1000 * 60 * 10, initialDelay = 1000 * 60)
    public void cardVinOrderCompensationTask() {
        if (isScheduledTaskPort(port)) {
            compensateCardOrders();
            compensateVinOrders();
        }
    }
    /**
     * VIN 结算失败重试(1分钟一轮,结算失败主触发):处理账户结算失败回退的状态4订单,
     * 与10分钟补偿任务(DB兜底扫描)互补;重试幂等由账户侧消费流水保证,不会重复扣款。
     */
    @Scheduled(fixedRate = 1000 * 60, initialDelay = 1000 * 30)
    public void vinSettleRetryTask() {
        if (isScheduledTaskPort(port)) {
            try {
                vinChargingOrderService.retryPendingVinSettle();
            } catch (Exception e) {
                log.error("[VD结算重试] 定时任务异常", e);
            }
        }
    }
    private void compensateCardOrders() {
        try {
            int recovered = cardChargingOrderService.recoverFinishedOrdersWithoutDeduct();
            if (recovered > 0) {
                log.warn("[SD扣款补偿] 本轮回退未扣款已结束订单数量:{}", recovered);
            }
        } catch (Exception e) {
            log.error("[SD扣款补偿] 已结束未扣款扫描异常", e);
        }
        try {
            for (TCardChargingOrder order : cardChargingOrderService.listTimeoutStartingOrders()) {
                compensateCardStartingOrder(order);
            }
        } catch (Exception e) {
            log.error("[SD补偿] 启动超时扫描异常", e);
        }
        try {
            for (TCardChargingOrder order : cardChargingOrderService.listTimeoutChargingOrders()) {
                compensateCardActiveOrder(order);
            }
        } catch (Exception e) {
            log.error("[SD补偿] 活动订单扫描异常", e);
        }
    }
    private void compensateCardStartingOrder(TCardChargingOrder order) {
        try {
            TransactionRecord record = findCompleteTransactionRecord(order.getCode());
            if (record != null) {
                cardChargingOrderService.cardEndChargeBillingCharge(toTransactionRecordVO(record));
                return;
            }
            UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode());
            if (latest != null && (latest.getCreate_time() == null
                    || System.currentTimeMillis() - latest.getCreate_time().getTime() <= MONITORING_SILENT_MILLIS)) {
                cardChargingOrderService.handleHandshakeVin(order.getCode(), null);
                log.info("[SD补偿] 启动应答缺失但存在活跃实时数据,恢复充电中 code={}", order.getCode());
                return;
            }
            cardChargingOrderService.closeTimeoutStartingOrder(order);
        } catch (Exception ex) {
            log.error("[SD补偿] 启动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex);
        }
    }
    private void compensateCardActiveOrder(TCardChargingOrder order) {
        try {
            TransactionRecord record = findCompleteTransactionRecord(order.getCode());
            if (record != null) {
                cardChargingOrderService.cardEndChargeBillingCharge(toTransactionRecordVO(record));
                return;
            }
            UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode());
            if (shouldFallbackSettle(latest, order.getCreateTime(), false)) {
                cardChargingOrderService.compensationSettle(order);
            }
        } catch (Exception ex) {
            log.error("[SD补偿] 活动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex);
        }
    }
    private void compensateVinOrders() {
        try {
            for (TVinChargingOrder order : vinChargingOrderService.listTimeoutStartingOrders()) {
                compensateVinStartingOrder(order);
            }
        } catch (Exception e) {
            log.error("[VD补偿] 启动超时扫描异常", e);
        }
        try {
            for (TVinChargingOrder order : vinChargingOrderService.listTimeoutChargingOrders()) {
                compensateVinActiveOrder(order);
            }
        } catch (Exception e) {
            log.error("[VD补偿] 活动订单扫描异常", e);
        }
    }
    private void compensateVinStartingOrder(TVinChargingOrder order) {
        try {
            TransactionRecord record = findCompleteTransactionRecord(order.getCode());
            if (record != null) {
                vinChargingOrderService.vinEndChargeBillingCharge(toTransactionRecordVO(record));
                return;
            }
            UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode());
            if (latest != null && (latest.getCreate_time() == null
                    || System.currentTimeMillis() - latest.getCreate_time().getTime() <= MONITORING_SILENT_MILLIS)) {
                vinChargingOrderService.handleHandshakeVin(order.getCode(), null);
                log.info("[VD补偿] 启动应答缺失但存在活跃实时数据,恢复充电中 code={}", order.getCode());
                return;
            }
            vinChargingOrderService.closeTimeoutStartingOrder(order);
        } catch (Exception ex) {
            log.error("[VD补偿] 启动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex);
        }
    }
    private void compensateVinActiveOrder(TVinChargingOrder order) {
        try {
            TransactionRecord record = findCompleteTransactionRecord(order.getCode());
            if (record != null) {
                vinChargingOrderService.vinEndChargeBillingCharge(toTransactionRecordVO(record));
                return;
            }
            UploadRealTimeMonitoringData latest = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode());
            boolean stopping = Integer.valueOf(4).equals(order.getStatus());
            if (shouldFallbackSettle(latest, order.getCreateTime(), stopping)) {
                vinChargingOrderService.compensationSettle(order);
            }
        } catch (Exception ex) {
            log.error("[VD补偿] 活动订单处理异常,保留原状态待下轮重试 code={}", order.getCode(), ex);
        }
    }
    private TransactionRecord findCompleteTransactionRecord(String code) {
        TransactionRecord record = transactionRecordService.findOne(code);
        return record != null && StringUtils.isNotEmpty(record.getResult()) ? record : null;
    }
    private TransactionRecordMessageVO toTransactionRecordVO(TransactionRecord record) {
        TransactionRecordMessageVO vo = new TransactionRecordMessageVO();
        BeanUtils.copyProperties(record, vo);
        return vo;
    }
    static boolean shouldFallbackSettle(UploadRealTimeMonitoringData latest, LocalDateTime createTime, boolean stopping) {
        if (latest != null && latest.getCreate_time() != null) {
            return stopping || System.currentTimeMillis() - latest.getCreate_time().getTime() > MONITORING_SILENT_MILLIS;
        }
        if (stopping) {
            return true;
        }
        return createTime != null
                && ChronoUnit.MILLIS.between(createTime, LocalDateTime.now()) > NO_DEVICE_DATA_TIMEOUT_MILLIS;
    }
    //十分钟循环执行的定时任务
    @Scheduled(fixedRate = 1000 * 60 * 10)
    public void taskTenMinutes() {
        if(null != port && port == 5400){
        if (isScheduledTaskPort(port)) {
            List<TChargingOrder> failedStartupOrder = chargingOrderService.findFailedStartupOrder();
            log.info("定时任务执行,查询到启动失败的订单数量:{}", failedStartupOrder.size());
            for (TChargingOrder order : failedStartupOrder) {
                log.info("定时任务执行,查询到启动失败的订单:{}", order.getCode());
                //查询是否有充电信息
                List<UploadRealTimeMonitoringData> dataByOrderCode = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
                log.info("充电实时数据:{}", JSON.toJSONString(dataByOrderCode));
                log.info("充电实时数据:{}", dataByOrderCode.size());
                //没有充电数据,则执行退款
                if(null == dataByOrderCode || dataByOrderCode.isEmpty()){
                    log.info("定时任务执行,查询到启动失败的订单,执行退款:{}", order.getCode());
                    chargingOrderService.refund(order.getCode());
                    int num = 0;
                    while (true){
                        TChargingOrderRefund one = chargingOrderRefundService.getOne(new LambdaQueryWrapper<TChargingOrderRefund>().eq(TChargingOrderRefund::getChargingOrderId, order.getId()));
                        if(null != one && 2 == one.getRefundStatus()){
                            order.setStatus(-1);
                            chargingOrderService.updateById(order);
                            break;
                    if(1 == order.getOrderSource()){
                        chargingOrderService.refund(order.getCode());
                        int num = 0;
                        while (true){
                            TChargingOrderRefund one = chargingOrderRefundService.getOne(new LambdaQueryWrapper<TChargingOrderRefund>().eq(TChargingOrderRefund::getChargingOrderId, order.getId()));
                            if(null != one && 2 == one.getRefundStatus()){
                                order.setStatus(-1);
                                chargingOrderService.updateById(order);
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            num++;
                            if(num > 30){
                                break;
                            }
                        }
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        num++;
                        if(num > 10){
                            break;
                        }
                    }else{
                        order.setStatus(-1);
                        chargingOrderService.updateById(order);
                    }
                }
            }
            //处理退款中的数据
            List<TChargingOrder> stoppedOrder = chargingOrderService.findStoppedOrder();
            log.info("定时任务执行,查询到停止中的订单数量:{}", stoppedOrder.size());
            for (TChargingOrder order : stoppedOrder) {
                log.info("定时任务执行,查询到停止中的订单:{}", order.getCode());
                TransactionRecord one = transactionRecordService.findOne(order.getCode());
                if(null != one){
                    log.info("定时任务执行,查询到停止中的订单账单数据:{}", JSON.toJSONString(one));
                    if(null == order.getStartTime()){
                        List<UploadRealTimeMonitoringData> dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        if(dataList.isEmpty()){
                            order.setStartTime(LocalDateTime.parse(one.getStart_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault())));
                        }else{
                            order.setStartTime(LocalDateTime.parse(sdf.format(dataList.get(dataList.size() - 1).getCreate_time()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())));
                        }
                    }
                    if(null == order.getEndTime()){
                        order.setEndTime(LocalDateTime.parse(one.getEnd_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault())));
                    }
                    chargingOrderService.updateById(order);
                    TransactionRecordMessageVO vo = new TransactionRecordMessageVO();
                    BeanUtils.copyProperties(one, vo);
                    R r = chargingOrderService.endChargeBillingCharge(vo);
                    log.info("定时任务执行,停止中的订单处理结果:{}", JSON.toJSONString(r));
                }else{
                    endOrder(order);
                }
            }
            //处理状态为充电中,但硬件已完成的订单
            List<TChargingOrder> chargingOrder = chargingOrderService.findChargingOrder();
            log.info("定时任务执行,查询到充电中的订单数量:{}", chargingOrder.size());
            for (TChargingOrder order : chargingOrder) {
                log.info("定时任务执行,查询到充电中的订单:{}", order.getCode());
                TransactionRecord one = transactionRecordService.findOne(order.getCode());
                if(null != one && StringUtils.isNotEmpty(one.getResult())){
                    log.info("定时任务执行,查询到充电中的订单账单数据:{}", JSON.toJSONString(one));
                    if(null == order.getStartTime()){
                        List<UploadRealTimeMonitoringData> dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        if(dataList.isEmpty()){
                            order.setStartTime(LocalDateTime.parse(one.getStart_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault())));
                        }else{
                            order.setStartTime(LocalDateTime.parse(sdf.format(dataList.get(dataList.size() - 1).getCreate_time()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())));
                        }
                    }
                    if(null == order.getEndTime()){
                        order.setEndTime(LocalDateTime.parse(one.getEnd_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS").withZone(ZoneId.systemDefault())));
                    }
                    chargingOrderService.updateById(order);
                    TransactionRecordMessageVO vo = new TransactionRecordMessageVO();
                    BeanUtils.copyProperties(one, vo);
                    R r = chargingOrderService.endChargeBillingCharge(vo);
                    log.info("定时任务执行,充电中的订单处理结果:{}", JSON.toJSONString(r));
                }else{
                    //判断充电流水超过10分钟没有更新,则判定为充电结束
                    List<UploadRealTimeMonitoringData> dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
                    if(!dataList.isEmpty()){
                        UploadRealTimeMonitoringData uploadRealTimeMonitoringData = dataList.get(0);
                        Date createTime = uploadRealTimeMonitoringData.getCreate_time();
                        if(System.currentTimeMillis() - createTime.getTime() - (8 * 60 * 60 * 1000) > 1000 * 60 * 10){
                            endOrder(order);
                        }
                    }
                }
                //推送监管平台订单状态和订单详情
                ChargingOrderVo chargingOrderVo = new ChargingOrderVo();
                BeanUtils.copyProperties(order, chargingOrderVo);
                chargingMessageClient.pushOrderInfo(chargingOrderVo);
                chargingMessageClient.pushOrderStatus(chargingOrderVo);
            }
            //处理还未退款,但是订单状态已结束的数据
            List<TChargingOrder> endChargingOrder = chargingOrderService.findEndChargingOrder();
            log.info("定时任务执行,查询到已结束未退款的订单数量:{}", endChargingOrder.size());
            for (TChargingOrder order : endChargingOrder) {
                if(-1 == order.getStatus()){
                    order.setStatus(2);
                }
                if(5 == order.getStatus()){
                    order.setStatus(4);
                }
                chargingOrderService.updateById(order);
            }
        }
    }
    @Scheduled(cron = "0 0 0 2 * ?")
    //定时任务添加结算账单汇总数据
    @Scheduled(cron = "0 30 0 * * ?")
    public void taskMonth() {
        if(null != port && port == 5400){
            try {
                // 获取上个月的开始和结束日期
                LocalDate firstDayOfLastMonth = LocalDate.now().minusMonths(1).
                        withDayOfMonth(2);
                String string = firstDayOfLastMonth.toString();
                // 将-替换为空字符串
                string = string.replace("-", "");
                // 生成一次全站订单
                TChargingBill tChargingBill = new TChargingBill();
                // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置)
                Random random = new Random();
                String randomDigits = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining()); // 将其连接成一个字符串
                tChargingBill.setCode("JSD"+string+randomDigits );
                tChargingBill.setType(1);
                tChargingBill.setSiteId(0);
                tChargingBill.setBillTime(LocalDateTime.now());
                tChargingBill.setStatus(1);
                tChargingBill.setOrderState(2);
                tChargingBill.setBillType(1);
                System.err.println("定时任务生成充电算帐单:全站");
                chargingBillService.save(tChargingBill);
                // 生成一次全站订单
                TChargingBill tChargingBill1 = new TChargingBill();
                // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置)
                Random random1 = new Random();
                String randomDigits1 = random1.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining()); // 将其连接成一个字符串
                tChargingBill1.setCode("JSD"+string+randomDigits1 );
                tChargingBill1.setType(1);
                tChargingBill1.setSiteId(0);
                tChargingBill1.setBillTime(LocalDateTime.now());
                tChargingBill1.setStatus(1);
                tChargingBill1.setOrderState(2);
                tChargingBill1.setBillType(2);
                System.err.println("定时任务生成账户结算帐单:全站");
                chargingBillService.save(tChargingBill1);
                System.err.println("定时任务生成各个站点结算帐单");
                List<Integer> collect = siteClient.getSiteAll().getData().stream().map(Site::getId).collect(Collectors.toList());
                // 充电算帐单
                List<TChargingBill> tChargingBills = new ArrayList<>();
                // 账户结算账单
                List<TChargingBill> tChargingBills1 = new ArrayList<>();
                for (int i = 0; i < collect.size(); i++) {
                    TChargingBill tChargingBill2 = new TChargingBill();
                    Random random2 = new Random();
                    String randomDigits2 = random2.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                            .mapToObj(String::valueOf)
                            .collect(Collectors.joining()); // 将其连接成一个字符串
                    tChargingBill2.setCode("JSD"+string+randomDigits2+(i+1) );
                    tChargingBill2.setType(2);
                    List<TChargingOrder> list = chargingOrderService.lambdaQuery()
                            .eq(TChargingOrder::getSiteId, collect.get(i)).list();
                    if (list.isEmpty()){
                        continue;
                    }
                    tChargingBill2.setSiteId(collect.get(i));
                    tChargingBill2.setBillTime(LocalDateTime.now());
                    tChargingBill2.setBillType(1);
                    tChargingBill2.setStatus(1);
                    tChargingBill2.setOrderState(2);
                    tChargingBills.add(tChargingBill2);
                    TChargingBill tChargingBill3 = new TChargingBill();
                    Random random3 = new Random();
                    String randomDigits3 = random3.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                            .mapToObj(String::valueOf)
                            .collect(Collectors.joining()); // 将其连接成一个字符串
                    tChargingBill3.setCode("JSD"+string+randomDigits3+(i+1) );
                    tChargingBill3.setType(2);
                    tChargingBill3.setSiteId(collect.get(i));
                    tChargingBill3.setBillTime(LocalDateTime.now());
                    tChargingBill3.setBillType(2);
                    tChargingBill3.setStatus(1);
                    tChargingBill3.setOrderState(2);
                    tChargingBills1.add(tChargingBill3);
                }
                System.err.println("列表"+tChargingBills);
                if (!tChargingBills.isEmpty())chargingBillService.saveBatch(tChargingBills);
                if (!tChargingBills1.isEmpty())chargingBillService.saveBatch(tChargingBills1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        if (isScheduledTaskPort(port)) {
            //推送三方引流平台数据
            pushOrderDrainagePlatform();
            //添加充电算账单汇总数据
            addChargingSettlementBill();
            //添加账户结算账单数据
            addAccountSettlementStatement();
        }
    }
    // 每个月最后一天23点执行的定时任务
    @Scheduled(cron = "0 0 23 * * ?")
    public void taskLastDay() {
        if(null != port && port == 5400){
        if (isScheduledTaskPort(port)) {
            try {
                // 获取上个月的开始和结束日期
                LocalDate firstDayOfLastMonth = LocalDate.now().minusMonths(1).
                        withDayOfMonth(1);
                LocalDate lastDayOfLastMonth = LocalDate.now().minusMonths(1).
                        withDayOfMonth(firstDayOfLastMonth.lengthOfMonth());
                // 将 LocalDate 转换为 LocalDateTime,并设定时间为一天的开始
                LocalDateTime startDateTime = firstDayOfLastMonth.atStartOfDay();
                LocalDateTime endDateTime = lastDayOfLastMonth.atTime(23, 59, 59); // 设定到最后一秒
                // 构建查询条件
                LambdaQueryWrapper<TChargingBill> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.ge(TChargingBill::getBillTime,
                                Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant()))
                        .le(TChargingBill::getBillTime,
                                Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant())); // 使用 le 包括最后一天的记录
                List<TChargingBill> list = chargingBillService.list(queryWrapper);
                for (TChargingBill tChargingBill : list) {
                    tChargingBill.setStatus(2);
                int dayOfMonth = LocalDate.now().getDayOfMonth();
                int lastDayOfMonth = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
                //当月最后一天
                if(dayOfMonth == lastDayOfMonth){
                    //修改充电结算账单为已出账
                    chargingSettlementBillService.update(new UpdateWrapper<TChargingSettlementBill>().set("status", 2).set("create_time", LocalDateTime.now()).eq("status", 1));
                    //修改账户结算账单为已出账
                    accountSettlementStatementService.update(new UpdateWrapper<TAccountSettlementStatement>().set("status", 2).set("create_time", LocalDateTime.now()).eq("status", 1));
                }
                chargingBillService.updateBatchById(list);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        port = event.getWebServer().getPort();
        System.out.println("端口号:" + port);
    }
    static boolean isScheduledTaskPort(Integer serverPort) {
        return Integer.valueOf(5400).equals(serverPort) || Integer.valueOf(9400).equals(serverPort);
    }
    @Transactional
    public void endOrder(TChargingOrder order){
        RLock lock = redissonClient.getLock("endOrder:" + order.getCode());
        try {
            boolean tryLock = lock.tryLock(60, 60, TimeUnit.SECONDS);
            if(tryLock){
                List<UploadRealTimeMonitoringData> dataList = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
                if(!dataList.isEmpty()){
                    //获取当前订单的计费规则,然后分段计算总的度数和充电金额
                    List<AccountingStrategyDetailOrder> detailOrders = accountingStrategyDetailOrderService.list(new LambdaQueryWrapper<AccountingStrategyDetailOrder>()
                            .eq(AccountingStrategyDetailOrder::getChargingOrderId, order.getId()).last(" order by start_time"));
                    detailOrders.get(detailOrders.size() - 1).setEndTime("23:59");
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
                    //开始解析每个时段的充电度数
                    BigDecimal decimal = BigDecimal.ZERO;
                    //如果使用优惠券需要判断优惠券是否满足使用条件
                    //退款金额=优惠券金额+剩余充电金额
                    BigDecimal periodElectricPrice_total = BigDecimal.ZERO;
                    BigDecimal periodServicePrice_total = BigDecimal.ZERO;
                    BigDecimal vipDiscountAmount_total = BigDecimal.ZERO;
                    BigDecimal serviceCharge_total = BigDecimal.ZERO;
                    BigDecimal total = BigDecimal.ZERO;
                    //判断实时数据是否跨天
                    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
                    Date end_time = dataList.get(0).getCreate_time();
                    String end = sdf2.format(end_time);
                    Date start_time = dataList.get(dataList.size() - 1).getCreate_time();
                    String start = sdf2.format(start_time);
                    if(!end.equals(start)){
                        List<AccountingStrategyDetailOrder> list = detailOrders.stream().map(s->{
                            AccountingStrategyDetailOrder accountingStrategyDetailOrder = new AccountingStrategyDetailOrder();
                            BeanUtils.copyProperties(s, accountingStrategyDetailOrder);
                            return accountingStrategyDetailOrder;
                        }).collect(Collectors.toList());
                        for (AccountingStrategyDetailOrder detailOrder : detailOrders) {
                            detailOrder.setStartTime(start + " " + detailOrder.getStartTime());
                            detailOrder.setEndTime(start + " " + detailOrder.getEndTime());
                        }
                        for (AccountingStrategyDetailOrder detailOrder : list) {
                            detailOrder.setStartTime(end + " " + detailOrder.getStartTime());
                            detailOrder.setEndTime(end + " " + detailOrder.getEndTime());
                        }
                        detailOrders.addAll(list);
                    }else{
                        for (AccountingStrategyDetailOrder detailOrder : detailOrders) {
                            detailOrder.setStartTime(start + " " + detailOrder.getStartTime());
                            detailOrder.setEndTime(start + " " + detailOrder.getEndTime());
                        }
                    }
                    //企业账户流程:白名单企业账户订单按企业优惠结算(方式2=服务费比例优惠,方式3=按计费模板同阶段单价)
                    boolean enterpriseSettlement = chargingOrderService.isWhitelistEnterpriseOrder(order);
                    CompanyPreferentialDTO enterprisePreferential = enterpriseSettlement
                            ? chargeAccountSupport.loadCompanyPreferential(order.getCompanyId()) : null;
                    Integer enterprisePreferentialType = null == enterprisePreferential ? null : enterprisePreferential.getPreferentialType();
                    TBillingTemplateDTO enterpriseTemplate = enterpriseSettlement
                            ? chargeAccountSupport.loadBillingTemplate(enterprisePreferential) : null;
                    BigDecimal enterpriseElectricDiscount = BigDecimal.ZERO;
                    BigDecimal enterpriseServiceDiscount = BigDecimal.ZERO;
                    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmm");
                    List<TChargingOrderAccountingStrategy> list = new ArrayList<>();
                    for (AccountingStrategyDetailOrder detailOrder : detailOrders) {
                        long startTime = Long.parseLong(detailOrder.getStartTime().replaceAll("-", "").replaceAll(" ", "").replaceAll(":", ""));
                        long endTime = Long.parseLong(detailOrder.getEndTime().replaceAll("-", "").replaceAll(" ", "").replaceAll(":", ""));
                        List<UploadRealTimeMonitoringData> collect = dataList.stream().filter(s -> Long.parseLong(sdf1.format(s.getCreate_time())) > startTime && Long.parseLong(sdf1.format(s.getCreate_time())) <= endTime).collect(Collectors.toList());
                        if(!collect.isEmpty()){
                            //升序排序
                            collect.sort(new Comparator<UploadRealTimeMonitoringData>(){
                                @Override
                                public int compare(UploadRealTimeMonitoringData o1, UploadRealTimeMonitoringData o2) {
                                    return o1.getCharging_degree().compareTo(o2.getCharging_degree());
                                }
                            });
                            UploadRealTimeMonitoringData uploadRealTimeMonitoringData = collect.get(collect.size() - 1);
                            BigDecimal chargingDegree = uploadRealTimeMonitoringData.getCharging_degree();
                            BigDecimal subtract = chargingDegree.subtract(decimal);
                            decimal = chargingDegree;
                            if(subtract.compareTo(BigDecimal.ZERO) > 0){
                                //组装充电明细数据
                                TChargingOrderAccountingStrategy chargingOrderAccountingStrategy = new TChargingOrderAccountingStrategy();
                                chargingOrderAccountingStrategy.setChargingOrderId(order.getId());
                                chargingOrderAccountingStrategy.setAccountingStrategyDetailId(detailOrder.getId());
                                chargingOrderAccountingStrategy.setType(detailOrder.getType());
                                chargingOrderAccountingStrategy.setElectrovalence(detailOrder.getElectrovalence());
                                chargingOrderAccountingStrategy.setServiceCharge(detailOrder.getServiceCharge());
                                chargingOrderAccountingStrategy.setCostServiceCharge(detailOrder.getCostServiceCharge());
                                chargingOrderAccountingStrategy.setChargingCapacity(subtract);
                                chargingOrderAccountingStrategy.setCreateTime(LocalDateTime.now());
                                if (list.size() == 0) {
                                    String time = sdf.format(collect.get(0).getCreate_time());
                                    chargingOrderAccountingStrategy.setStartTime(time);
                                } else {
                                    chargingOrderAccountingStrategy.setStartTime(detailOrder.getStartTime().split(" ")[1]);
                                }
                                chargingOrderAccountingStrategy.setEndTime(detailOrder.getEndTime().split(" ")[1]);
                                //已充电总度数
                                BigDecimal finalElectricPrice = detailOrder.getElectrovalence();
                                BigDecimal finalServicePrice = detailOrder.getServiceCharge();
                                //企业账户流程:按企业优惠计算最终用电单价
                                if (enterpriseSettlement) {
                                    if (Integer.valueOf(ChargeAccountSupport.PREFERENTIAL_TYPE_RATE).equals(enterprisePreferentialType)) {
                                        //方式2:服务费按比例优惠
                                        finalServicePrice = ChargeAccountSupport.applyServiceDiscountRate(finalServicePrice, enterprisePreferential.getServiceDiscountRate());
                                    } else if (Integer.valueOf(ChargeAccountSupport.PREFERENTIAL_TYPE_TEMPLATE).equals(enterprisePreferentialType)) {
                                        //方式3:按计费模板同电价阶段单价
                                        TBillingTemplateDetail templateDetail = ChargeAccountSupport.findTemplateDetail(enterpriseTemplate, detailOrder.getType());
                                        if (null == templateDetail) {
                                            log.error("[CD补偿结算] 计费模板缺少对应电价阶段,该阶段按原价结算 code={} type={}", order.getCode(), detailOrder.getType());
                                        } else {
                                            if (null != templateDetail.getElectrovalence()) {
                                                finalElectricPrice = templateDetail.getElectrovalence();
                                            }
                                            if (null != templateDetail.getServiceCharge()) {
                                                finalServicePrice = templateDetail.getServiceCharge();
                                            }
                                        }
                                    }
                                }
                                BigDecimal electrovalenc = finalElectricPrice.multiply(subtract);
                                BigDecimal originalServicePrice = detailOrder.getServiceCharge().multiply(subtract);
                                BigDecimal serviceCharge = finalServicePrice.multiply(subtract);
                                BigDecimal vipDiscountAmount = BigDecimal.ZERO;
                                //计算优惠金额;企业账户流程按企业优惠结算,其余订单中余额支付(含组合支付)不参与会员折扣
                                if (enterpriseSettlement) {
                                    //企业优惠金额(原价-优惠价),用于订单优惠统计与 whitelist_* 快照
                                    enterpriseElectricDiscount = enterpriseElectricDiscount.add(detailOrder.getElectrovalence().multiply(subtract).subtract(electrovalenc));
                                    enterpriseServiceDiscount = enterpriseServiceDiscount.add(originalServicePrice.subtract(serviceCharge));
                                } else if (!isWhitelistOrder(order) && !isBalancePayMode(order.getPayMethod()) && null != order.getVipDiscount()) {
                                    //0.58折
                                    vipDiscountAmount = serviceCharge.multiply(new BigDecimal(1).subtract(order.getVipDiscount()));
                                    serviceCharge = serviceCharge.multiply(order.getVipDiscount());
                                }
                                //企业账户流程:明细单价记录优惠后单价,金额与单价口径一致
                                if (enterpriseSettlement) {
                                    chargingOrderAccountingStrategy.setElectrovalence(finalElectricPrice);
                                    chargingOrderAccountingStrategy.setServiceCharge(finalServicePrice);
                                }
                                chargingOrderAccountingStrategy.setPeriodElectricPrice(electrovalenc.setScale(4, RoundingMode.HALF_EVEN));
                                chargingOrderAccountingStrategy.setPeriodServicePrice(serviceCharge.setScale(4, RoundingMode.HALF_EVEN));
                                chargingOrderAccountingStrategy.setPeriodOriginalServicePrice(originalServicePrice.setScale(4, RoundingMode.HALF_EVEN));
                                chargingOrderAccountingStrategy.setVipDiscountAmount(vipDiscountAmount.setScale(4, RoundingMode.HALF_EVEN));
                                chargingOrderAccountingStrategy.setCreateTime(LocalDateTime.now());
                                list.add(chargingOrderAccountingStrategy);
                                //电费
                                periodElectricPrice_total = periodElectricPrice_total.add(electrovalenc);
                                //服务费(含折扣)
                                serviceCharge_total = serviceCharge_total.add(serviceCharge);
                                //服务费(不含折扣)
                                periodServicePrice_total = periodServicePrice_total.add(originalServicePrice);
                                //会员折扣优惠金额
                                vipDiscountAmount_total = vipDiscountAmount_total.add(vipDiscountAmount);
                                //原始总金额(不含折扣)
                                total = total.add(electrovalenc.add(originalServicePrice));
                            }
                        }
                    }
                    list.get(list.size() - 1).setEndTime(sdf.format(dataList.get(0).getCreate_time()));
                    chargingOrderAccountingStrategyService.saveBatch(list);
                    BigDecimal orderAmount = BigDecimal.valueOf(total.doubleValue());
                    //原金额
                    BigDecimal rechargeAmount = order.getRechargeAmount();
                    //支付金额
                    BigDecimal payAmount = periodElectricPrice_total.add(serviceCharge_total);
                    //退款金额=充值金额-实际支付金额
                    BigDecimal refundAmount = rechargeAmount.subtract(payAmount);
                    UploadRealTimeMonitoringData uploadRealTimeMonitoringData = uploadRealTimeMonitoringDataService.getLastDataById(order.getCode());
                    if (null != uploadRealTimeMonitoringData && null == order.getEndMode()) {
                        Integer soc = uploadRealTimeMonitoringData.getSoc();
                        if (soc >= 98) {
                            order.setEndMode(2);
                        } else if (null != order.getResidualAmount() && order.getResidualAmount().compareTo(new BigDecimal(1)) <= 0) {
                            order.setEndMode(3);
                        } else {
                            order.setEndMode(1);
                        }
                    }
                    order.setResidualAmount(rechargeAmount.subtract(total).setScale(2, RoundingMode.HALF_EVEN));
                    order.setStartTime(list.get(0).getCreateTime());
                    order.setEndTime(list.get(list.size() - 1).getCreateTime());
                    order.setStatus(5);
                    order.setOrderAmount(orderAmount.setScale(2, RoundingMode.HALF_EVEN));
                    order.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN));
                    order.setChargingCapacity(list.get(list.size() - 1).getChargingCapacity());
                    order.setElectricity(list.get(list.size() - 1).getChargingCapacity());
                    order.setVipDiscountAmount(vipDiscountAmount_total);
                    if (vipDiscountAmount_total.compareTo(BigDecimal.ZERO) == 0) {
                        order.setVipDiscount(BigDecimal.valueOf(1));
                    }
                    //计算优惠券
                    BigDecimal couponDiscount = BigDecimal.ZERO;
                    if (!isWhitelistOrder(order) && null != order.getAppCouponId()) {
                        //判断实际充电金额是否满足优惠券使用条件,如果不满足则不适用优惠券。
                        TAppCoupon appCoupon = appCouponClient.getAppCouponById(order.getAppCouponId()).getData();
                        String couponJson = appCoupon.getCouponJson();
                        TCoupon tCoupon = com.alibaba.fastjson2.JSON.parseObject(couponJson, TCoupon.class);
                        Integer preferentialMode = tCoupon.getPreferentialMode();
                        if (1 == preferentialMode) {
                            //满减
                            if (payAmount.compareTo(tCoupon.getMeetTheConditions()) >= 0) {
                                BigDecimal couponDiscountAmount = tCoupon.getDiscountAmount();
                                //如果优惠金额大于服务费金额,以服务费作为最大限制
                                if (serviceCharge_total.compareTo(couponDiscountAmount) < 0) {
                                    couponDiscount = serviceCharge_total;
                                    serviceCharge_total = BigDecimal.ZERO;
                                } else {
                                    couponDiscount = couponDiscountAmount;
                                }
                                appCoupon.setStatus(2);
                                appCouponClient.updateAppCoupon(appCoupon);
                            } else {
                                appCouponClient.refund(order.getAppCouponId().toString());
                                order.setAppCouponId(null);
                                order.setCouponDiscountAmount(BigDecimal.ZERO);
                            }
                        }
                        if (2 == preferentialMode) {
                            //抵扣
                            if (payAmount.compareTo(tCoupon.getMeetTheConditions()) >= 0) {
                                //折扣金额
                                BigDecimal divide = payAmount.multiply(new BigDecimal(10).subtract(tCoupon.getDiscount())).divide(new BigDecimal(10));
                                divide = divide.compareTo(tCoupon.getMaximumDiscountAmount()) > 0 ? tCoupon.getMaximumDiscountAmount() : divide;
                                //如果优惠金额大于服务费金额,以服务费作为最大限制
                                if (serviceCharge_total.compareTo(divide) < 0) {
                                    couponDiscount = serviceCharge_total;
                                    serviceCharge_total = BigDecimal.ZERO;
                                } else {
                                    couponDiscount = divide;
                                }
                                appCoupon.setStatus(2);
                                appCouponClient.updateAppCoupon(appCoupon);
                            } else {
                                order.setAppCouponId(null);
                                order.setCouponDiscountAmount(BigDecimal.ZERO);
                                appCouponClient.refund(order.getAppCouponId().toString());
                            }
                        }
                    }
                    BigDecimal[] whitelistRefundSplit = calculateWhitelistRefundSplit(order, periodElectricPrice_total, serviceCharge_total);
                    BigDecimal electricDiscount = whitelistRefundSplit[0];
                    BigDecimal serviceDiscount = whitelistRefundSplit[1];
                    BigDecimal whitelistDiscount = electricDiscount.add(serviceDiscount).setScale(4, RoundingMode.HALF_EVEN);
                    if (enterpriseSettlement) {
                        // 企业账户流程:企业优惠已在明细阶段计入金额,这里只做统计快照(金额口径与实时结算一致)
                        electricDiscount = enterpriseElectricDiscount.max(BigDecimal.ZERO).setScale(4, RoundingMode.HALF_EVEN);
                        serviceDiscount = enterpriseServiceDiscount.max(BigDecimal.ZERO).setScale(4, RoundingMode.HALF_EVEN);
                        whitelistDiscount = electricDiscount.add(serviceDiscount);
                    } else if (whitelistDiscount.compareTo(BigDecimal.ZERO) > 0) {
                        // 补偿任务需与实时结算使用同一拆分口径,避免财务导出金额不一致。
                        periodElectricPrice_total = periodElectricPrice_total.subtract(electricDiscount).max(BigDecimal.ZERO);
                        serviceCharge_total = serviceCharge_total.subtract(serviceDiscount).max(BigDecimal.ZERO);
                        refundAmount = refundAmount.add(whitelistDiscount);
                        payAmount = payAmount.subtract(whitelistDiscount).max(BigDecimal.ZERO);
                    }
                    //优惠券优惠金额
                    couponDiscount = couponDiscount.setScale(4, RoundingMode.HALF_EVEN);
                    //退款金额+优惠券
                    refundAmount = refundAmount.add(couponDiscount);
                    //实际支付金额-优惠券
                    payAmount = payAmount.subtract(couponDiscount);
                    if (serviceCharge_total.compareTo(BigDecimal.ZERO) > 0) {
                        serviceCharge_total = serviceCharge_total.subtract(couponDiscount);
                    }
                    order.setCouponDiscountAmount(couponDiscount.setScale(2, RoundingMode.HALF_EVEN));
                    //企业账户流程:企业优惠金额与 whitelist_* 三列快照双写(订单优惠统计沿用 whitelist_* 口径)
                    if (enterpriseSettlement) {
                        order.setDiscountElectrovalence(electricDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setDiscountServiceCharge(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setWhitelistElectricRefundAmount(electricDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setWhitelistServiceRefundAmount(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN));
                    } else {
                        order.setWhitelistDiscountAmount(whitelistDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setWhitelistElectricRefundAmount(electricDiscount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setWhitelistServiceRefundAmount(serviceDiscount.setScale(2, RoundingMode.HALF_EVEN));
                    }
                    order.setElectrovalence(periodElectricPrice_total.setScale(2, RoundingMode.HALF_EVEN));
                    order.setServiceCharge(serviceCharge_total.setScale(2, RoundingMode.HALF_EVEN));
                    if (enterpriseSettlement) {
                        // 企业账户流程:资金来自企业账户额度(差额结算时退回企业账户),订单无用户侧退款,实付金额=实际消费金额
                        order.setBalancePayAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setPaymentAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setRefundAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN));
                        order.setRefundStatus(2);
                        refundAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN);
                    } else {
                        order.setPaymentAmount(payAmount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN));
                        order.setRefundStatus(1);
                    }
                    UploadRealTimeMonitoringData asc = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode(), "asc");
                    UploadRealTimeMonitoringData desc = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode(), "desc");
                    if(null != asc){
                        order.setStartSoc(new BigDecimal(asc.getSoc()));
                    }
                    if(null != desc){
                        order.setEndSoc(new BigDecimal(desc.getSoc()));
                    }
                    chargingOrderService.updateById(order);
                    //企业账户流程:结算企业额度(按实际消费扣减锁定额度、差额退回企业账户)并写消费流水
                    if (enterpriseSettlement && !chargingOrderService.settleWhitelistEnterpriseAccount(order, payAmount)) {
                        // 结算失败回退为停止中,交由补偿任务下一轮重新结算,避免企业额度长期冻结
                        order.setStatus(4);
                        chargingOrderService.updateById(order);
                        log.error("[CD补偿结算] 企业账户额度结算失败,订单回退停止中等待重试 code={}", order.getCode());
                        return;
                    }
                    order = chargingOrderService.getById(order.getId());
                    Site site = siteClient.getSiteByIds(Arrays.asList(order.getSiteId())).getData().get(0);
                    //推送三方平台
                    if (2 == order.getOrderSource() && 1 == site.getIsOpenSynchronization()) {
                        TChargingOrder finalChargingOrder = order;
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                tcecClient.notificationEquipChargeStatus(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getOperatorId());
                                tcecClient.notificationStopChargeResult(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getChargingGunId().toString(),
                                        finalChargingOrder.getOperatorId());
                                tcecClient.notificationChargeOrderInfo(finalChargingOrder.getStartChargeSeq(), finalChargingOrder.getOperatorId());
                            }
                        }).start();
                    }
                    //开始将优惠券优惠的金额添加到明细中
                    BigDecimal couponDiscountAmount = order.getCouponDiscountAmount();
                    if (null != couponDiscountAmount && couponDiscountAmount.compareTo(BigDecimal.ZERO) > 0) {
                        List<TChargingOrderAccountingStrategy> list1 = chargingOrderAccountingStrategyService.list(new LambdaQueryWrapper<TChargingOrderAccountingStrategy>().eq(TChargingOrderAccountingStrategy::getChargingOrderId, order.getId()));
                        BigDecimal reduce = list1.stream().map(TChargingOrderAccountingStrategy::getPeriodServicePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                        for (TChargingOrderAccountingStrategy chargingOrderAccountingStrategy : list1) {
                            BigDecimal periodServicePrice = chargingOrderAccountingStrategy.getPeriodServicePrice();
                            BigDecimal multiply = couponDiscountAmount.multiply(periodServicePrice.divide(reduce, new MathContext(4, RoundingMode.HALF_EVEN)));
                            periodServicePrice = periodServicePrice.subtract(multiply);
                            chargingOrderAccountingStrategy.setPeriodServicePrice(periodServicePrice.setScale(2, RoundingMode.HALF_EVEN));
                            chargingOrderAccountingStrategy.setCouponDiscountAmount(multiply.setScale(2, RoundingMode.HALF_EVEN));
                        }
                        chargingOrderAccountingStrategyService.updateBatchById(list1);
                    }
                    // 将枪状态重置为空闲
                    TChargingGun chargingGun = new TChargingGun();
                    chargingGun.setId(order.getChargingGunId());
                    chargingGun.setStatus(2);
                    chargingGun.setChargingPower(BigDecimal.ZERO);
                    chargingGunClient.updateChargingGunById(chargingGun);
                    chargingGun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData();
                    //推送状态给三方平台
                    if (2 == order.getOrderSource() && 1 == site.getIsOpenSynchronization()) {
                        tcecClient.pushChargingGunStatus(chargingGun.getFullNumber(), 2);
                    }
                    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
                    TChargingOrder finalOrder = order;
                    threadPoolExecutor.execute(()->{
                        //推送成都监管
                        NotificationConnectorChargeStatusVo statusVo = new NotificationConnectorChargeStatusVo();
                        statusVo.setOrderCode(finalOrder.getCode());
                        statusVo.setChargingGunId(finalOrder.getChargingGunId());
                        chengDuJianGuanClient.notificationConnectorChargeStatus(statusVo);
                        chengDuJianGuanClient.notificationOrderInfo(statusVo);
                    });
                    //添加积分
                    if (1 == order.getOrderSource()) {
                        TIntegralRule integralRule = integralRuleClient.getSet().getData();
                        if (null != integralRule) {
                            TAppUser appUser = appUserClient.getUserById(order.getAppUserId()).getData();
                            Integer num1 = com.alibaba.fastjson2.JSON.parseObject(integralRule.getChargeCredit()).getInteger("num1");
                            Integer integral = order.getServiceCharge().intValue() * num1;
                            if (null != appUser.getVipId()) {
                                TVip vip = vipClient.getInfo1(appUser.getVipId()).getData();
                                Integer doubleIntegration = vip.getDoubleIntegration();
                                //双倍积分
                                if (1 == doubleIntegration) {
                                    integral *= 2;
                                }
                            }
                            if (integral > 0) {
                                TAppUserIntegralChange appUserIntegralChange = new TAppUserIntegralChange();
                                appUserIntegralChange.setAppUserId(appUser.getId());
                                appUserIntegralChange.setChangeType(2);
                                appUserIntegralChange.setHistoricalIntegral(appUser.getPoints());
                                appUser.setPoints(appUser.getPoints() + integral);
                                appUserIntegralChange.setCurrentIntegral(appUser.getPoints());
                                appUserIntegralChange.setCreateTime(LocalDateTime.now());
                                appUserIntegralChange.setOrderCode(order.getCode());
                                appUserIntegralChange.setExtension(order.getId().toString());
                                appUserClient.updateAppUser(appUser);
                                appUserIntegralChangeClient.addAppUserIntegralChange(appUserIntegralChange);
                            }
                        }
                        //计算用户标签
                        chargingOrderService.editUserTag(order);
                        //用户推荐奖励
                        chargingOrderService.referralReward(order);
                        //开始构建退款费用
                        refundAmount = refundAmount.setScale(2, RoundingMode.HALF_EVEN);
                        BigDecimal refundableThirdPayAmount = getRefundableThirdPayAmount(order);
                        BigDecimal remainingThirdAmount = refundableThirdPayAmount
                                .subtract(money(order.getThirdRefundAmount())).max(BigDecimal.ZERO);
                        BigDecimal remainingBalanceAmount = money(order.getBalancePayAmount())
                                .subtract(money(order.getBalanceRefundAmount())).max(BigDecimal.ZERO);
                        BigDecimal refundableAmount = remainingThirdAmount.add(remainingBalanceAmount).setScale(2, RoundingMode.HALF_UP);
                        // 白名单全部免费只记录预估预充金额,实际渠道退款金额保持0,防止补偿任务重复发起退款。
                        BigDecimal recordedRefundAmount = isWhitelistAllFreeOrder(order) ? money(order.getRechargeAmount()) : refundAmount;
                        BigDecimal channelRefundAmount = isWhitelistAllFreeOrder(order)
                                ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                                : refundAmount.min(refundableAmount).setScale(2, RoundingMode.HALF_UP);
                        Integer rechargePaymentType = order.getRechargePaymentType();
                        BigDecimal thirdRefundAmount = channelRefundAmount.min(remainingThirdAmount).setScale(2, RoundingMode.HALF_UP);
                        BigDecimal balanceRefundAmount = channelRefundAmount.subtract(thirdRefundAmount)
                                .min(remainingBalanceAmount).setScale(2, RoundingMode.HALF_UP);
                        if (channelRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                            refundAmount = thirdRefundAmount.add(balanceRefundAmount).setScale(2, RoundingMode.HALF_UP);
                            order.setThirdRefundAmount(money(order.getThirdRefundAmount()).add(thirdRefundAmount));
                            order.setBalanceRefundAmount(money(order.getBalanceRefundAmount()).add(balanceRefundAmount));
                            order.setRefundAmount(recordedRefundAmount);
                            order.setRefundStatus(refundAmount.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2);
                            chargingOrderService.updateById(order);
                            //构建退款明细
                            TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                            chargingOrderRefund.setChargingOrderId(order.getId());
                            SimpleDateFormat sdfaa = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                            chargingOrderRefund.setRefundCode("CDF" + sdfaa.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue()));
                            chargingOrderRefund.setRefundAmount(refundAmount);
                            chargingOrderRefund.setRefundStatus(1);
                            chargingOrderRefund.setPayType(rechargePaymentType);
                            chargingOrderRefund.setCode(order.getCode());
                            chargingOrderRefund.setRefundTitle("充电完成退款");
                            chargingOrderRefund.setRefundContent("充电完成退款");
                            chargingOrderRefund.setRefundReason("充电完成退款");
                            chargingOrderRefund.setRefundRemark("实际充电消费金额:" + order.getPaymentAmount());
                            chargingOrderRefund.setRefundTotalAmount(refundAmount);
                            chargingOrderRefund.setPayAmount(rechargeAmount);
                            if (thirdRefundAmount.compareTo(BigDecimal.ZERO) == 0) {
                                chargingOrderRefund.setRefundStatus(2);
                                chargingOrderRefund.setRefundSerialNumber("BALANCE");
                                chargingOrderRefund.setRefundTime(LocalDateTime.now());
                                chargingOrderRefundService.save(chargingOrderRefund);
                                if (balanceRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                                    recordBalanceRefund(order, balanceRefundAmount, chargingOrderRefund.getRefundCode());
                                }
                                order.setRefundStatus(2);
                                order.setRefundTime(LocalDateTime.now());
                                chargingOrderService.updateById(order);
                            } else if ("ICBC".equalsIgnoreCase(order.getSourceName())) {
                                IcbcRefundReq req = new IcbcRefundReq();
                                req.setOutTradeNo(order.getCode());
                                req.setOrderId(order.getRechargeSerialNumber());
                                req.setOutRefundNo(chargingOrderRefund.getRefundCode());
                                req.setRefundAmount(thirdRefundAmount);
                                req.setTotalAmount(getRefundableThirdPayAmount(order));
                                req.setReason("充电完成退款");
                                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())) {
                                    chargingOrderRefundService.save(chargingOrderRefund);
                                    String refundId = StringUtils.isNotEmpty(resp.getRefundId()) ? resp.getRefundId() : resp.getOutRefundNo();
                                    chargingOrderService.chargingOrderStartupFailureWxRefund(
                                            chargingOrderRefund.getRefundCode(), refundId, "SUCCESS", resp.getRefundTime());
                                } else {
                                    log.error("工行充电完成退款失败,订单号:{},退款单号:{},返回:{}",
                                            order.getCode(), chargingOrderRefund.getRefundCode(), result == null ? null : result.getMsg());
                                }
                            } else if (1 == rechargePaymentType) {
                                WxPaymentRefundModel model = new WxPaymentRefundModel();
                                model.setOut_trade_no(order.getCode());
                                model.setOut_refund_no(chargingOrderRefund.getRefundCode());
                                model.setReason("充电完成退款");
                                model.setNotify_url("/payment/wx/refund/notify");
                                WxPaymentRefundModel.RefundAmount amount = new WxPaymentRefundModel.RefundAmount();
                                amount.setRefund(thirdRefundAmount.multiply(new BigDecimal(100)).intValue());
                                amount.setTotal(getRefundableThirdPayAmount(order).multiply(new BigDecimal(100)).intValue());
                                amount.setCurrency("CNY");
                                model.setAmount(amount);
                                R<Map<String, Object>> result = wxPaymentClient.refundOrderR(model);
                                if (200 == result.getCode()) {
                                    chargingOrderRefundService.save(chargingOrderRefund);
                                    //???
                                    Map<String, Object> amount1 = (Map<String, Object>) result.getData().get("amount");
                                    Object refund_fee1 = amount1.get("refund_fee");
                                    BigDecimal refund_fee = new BigDecimal(null == refund_fee1 ? "0" : refund_fee1.toString()).divide(new BigDecimal(100));
                                    chargingOrderRefund.setRefundFee(refund_fee);
                                    chargingOrderRefundService.updateById(chargingOrderRefund);
                                }
                            }
                            else if (2 == rechargePaymentType) {
                                RefundReq dto = new RefundReq();
                                dto.setOutTradeNo(order.getCode());
                                dto.setOutRequestNo(chargingOrderRefund.getRefundCode());
                                dto.setRefundAmount(thirdRefundAmount.toString());
                                dto.setRefundReason("充电完成退款");
                                RefundResp resp = aliPaymentClient.refund(dto).getData();
                                if (null != resp) {
                                    chargingOrderRefundService.save(chargingOrderRefund);
                                    chargingOrderService.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null);
                                }
                            }
                            else if (3 == rechargePaymentType) {
                                RefundReq dto = new RefundReq();
                                dto.setOutTradeNo(order.getRechargeSerialNumber());
                                dto.setOutRequestNo(chargingOrderRefund.getRefundCode());
                                dto.setRefundAmount(thirdRefundAmount.toString());
                                dto.setRefundReason("充电完成退款");
                                RefundResp resp = h5AliPaymentClient.refund(dto).getData();
                                if (null != resp && "10000".equals(resp.getCode())) {
                                    chargingOrderRefundService.save(chargingOrderRefund);
                                    chargingOrderService.chargingOrderStartupFailureWxRefund(chargingOrderRefund.getRefundCode(), resp.getTradeNo(), "SUCCESS", null);
                                }
                            }
                        } else if (recordedRefundAmount.compareTo(BigDecimal.ZERO) > 0) {
                            order.setThirdRefundAmount(thirdRefundAmount);
                            order.setBalanceRefundAmount(balanceRefundAmount);
                            order.setRefundAmount(recordedRefundAmount);
                            order.setRefundStatus(2);
                            chargingOrderService.updateById(order);
                            TChargingOrderRefund chargingOrderRefund = new TChargingOrderRefund();
                            chargingOrderRefund.setChargingOrderId(order.getId());
                            SimpleDateFormat sdfaa = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                            chargingOrderRefund.setRefundCode("CDF" + sdfaa.format(new Date()) + (Double.valueOf(Math.random() * 1000).intValue()));
                            chargingOrderRefund.setRefundAmount(recordedRefundAmount);
                            chargingOrderRefund.setBalanceRefundAmount(balanceRefundAmount);
                            chargingOrderRefund.setThirdRefundAmount(thirdRefundAmount);
                            chargingOrderRefund.setRefundStatus(2);
                            chargingOrderRefund.setRefundSerialNumber("WHITELIST");
                            chargingOrderRefund.setRefundTime(LocalDateTime.now());
                            chargingOrderRefund.setPayType(rechargePaymentType);
                            chargingOrderRefund.setCode(order.getCode());
                            chargingOrderRefund.setRefundTitle("充电完成退款");
                            chargingOrderRefund.setRefundContent("充电完成退款");
                            chargingOrderRefund.setRefundReason("充电完成退款");
                            chargingOrderRefund.setRefundRemark("白名单全部免费,记录预估退款金额");
                            chargingOrderRefund.setRefundTotalAmount(recordedRefundAmount);
                            chargingOrderRefund.setPayAmount(rechargeAmount);
                            chargingOrderRefundService.save(chargingOrderRefund);
                        }
                    }
                    //添加汇总统计数据
                    List<TChargingOrderAccountingStrategy> list4 = chargingOrderAccountingStrategyService.list(new QueryWrapper<TChargingOrderAccountingStrategy>().eq("charging_order_id", order.getId()));
                    BigDecimal electronic_reduce = list4.stream().map(TChargingOrderAccountingStrategy::getPeriodElectricPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal service_reduce = list4.stream().map(TChargingOrderAccountingStrategy::getPeriodServicePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal chargingCapacity = list4.stream().map(TChargingOrderAccountingStrategy::getChargingCapacity).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal serviceMoney = BigDecimal.ZERO;
                    BigDecimal paymentMoney = BigDecimal.ZERO;
                    long time = 0;
                    if (!order.getOrderSource().equals(2)) {
                        serviceMoney = serviceMoney.add(service_reduce);
                        paymentMoney = paymentMoney.add(electronic_reduce).add(service_reduce);
                    } else {
                        serviceMoney = serviceMoney.add(service_reduce.multiply(new BigDecimal("0.8")));
                        paymentMoney = paymentMoney.add(electronic_reduce).add(service_reduce.multiply(new BigDecimal("0.8")));
                    }
                    if (order.getStartTime() != null && order.getEndTime() != null) {
                        time = ChronoUnit.SECONDS.between(order.getStartTime(), order.getEndTime());
                    }
                    TChargingOrderSummaryData summaryData = new TChargingOrderSummaryData();
                    summaryData.setChargingOrderId(order.getId());
                    summaryData.setChargingCapacity(chargingCapacity.setScale(6, RoundingMode.HALF_EVEN));
                    summaryData.setChargingDuration(time);
                    summaryData.setIncome(paymentMoney.setScale(2, BigDecimal.ROUND_HALF_EVEN));
                    summaryData.setElectricPrice(electronic_reduce.setScale(2, BigDecimal.ROUND_HALF_EVEN));
                    summaryData.setServicePrice(serviceMoney.setScale(2, BigDecimal.ROUND_HALF_EVEN));
                    chargingOrderSummaryDataService.save(summaryData);
                    //推送监管平台订单状态和订单详情
                    ChargingOrderVo chargingOrderVo = new ChargingOrderVo();
                    BeanUtils.copyProperties(order, chargingOrderVo);
                    chargingMessageClient.pushOrderInfo(chargingOrderVo);
                    chargingMessageClient.pushOrderStatus(chargingOrderVo);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    /**
     * 添加充电算账单汇总数据
     * 生成上个月账单,避免月末最后一天 00:30 之后结算的订单漏统计(与账户结算账单 addAccountSettlementStatement 保持一致)。
     */
    public void addChargingSettlementBill(){
        int day = LocalDate.now().getDayOfMonth();
        int lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        if (2 <= day && day <= lastDay) {
            refreshChargingSettlementBill(LocalDate.now().minusMonths(1));
        }
    }
    /**
     * 主动刷新指定月份的充电结算账单。重建该月全部数据(含已出账),并保持已出账月份状态不回退。
     */
    public synchronized void refreshChargingSettlementBill(LocalDate billingMonth){
        try {
            if (billingMonth == null) {
                throw new IllegalArgumentException("账单月份不能为空");
            }
                LocalDate firstDayOfBillingMonth = billingMonth.withDayOfMonth(2);
                String string = firstDayOfBillingMonth.toString();
                // 将-替换为空字符串
                string = string.replace("-", "");
                String targetMonth = billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                //统计数据的开始时间
                String startTime = targetMonth + "-01 00:00:00";
                //统计数据的结束时间
                int lastDay = billingMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
                String endTime = targetMonth + "-" + String.format("%02d", lastDay) + " 23:59:59";
                LocalDateTime createTime = LocalDateTime.now();
                //删除之前生成的汇总数据,在添加最新的汇总数据
                //重建时删除该月全部记录(含已出账),避免重建已冻结月份时旧数据残留造成重复;并保留已出账状态
                String format = firstDayOfBillingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                boolean targetFrozen = chargingSettlementBillService.count(new QueryWrapper<TChargingSettlementBill>()
                        .eq("status", 2)
                        .last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'")) > 0;
                chargingSettlementBillService.remove(new QueryWrapper<TChargingSettlementBill>().last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'"));
                int targetStatus = targetFrozen ? 2 : 1;
                //循环生成按照开始时间和结束时间分别统计的汇总数据
                for (int i = 1; i < 3; i++) {
                    TChargingSettlementBill chargingSettlementBill = new TChargingSettlementBill();
                    // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置)
                    Random random = new Random();
                    String randomDigits = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                            .mapToObj(String::valueOf)
                            .collect(Collectors.joining()); // 将其连接成一个字符串
                    chargingSettlementBill.setSiteId(0);
                    chargingSettlementBill.setStatisticalDateType(i);
                    chargingSettlementBill.setBillingCycle(firstDayOfBillingMonth);
                    chargingSettlementBill.setStatus(targetStatus);
                    chargingSettlementBill.setCode("JSD"+string+randomDigits);
                    //根据业务订单查询汇总数据
                    List<Map<String, Object>> mapList = chargingOrderService.getChargingSettlementBill(startTime, endTime, i);
                    Long chargingDuration = 0L;
                    Integer orderNumber = 0;
                    BigDecimal totalAmount = BigDecimal.ZERO;
                    BigDecimal platformFee = BigDecimal.ZERO;
                    BigDecimal tripartiteCommission = BigDecimal.ZERO;
                    BigDecimal fundsReceived = BigDecimal.ZERO;
                    BigDecimal totalElectricity = BigDecimal.ZERO;
                    BigDecimal totalElectricityCharge = BigDecimal.ZERO;
                    BigDecimal totalServiceFee = BigDecimal.ZERO;
                    BigDecimal couponDeduction = BigDecimal.ZERO;
                    List<TChargingSettlementBill> list = new ArrayList<>();
                    for (Map<String, Object> map : mapList) {
                        Long charging_duration = null == map.get("chargingDuration") ? 0L : Long.valueOf(map.get("chargingDuration").toString());
                        Integer order_number = null == map.get("orderNum") ? 0 : Integer.valueOf(map.get("orderNum").toString());
                        BigDecimal total_amount = null == map.get("totalAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("totalAmount").toString());
                        BigDecimal platform_fee = null == map.get("platformFee") ? BigDecimal.ZERO : new BigDecimal(map.get("platformFee").toString());
                        BigDecimal tripartite_commission = null == map.get("tripartiteCommission") ? BigDecimal.ZERO : new BigDecimal(map.get("tripartiteCommission").toString());
                        BigDecimal funds_received = total_amount.subtract(platform_fee).subtract(tripartite_commission);
                        BigDecimal total_electricity = null == map.get("totalElectricity") ? BigDecimal.ZERO : new BigDecimal(map.get("totalElectricity").toString());
                        BigDecimal total_electricity_charge = null == map.get("totalElectricityCharge") ? BigDecimal.ZERO : new BigDecimal(map.get("totalElectricityCharge").toString());
                        BigDecimal total_service_fee = null == map.get("totalServiceFee") ? BigDecimal.ZERO : new BigDecimal(map.get("totalServiceFee").toString());
                        BigDecimal coupon_deduction = null == map.get("couponDeduction") ? BigDecimal.ZERO : new BigDecimal(map.get("couponDeduction").toString());
                        //构建每个站点的汇总数据
                        TChargingSettlementBill chargingSettlementBill1 = new TChargingSettlementBill();
                        String randomDigits1 = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                                .mapToObj(String::valueOf)
                                .collect(Collectors.joining()); // 将其连接成一个字符串
                        chargingSettlementBill1.setSiteId(Integer.valueOf(map.get("siteId").toString()));
                        chargingSettlementBill1.setStatisticalDateType(i);
                        chargingSettlementBill1.setBillingCycle(firstDayOfBillingMonth);
                        chargingSettlementBill1.setStatus(targetStatus);
                        chargingSettlementBill1.setCode("JSD"+string+randomDigits1);
                        chargingSettlementBill1.setChargingDuration(charging_duration);
                        chargingSettlementBill1.setOrderNumber(order_number);
                        chargingSettlementBill1.setTotalAmount(total_amount.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setCouponDeduction(coupon_deduction.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setPlatformFee(platform_fee.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setTripartiteCommission(tripartite_commission.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setFundsReceived(funds_received.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setTotalElectricity(total_electricity.setScale(4, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setTotalElectricityCharge(total_electricity_charge.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setTotalServiceFee(total_service_fee.setScale(2, RoundingMode.HALF_EVEN));
                        chargingSettlementBill1.setCreateTime(createTime);
                        list.add(chargingSettlementBill1);
                        //计算全站汇总数据
                        chargingDuration = chargingDuration + charging_duration;
                        orderNumber = orderNumber + order_number;
                        totalAmount = totalAmount.add(total_amount);
                        platformFee = platformFee.add(platform_fee);
                        tripartiteCommission = tripartiteCommission.add(tripartite_commission);
                        fundsReceived = fundsReceived.add(funds_received);
                        totalElectricity = totalElectricity.add(total_electricity);
                        totalElectricityCharge = totalElectricityCharge.add(total_electricity_charge);
                        totalServiceFee = totalServiceFee.add(total_service_fee);
                        couponDeduction = couponDeduction.add(coupon_deduction);
                    }
                    chargingSettlementBill.setChargingDuration(chargingDuration);
                    chargingSettlementBill.setOrderNumber(orderNumber);
                    chargingSettlementBill.setTotalAmount(totalAmount.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setCouponDeduction(couponDeduction.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setPlatformFee(platformFee.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setTripartiteCommission(tripartiteCommission.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setFundsReceived(fundsReceived.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setTotalElectricity(totalElectricity.setScale(4, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setTotalElectricityCharge(totalElectricityCharge.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setTotalServiceFee(totalServiceFee.setScale(2, RoundingMode.HALF_EVEN));
                    chargingSettlementBill.setCreateTime(createTime);
                    chargingSettlementBillService.save(chargingSettlementBill);
                    chargingSettlementBillService.saveBatch(list);
                }
        } catch (Exception e) {
            log.error("生成{}充电结算账单失败", billingMonth, e);
            throw new RuntimeException("生成充电结算账单失败", e);
        }
    }
    /**
     * 添加账户结算账单数据
     */
    public void addAccountSettlementStatement(){
        int day = LocalDate.now().getDayOfMonth();
        int lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        //时间在当月的2号到当月的最后一天才执行汇总数据和生成新的汇总数据(中间有修改数据的情况)
        if (2 <= day && day <= lastDay) {
            refreshAccountSettlementStatement(LocalDate.now().minusMonths(1));
        }
    }
    /**
     * 主动刷新指定月份的账户结算账单。只重建该月未出账数据,已出账数据不受影响。
     */
    public synchronized void refreshAccountSettlementStatement(LocalDate billingMonth) {
        try {
                if (billingMonth == null) {
                    throw new IllegalArgumentException("账单月份不能为空");
                }
                LocalDate firstDayOfBillingMonth = billingMonth.withDayOfMonth(2);
                String string = firstDayOfBillingMonth.toString();
                // 将-替换为空字符串
                string = string.replace("-", "");
                String targetMonth = billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                //统计数据的开始时间
                String startTime = targetMonth + "-01 00:00:00";
                //统计数据的结束时间
                int targetLastDay = billingMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
                String endTime = targetMonth + "-" + String.format("%02d", targetLastDay) + " 23:59:59";
                LocalDateTime createTime = LocalDateTime.now();
                //删除之前生成的汇总数据,在添加最新的汇总数据
                String format = firstDayOfBillingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                accountSettlementStatementService.remove(new QueryWrapper<TAccountSettlementStatement>().eq("status", 1).last(" and DATE_FORMAT(billing_cycle, '%Y-%m') = '" + format + "'"));
                Map<Integer, BigDecimal> siteServiceShareRatioMap = loadSiteServiceShareRatioMap();
                // V2.0 账户类型统一为工商银行商户,只生成明星充电小程序订单账单。
                for (int i = 3; i < 4; i++) {
                    TAccountSettlementStatement accountSettlementStatement = new TAccountSettlementStatement();
                    // 订单生成规则JSD+20231201(账单所属月份)+1131304205(随机10位数)+001(当月账单序号,每月重置)
                    Random random = new Random();
                    String randomDigits = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                            .mapToObj(String::valueOf)
                            .collect(Collectors.joining()); // 将其连接成一个字符串
                    accountSettlementStatement.setSiteId(0);
                    accountSettlementStatement.setAccountType(i);
                    accountSettlementStatement.setBillingCycle(firstDayOfBillingMonth);
                    accountSettlementStatement.setStatus(1);
                    accountSettlementStatement.setCode("JSD"+string+randomDigits);
                    //根据业务订单查询汇总数据
                    List<Map<String, Object>> mapList = chargingOrderService.getAccountSettlementStatement(startTime, endTime);
                    BigDecimal rechargeAmount = BigDecimal.ZERO;
                    BigDecimal refundAmount = BigDecimal.ZERO;
                    BigDecimal platformFee = BigDecimal.ZERO;
                    BigDecimal tripartiteCommission = BigDecimal.ZERO;
                    BigDecimal recordedAmount = BigDecimal.ZERO;
                    BigDecimal platformIncome = BigDecimal.ZERO;
                    BigDecimal partnerIncome = BigDecimal.ZERO;
                    List<TAccountSettlementStatement> list = new ArrayList<>();
                    for (Map<String, Object> map : mapList) {
                        Integer siteId = Integer.valueOf(map.get("siteId").toString());
                        BigDecimal recharge_amount = null == map.get("rechargeAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("rechargeAmount").toString());
                        BigDecimal refund_amount = null == map.get("refundAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("refundAmount").toString());
                        BigDecimal service_amount = null == map.get("serviceAmount") ? BigDecimal.ZERO : new BigDecimal(map.get("serviceAmount").toString());
                        BigDecimal partner_income = calculateAccountPartnerIncome(
                                service_amount, siteServiceShareRatioMap.get(siteId), false);
                        BigDecimal platform_income = calculateAccountPlatformIncome(recharge_amount, partner_income);
                        BigDecimal recorded_amount = recharge_amount.subtract(refund_amount);
                        //构建每个站点的汇总数据
                        TAccountSettlementStatement accountSettlementStatement1 = new TAccountSettlementStatement();
                        String randomDigits1 = random.ints(10, 0, 10) // 生成10个随机数字,范围在0-9
                                .mapToObj(String::valueOf)
                                .collect(Collectors.joining()); // 将其连接成一个字符串
                        accountSettlementStatement1.setSiteId(siteId);
                        accountSettlementStatement1.setAccountType(i);
                        accountSettlementStatement1.setBillingCycle(firstDayOfBillingMonth);
                        accountSettlementStatement1.setStatus(1);
                        accountSettlementStatement1.setCode("JSD"+string+randomDigits1);
                        accountSettlementStatement1.setRechargeAmount(recharge_amount.setScale(2, RoundingMode.HALF_EVEN));
                        accountSettlementStatement1.setRefundAmount(refund_amount.setScale(2, RoundingMode.HALF_EVEN));
                        accountSettlementStatement1.setPlatformFee(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN));
                        accountSettlementStatement1.setTripartiteCommission(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN));
                        accountSettlementStatement1.setRecordedAmount(recorded_amount.setScale(2, RoundingMode.HALF_EVEN));
                        accountSettlementStatement1.setPlatformIncome(platform_income.setScale(2, RoundingMode.HALF_UP));
                        accountSettlementStatement1.setPartnerIncome(partner_income.setScale(2, RoundingMode.HALF_UP));
                        accountSettlementStatement1.setCreateTime(createTime);
                        list.add(accountSettlementStatement1);
                        //计算全站汇总数据
                        rechargeAmount = rechargeAmount.add(recharge_amount);
                        refundAmount = refundAmount.add(refund_amount);
                        recordedAmount = recordedAmount.add(recorded_amount);
                        platformIncome = platformIncome.add(platform_income);
                        partnerIncome = partnerIncome.add(partner_income);
                    }
                    accountSettlementStatement.setRechargeAmount(rechargeAmount.setScale(2, RoundingMode.HALF_EVEN));
                    accountSettlementStatement.setRefundAmount(refundAmount.setScale(2, RoundingMode.HALF_EVEN));
                    accountSettlementStatement.setPlatformFee(platformFee.setScale(2, RoundingMode.HALF_EVEN));
                    accountSettlementStatement.setTripartiteCommission(tripartiteCommission.setScale(2, RoundingMode.HALF_EVEN));
                    accountSettlementStatement.setRecordedAmount(recordedAmount.setScale(2, RoundingMode.HALF_EVEN));
                    accountSettlementStatement.setPlatformIncome(platformIncome.setScale(2, RoundingMode.HALF_UP));
                    accountSettlementStatement.setPartnerIncome(partnerIncome.setScale(2, RoundingMode.HALF_UP));
                    accountSettlementStatement.setCreateTime(createTime);
                    accountSettlementStatementService.save(accountSettlementStatement);
                    accountSettlementStatementService.saveBatch(list);
                }
        } catch (Exception e) {
            log.error("生成{}账户结算账单失败", billingMonth, e);
            throw new RuntimeException("生成账户结算账单失败", e);
        }
    }
    static BigDecimal calculateAccountPartnerIncome(BigDecimal paidServiceAmount, BigDecimal serviceShareRatio,
                                                     boolean thirdPartyOrder) {
        if (thirdPartyOrder || paidServiceAmount == null || serviceShareRatio == null
                || serviceShareRatio.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }
        return paidServiceAmount.multiply(serviceShareRatio)
                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
    }
    static BigDecimal calculateAccountPlatformIncome(BigDecimal paymentAmount, BigDecimal partnerIncome) {
        BigDecimal paid = paymentAmount == null ? BigDecimal.ZERO : paymentAmount;
        BigDecimal partner = partnerIncome == null ? BigDecimal.ZERO : partnerIncome;
        return paid.subtract(partner).setScale(2, RoundingMode.HALF_UP);
    }
    private Map<Integer, BigDecimal> loadSiteServiceShareRatioMap() {
        List<Site> sites = Optional.ofNullable(siteClient.getSiteAll())
                .map(R::getData).orElse(Collections.emptyList());
        List<Partner> partners = Optional.ofNullable(siteClient.getAllPartner())
                .map(R::getData).orElse(Collections.emptyList());
        Map<Integer, Partner> partnerMap = partners.stream()
                .filter(partner -> partner != null && partner.getId() != null)
                .collect(Collectors.toMap(Partner::getId, partner -> partner, (left, right) -> left));
        Map<Integer, BigDecimal> ratioMap = new HashMap<>();
        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;
    }
    /**
     * 推送三方引流平台充电数据
     */
    public void pushOrderDrainagePlatform(){
        String format = LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<TChargingOrder> list = chargingOrderService.list(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getStatus, 5)
                .eq(TChargingOrder::getOrderSource, 2).eq(TChargingOrder::getDelFlag, 0)
                .isNotNull(TChargingOrder::getStartChargeSeq).isNotNull(TChargingOrder::getOperatorId)
                .last(" and DATE_FORMAT(end_time, '%Y-%m-%d') = '" + format + "'"));
        for (TChargingOrder tChargingOrder : list) {
            String code = tChargingOrder.getCode();
            chargingOrderService.pushOrderInfo(code);
        }
    }
}