package com.jsowell.pile.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Refund;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.vo.AuthorizedDeptVO;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.core.domain.ykc.TransactionRecordsData;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.MemberWalletEnum;
import com.jsowell.common.enums.ykc.*;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.AdapayUtil;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.SecurityUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.bean.BeanUtils;
import com.jsowell.common.util.id.IdUtils;
import com.jsowell.common.util.id.SnowflakeIdWorker;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.dto.*;
import com.jsowell.pile.mapper.OrderBasicInfoMapper;
import com.jsowell.pile.service.*;
import com.jsowell.pile.transaction.dto.OrderTransactionDTO;
import com.jsowell.pile.transaction.service.TransactionService;
import com.jsowell.pile.vo.base.OrderAmountDetailVO;
import com.jsowell.pile.vo.base.OrderPeriodAmountVO;
import com.jsowell.pile.vo.base.PileInfoVO;
import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO;
import com.jsowell.pile.vo.uniapp.MemberVO;
import com.jsowell.pile.vo.uniapp.OrderVO;
import com.jsowell.pile.vo.uniapp.PersonPileConnectorSumInfoVO;
import com.jsowell.pile.vo.uniapp.SendMessageVO;
import com.jsowell.pile.vo.web.*;
import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.dto.WeChatRefundDTO;
import com.jsowell.wxpay.dto.WechatSendMsgDTO;
import com.jsowell.wxpay.response.WechatPayRefundRequest;
import com.jsowell.wxpay.response.WechatPayRefundResponse;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 订单Service业务层处理
 *
 * @author jsowell
 * @date 2022-09-30
 */
@Service
public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private OrderBasicInfoMapper orderBasicInfoMapper;

    @Autowired
    private TransactionService transactionService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IOrderPayRecordService orderPayRecordService;

    @Autowired
    private IMemberBasicInfoService memberBasicInfoService;

    @Autowired
    private WxpayCallbackRecordService wxpayCallbackRecordService;

    @Autowired
    private AdapayCallbackRecordService adapayCallbackRecordService;

    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private IOrderAbnormalRecordService orderAbnormalRecordService;

    @Autowired
    private TransactionService pileTransactionService;

    @Autowired
    private WxAppletRemoteService wxAppletRemoteService;

    @Autowired
    private IPileBasicInfoService pileBasicInfoService;

    @Autowired
    private IPileConnectorInfoService pileConnectorInfoService;

    @Autowired
    private WxpayRefundCallbackService wxpayRefundCallbackService;

    @Autowired
    private IPileBillingTemplateService pileBillingTemplateService;

    @Autowired
    private IPileAuthCardService pileAuthCardService;

    @Autowired
    private OrderMonitorDataService orderMonitorDataService;

    @Autowired
    private IPileStationInfoService pileStationInfoService;

    @Autowired
    private IPileMerchantInfoService pileMerchantInfoService;

    @Autowired
    private IMemberPlateNumberRelationService memberPlateNumberRelationService;

    @Value("${adapay.refundCallback}")
    private String ADAPAY_REFUND_CALLBACK_URL;

    @Autowired
    private IMemberTransactionRecordService memberTransactionRecordService;

    @Autowired
    private ISettleOrderReportService settleOrderReportService;

    @Autowired
    private IAdapayMemberAccountService adapayMemberAccountService;
    /**
     * 条件查询订单基本信息
     *
     * @param info
     * @return
     */
    @Override
    public OrderBasicInfo getOrderBasicInfo(OrderBasicInfo info) {
        return orderBasicInfoMapper.getOrderBasicInfo(info);
    }

    /**
     * 查询订单列表
     *
     * @param dto 订单
     * @return 订单
     */
    @Override
    // @DataScope(deptAlias = "t3")
    public List<OrderListVO> selectOrderBasicInfoList(QueryOrderDTO dto) {
        // 权限过滤
        AuthorizedDeptVO authorizedMap = SecurityUtils.getAuthorizedMap();
        if (authorizedMap == null) {
            // 为空表示没有权限，返回空数组
            return Lists.newArrayList();
        }
        dto.setStationDeptIds(authorizedMap.getStationDeptIds());
        dto.setMerchantDeptIds(authorizedMap.getMerchantDeptIds());

        List<OrderListVO> orderListVOS = orderBasicInfoMapper.selectOrderBasicInfoList(dto);
        if (CollectionUtils.isNotEmpty(orderListVOS)) {
            for (OrderListVO orderListVO : orderListVOS) {
                // 如果是微信支付，通过订单号查询微信支付单号
                // logger.info("如果是微信支付，通过订单号查询微信支付单号 orderListVO:{}", JSON.toJSONString(orderListVO));
                if (StringUtils.equals(PaymentInstitutionsEnum.ADAPAY.getValue(), orderListVO.getPaymentInstitutions())) {
                    AdapayCallbackRecord adapayCallbackRecord = adapayCallbackRecordService.selectByOrderCode(orderListVO.getOrderCode());
                    orderListVO.setOutTradeNo(adapayCallbackRecord.getPaymentId());
                } else if (StringUtils.equals(PaymentInstitutionsEnum.WECHAT_PAY.getValue(), orderListVO.getPaymentInstitutions())){
                    WxpayCallbackRecord wxpayCallbackRecord = wxpayCallbackRecordService.selectByOrderCode(orderListVO.getOrderCode());
                    orderListVO.setOutTradeNo(wxpayCallbackRecord.getOutTradeNo());
                }
                orderListVO.setPileConnectorCode(orderListVO.getPileSn() + orderListVO.getConnectorCode());
                orderListVO.setOrderStatusDescribe(transformOrderStatusDescribe(orderListVO.getOrderStatus(), orderListVO.getPayStatus()));
            }
        }
        return orderListVOS;
    }

    private void tempUpdateVirtualAmount(OrderListVO orderListVO) {
        if (orderListVO.getVirtualAmount() != null) {
            return;
        }
        // 订单总消费金额
        BigDecimal orderAmount = new BigDecimal(orderListVO.getOrderAmount());
        // 支付金额
        BigDecimal payAmount = new BigDecimal(orderListVO.getPayAmount());

        if (orderAmount.compareTo(payAmount) > 0) {
            orderAmount = payAmount;
        }

        // 使用虚拟金额消费 金额
        BigDecimal virtualAmount = BigDecimal.ZERO;
        // 结算金额
        BigDecimal settleAmount = BigDecimal.ZERO;

        if (orderAmount.compareTo(BigDecimal.ZERO) > 0) {
            if (StringUtils.equals(orderListVO.getPayMode(), OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) {
					/*
					余额支付  查询支付记录，如全部用本金支付，则虚拟金额为0，结算金额为订单消费金额，
					如果使用了赠送金额，虚拟金额为赠送金额支付部分，结算金额=订单消费金额-虚拟金额消费部分
					 */
                // 查询支付记录
                List<OrderPayRecord> orderPayRecordList = orderPayRecordService.getOrderPayRecordList(orderListVO.getOrderCode());
                for (OrderPayRecord orderPayRecord : orderPayRecordList) {
                    if (StringUtils.equals(orderPayRecord.getPayMode(), OrderPayRecordEnum.GIFT_BALANCE_PAYMENT.getValue())) {
                        BigDecimal refundAmount = orderPayRecord.getRefundAmount();
                        if (refundAmount == null) {
                            // 退款金额为null, 需要退款的金额 = 支付金额 - 订单金额
                            refundAmount = orderPayRecord.getPayAmount().subtract(orderAmount);
                        }
                        // 赠送金额消费部分 = 支付金额 - 需要退款金额
                        virtualAmount = orderPayRecord.getPayAmount().subtract(refundAmount);
                        // 结算金额 = 订单金额 - 赠送金额消费部分
                        settleAmount = orderAmount.subtract(virtualAmount);
                    } else {
                        // 没有使用赠送金额支付，那么虚拟金额就是0，结算金额就等于订单金额
                        settleAmount = orderAmount;
                    }
                }
            } else {
					/*
					微信支付  虚拟金额为0 结算金额等于订单消费金额
					 */
                settleAmount = orderAmount;
            }
        }

        OrderBasicInfo build = OrderBasicInfo.builder()
                .id(Long.parseLong(orderListVO.getId()))
                .orderCode(orderListVO.getOrderCode())
                .orderAmount(orderAmount)
                .virtualAmount(virtualAmount)
                .settleAmount(settleAmount)
                .build();
        updateOrderBasicInfo(build);
    }

    /**
     * 通过订单状态和支付状态 转换订单状态描述
     *
     * @param orderStatus
     * @param payStatus
     * @return
     */
    @Override
    public String transformOrderStatusDescribe(String orderStatus, String payStatus) {
        // 订单状态描述
        // String orderStatus = orderListVO.getOrderStatus(); // 订单状态
        // String payStatus = orderListVO.getPayStatus(); // 支付状态
        String orderStatusDescribe;
        if (StringUtils.equals(orderStatus, OrderStatusEnum.NOT_START.getValue())) {
            // 未启动还有两种情况 待支付 / 支付成功
            if (StringUtils.equals(payStatus, OrderPayStatusEnum.paid.getValue())) {
                // 支付成功，未启动
                orderStatusDescribe = OrderPayStatusEnum.paid.getLabel() + ", " + OrderStatusEnum.getOrderStatus(orderStatus);
            } else {
                // 待支付
                orderStatusDescribe = OrderPayStatusEnum.unpaid.getLabel();
            }
        } else {
            orderStatusDescribe = OrderStatusEnum.getOrderStatus(orderStatus);
        }
        return orderStatusDescribe;
    }

    /**
     * 查询时间段内订单总金额和总用电量
     *
     * @param dto
     * @return
     */
    @Override
    // @DataScope(deptAlias = "t3")
    public OrderTotalDataVO getOrderTotalData(QueryOrderDTO dto) {
        OrderTotalDataVO vo = new OrderTotalDataVO();
        dto.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
        List<OrderListVO> list = selectOrderBasicInfoList(dto);
        BigDecimal sumOrderAmount = BigDecimal.ZERO;
        BigDecimal sumUsedElectricity = BigDecimal.ZERO;
        vo.setDateDescription(dto.getStartTime() + " - " + dto.getEndTime());
        if (CollectionUtils.isNotEmpty(list)) {
            for (OrderListVO orderListVO : list) {
                BigDecimal orderAmount = StringUtils.isBlank(orderListVO.getOrderAmount())
                        ? BigDecimal.ZERO
                        : new BigDecimal(orderListVO.getOrderAmount());
                sumOrderAmount = sumOrderAmount.add(orderAmount);

                BigDecimal chargingDegree = StringUtils.isBlank(orderListVO.getChargingDegree())
                        ? BigDecimal.ZERO
                        : new BigDecimal(orderListVO.getChargingDegree());
                sumUsedElectricity = sumUsedElectricity.add(chargingDegree);
            }
        }
        vo.setSumOrderAmount(sumOrderAmount);
        vo.setSumUsedElectricity(sumUsedElectricity);
        return vo;
    }

    /**
     * 通过订单号查询订单信息（小程序发送消息用）
     *
     * @param orderCode
     * @return
     */
    @Override
    public SendMessageVO selectOrderInfoByOrderCode(String orderCode) {
        return orderBasicInfoMapper.selectOrderInfoByOrderCode(orderCode);
    }

    /**
     * 充电桩启动失败
     *
     * @param transactionCode 交易流水号
     * @param failedReasonMsg 失败原因
     */
    @Override
    public void chargingPileFailedToStart(String transactionCode, String failedReasonMsg) {
        logger.info("启动失败退款 transactionCode:{}, 失败原因:{}", transactionCode, failedReasonMsg);
        // OrderBasicInfo orderInfo = getOrderInfoByOrderCode(orderCode);
        OrderBasicInfo orderInfo = getOrderInfoByTransactionCode(transactionCode);
        if (orderInfo == null) {
            return;
        }
        // 启动失败原因
        orderInfo.setReason(failedReasonMsg);
        // 订单退款(结算订单)
        TransactionRecordsData data = TransactionRecordsData.builder()
                .transactionCode(orderInfo.getTransactionCode())
                .consumptionAmount(String.valueOf(orderInfo.getOrderAmount()))
                .stopReasonMsg(failedReasonMsg)
                .totalElectricity(Constants.ZERO)
                .sharpUsedElectricity(Constants.ZERO)
                .peakUsedElectricity(Constants.ZERO)
                .flatUsedElectricity(Constants.ZERO)
                .valleyUsedElectricity(Constants.ZERO)
                .build();
        settleOrder(data, orderInfo);
    }

    /**
     * 充电桩启动成功
     *
     * @param transactionCode
     */
    @Override
    public void chargingPileStartedSuccessfully(String transactionCode) {
        // OrderBasicInfo orderInfo = getOrderInfoByOrderCode(orderCode);
        OrderBasicInfo orderInfo = getOrderInfoByTransactionCode(transactionCode);
        if (orderInfo == null) {
            return;
        }
        // 启动成功，订单状态改为充电中
        orderInfo.setOrderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue());
        if (orderInfo.getChargeStartTime() == null) {
            orderInfo.setChargeStartTime(new Date());
        }
        updateOrderBasicInfo(orderInfo);
    }

    @Override
    public void closeStartFailedOrder(String startTime, String endTime) {
        List<OrderBasicInfo> orderList = orderBasicInfoMapper.selectOrderListByTimeRangeAndStatus(startTime, endTime, OrderStatusEnum.NOT_START.getValue(), OrderPayStatusEnum.paid.getValue());
        List<String> orderCodeList = orderList.stream().map(OrderBasicInfo::getOrderCode).collect(Collectors.toList());
        logger.info("{}-{}期间，共{}条，支付成功未启动订单，订单号:{}", startTime, endTime, orderList.size(), orderCodeList);
        if (CollectionUtils.isEmpty(orderList)) {
            return;
        }
        long currentTimeMillis = System.currentTimeMillis();
        // 判断支付成功时间距当前时间是否大于15分钟
        for (OrderBasicInfo orderBasicInfo : orderList) {
            // 立即启动的订单使用支付时间判断，预约充电的订单使用预约时间判断
            long time;
            String startType = orderBasicInfo.getStartType();
            if (StringUtils.equals(StartTypeEnum.NOW.getValue(), startType)) {
                Date payTime = orderBasicInfo.getPayTime();
                time = payTime == null ? 0L : payTime.getTime();
            } else {
                Date appointmentTime = orderBasicInfo.getAppointmentTime();
                time = appointmentTime == null ? 0L : appointmentTime.getTime();
            }

            if (currentTimeMillis - time < 1000 * 60 * 15) {
                continue;
            }
            // 已经支付超过15分钟 判断充电桩的状态
            String pileConnectorCode = orderBasicInfo.getPileSn() + orderBasicInfo.getConnectorCode();
            PileConnectorInfoVO connector = pileConnectorInfoService.getPileConnectorInfoByConnectorCode(pileConnectorCode);
            // 充电桩不在线，则不做处理。请联系管理员操作
            if (PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue().equals(String.valueOf(connector.getStatus()))) {
                logger.info("订单号:{}已经支付超过15分钟，充电桩:{}未启动，但是该桩为离线状态，请联系管理员处理", orderBasicInfo.getOrderCode(), pileConnectorCode);
                continue;
            }
            // 获取订单的实时检测数据，有实时数据说明充电了，没有实时数据说明桩确实没有充电
            List<RealTimeMonitorData> chargingRealTimeData = getChargingRealTimeData(orderBasicInfo.getTransactionCode());
            if (CollectionUtils.isEmpty(chargingRealTimeData)) {
                // 充电桩在线，并且没有0x13实时数据，则执行结算退款操作
                chargingPileFailedToStart(orderBasicInfo.getTransactionCode(), "充电桩启动失败，执行退款处理");
            }
        }
    }

    /**
     * 查询充电中的订单，没有数据权限校验，后管不要用
     *
     * @param pileSn
     * @return
     */
    @Override
    public List<OrderListVO> selectChargingOrder(String pileSn) {
        QueryOrderDTO dto = QueryOrderDTO.builder()
                .pileSn(pileSn)
                .orderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue())
                .build();
        return orderBasicInfoMapper.selectOrderBasicInfoList(dto);
    }

    /**
     * 修改订单
     *
     * @param orderBasicInfo 订单
     * @return 结果
     */
    @Transactional
    @Override
    public int updateOrderBasicInfo(OrderBasicInfo orderBasicInfo) {
        // 清缓存
        this.cleanCacheByOrderCode(orderBasicInfo.getOrderCode(), orderBasicInfo.getTransactionCode());
        int i = orderBasicInfoMapper.updateOrderBasicInfo(orderBasicInfo);
        CompletableFuture.runAsync(() -> this.cleanCacheByOrderCode(orderBasicInfo.getOrderCode(), orderBasicInfo.getTransactionCode()));
        return i;
    }

    /**
     * 修改订单详情
     *
     * @param orderDetail
     * @return
     */
    @Override
    public int updateOrderDetail(OrderDetail orderDetail) {
        return orderBasicInfoMapper.updateOrderDetail(orderDetail);
    }

    @Override
    public void cleanCacheByOrderCode(String orderCode, String transactionCode) {
        logger.debug("清除订单缓存 orderCode:{}, transactionCode:{}", orderCode, transactionCode);
        List<String> keys = Lists.newArrayList();
        if (StringUtils.isNotBlank(orderCode)) {
            keys.add(CacheConstants.GET_ORDER_INFO_BY_ORDER_CODE + orderCode);
        }
        if (StringUtils.isNotBlank(transactionCode)) {
            keys.add(CacheConstants.GET_ORDER_INFO_BY_TRANSACTION_CODE + transactionCode);
        }
        if (CollectionUtils.isNotEmpty(keys)) {
            redisCache.deleteObject(keys);
        }
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteOrderBasicInfoByIds(Long[] ids) {
        orderBasicInfoMapper.deleteOrderDetailByOrderCodes(ids);
        return orderBasicInfoMapper.deleteOrderBasicInfoByIds(ids);
    }

    /**
     * 通过订单号查询订单信息
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderBasicInfo getOrderInfoByOrderCode(String orderCode) {
        // 如果orderCode是00000000000000000000000000000000，直接返回null
        if (StringUtils.equals(Constants.ILLEGAL_TRANSACTION_CODE, orderCode)) {
            return null;
        }
        String redisKey = CacheConstants.GET_ORDER_INFO_BY_ORDER_CODE + orderCode;
        OrderBasicInfo orderBasicInfo = redisCache.getCacheObject(redisKey);
        if (orderBasicInfo == null) {
            // 查数据库
            orderBasicInfo = orderBasicInfoMapper.getOrderInfoByOrderCode(orderCode);
            // 放缓存
            if (orderBasicInfo != null) {
                redisCache.setCacheObject(redisKey, orderBasicInfo, 5, TimeUnit.MINUTES);
            }
        }
        logger.info("通过订单号:{}, 查询订单信息:{}", orderCode, JSON.toJSONString(orderBasicInfo));
        return orderBasicInfo;
    }

    @Override
    public OrderBasicInfo getOrderInfoByTransactionCode(String transactionCode) {
        if (StringUtils.equals(Constants.ILLEGAL_TRANSACTION_CODE, transactionCode)) {
            return null;
        }
        String redisKey = CacheConstants.GET_ORDER_INFO_BY_TRANSACTION_CODE + transactionCode;
        OrderBasicInfo orderBasicInfo = redisCache.getCacheObject(redisKey);
        if (orderBasicInfo == null) {
            // 查数据库
            orderBasicInfo = orderBasicInfoMapper.getOrderInfoByTransactionCode(transactionCode);
            // 放缓存
            if (orderBasicInfo != null) {
                redisCache.setCacheObject(redisKey, orderBasicInfo, 5, TimeUnit.MINUTES);
            }
        }
        logger.info("通过交易流水号:{}, 查询订单信息:{}", transactionCode, JSON.toJSONString(orderBasicInfo));
        return orderBasicInfo;
    }

    /**
     * 根据充电桩编号和枪口号查询正在充电中的订单
     *
     * @param pileSn        桩编号
     * @param connectorCode 枪口号
     * @return
     */
    @Override
    public OrderBasicInfo queryChargingByPileSnAndConnectorCode(String pileSn, String connectorCode) {
        return orderBasicInfoMapper.queryOrderBasicInfo(pileSn, connectorCode, OrderStatusEnum.IN_THE_CHARGING.getValue());
    }

    /**
     * 根据枪口编号查询正在充电中的订单
     *
     * @param pileConnectorCode
     * @return
     */
    @Override
    public OrderBasicInfo queryChargingByPileConnectorCode(String pileConnectorCode) {
        if (StringUtils.isBlank(pileConnectorCode)) {
            return null;
        }
        String pileSn = pileConnectorCode.substring(0, pileConnectorCode.length() - 2);
        String connectorCode = pileConnectorCode.substring(pileConnectorCode.length() - 2);
        return queryChargingByPileSnAndConnectorCode(pileSn, connectorCode);
    }

    /**
     * 结算订单逻辑
     *
     * @param data           交易记录数据
     * @param orderBasicInfo 订单主表信息，由调用方传过来
     */
    @Override
    public void settleOrder(TransactionRecordsData data, OrderBasicInfo orderBasicInfo) {
        logger.info("结算订单start data:{}, orderBasicInfo:{}", data.toString(), orderBasicInfo.toString());
        String orderCode = orderBasicInfo.getOrderCode();

        // 判断订单状态
        if (StringUtils.equals(orderBasicInfo.getOrderStatus(), OrderStatusEnum.ORDER_COMPLETE.getValue())) {
            logger.info("结算订单:{}, 是订单完成状态", orderCode);
            return;
        }
        // 消费金额就是订单总金额
        BigDecimal orderAmount = new BigDecimal(data.getConsumptionAmount());

        // 付款金额 - 实际消费金额，如果有剩余，需要走退款操作 当使用余额支付时payAmount = principalPay + giftPay
        BigDecimal payAmount = orderBasicInfo.getPayAmount();

        // 有时候充电桩到达金额停止充电会多出一点金额，比如实际需要充50元的电，充电桩传来的消费金额为50.01元，在后台记录的时候需要舍去
        if (orderAmount.compareTo(payAmount) > 0) {
            logger.info("结算订单:【{}】充电桩传来的消费金额:【{}】大于付款金额:【{}】, 消费金额设置为付款金额相等数据", orderBasicInfo.getOrderCode(), orderAmount, payAmount);
            orderAmount = payAmount;
        }

        // 虚拟金额 指订单消费中使用赠送金额支付的部分
        BigDecimal virtualAmount = BigDecimal.ZERO;

        // 剩余需要退回的金额 residue
        BigDecimal residue = payAmount.subtract(orderAmount);
        if (residue.compareTo(BigDecimal.ZERO) > 0) {
            // 查支付记录
            List<OrderPayRecord> payRecordList = orderPayRecordService.getOrderPayRecordList(orderBasicInfo.getOrderCode());
            // 更新订单支付记录
            List<OrderPayRecord> updatePayRecordList = Lists.newArrayList();
            // 根据支付方式不同，走不同渠道退款
            String payMode = orderBasicInfo.getPayMode();
            if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) { // 余额支付
                Map<String, OrderPayRecord> payRecordMap = payRecordList.stream()
                        .collect(Collectors.toMap(OrderPayRecord::getPayMode, Function.identity(), (k1, k2) -> k1));
                // 取出本金支付金额，赠送支付金额
                BigDecimal principalPay = null;
                BigDecimal giftPay = null;

                OrderPayRecord principalPayRecord = payRecordMap.get("1");
                if (principalPayRecord != null) {
                    principalPay = principalPayRecord.getPayAmount();
                }

                OrderPayRecord giftPayRecord = payRecordMap.get("2");
                if (giftPayRecord != null) {
                    giftPay = giftPayRecord.getPayAmount();
                }

                Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, giftPay, orderAmount);
                logger.info("结算订单:{}, 剩余金额退回余额, 订单消费金额:{}, 本金支付金额:{}, 赠送支付金额:{}, 退回金额map:{}",
                        orderCode, orderAmount, principalPay, giftPay, JSONObject.toJSONString(returnAmountMap));
                // 更新会员钱包
                BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal");
                if (returnPrincipal != null && principalPayRecord != null) {
                    principalPayRecord.setRefundAmount(returnPrincipal);
                    updatePayRecordList.add(principalPayRecord);
                }
                BigDecimal returnGift = returnAmountMap.get("returnGift");
                if (returnGift != null && giftPayRecord != null) {
                    giftPayRecord.setRefundAmount(returnGift);
                    updatePayRecordList.add(giftPayRecord);
                    // 支付的赠送金额-退回的赠送金额 = 实际使用赠送金额消费的部分
                    virtualAmount = giftPay.subtract(returnGift);
                }
                UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder()
                        .memberId(orderBasicInfo.getMemberId())
                        .type(MemberWalletEnum.TYPE_IN.getValue()) // 进账
                        .subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款
                        .updatePrincipalBalance(returnPrincipal)
                        .updateGiftBalance(returnGift)
                        .relatedOrderCode(orderBasicInfo.getOrderCode())
                        .build();
                memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);
            } else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) { // 微信支付
                // 微信退款逻辑
                WeChatRefundDTO weChatRefundDTO = new WeChatRefundDTO();
                weChatRefundDTO.setOrderCode(orderBasicInfo.getOrderCode());
                weChatRefundDTO.setRefundType("1");
                weChatRefundDTO.setRefundAmount(residue);

                // 查到该笔订单付款金额到哪里了
                MemberTransactionRecord transactionRecord = memberTransactionRecordService.selectByOrderCode(orderBasicInfo.getOrderCode());
                logger.info("查到该笔订单付款金额到哪里了:{}", JSON.toJSONString(transactionRecord));
                if (StringUtils.equals(transactionRecord.getPaymentInstitutions(), PaymentInstitutionsEnum.WECHAT_PAY.getValue())) {
                    this.weChatRefund(weChatRefundDTO);
                } else if (StringUtils.equals(transactionRecord.getPaymentInstitutions(), PaymentInstitutionsEnum.ADAPAY.getValue())) {
                    this.refundForOrderWithAdapay(weChatRefundDTO);
                }
                // 订单支付记录
                OrderPayRecord orderPayRecord = payRecordList.get(0);
                orderPayRecord.setRefundAmount(residue);
                updatePayRecordList.add(orderPayRecord);
            } else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_ALIPAY.getValue())) { // 支付宝支付
                // 支付宝退款逻辑
            } else {
                // 白名单支付
                logger.info("订单：{}使用白名单支付，不进行退款处理", orderBasicInfo.getOrderCode());
            }

            // 更新order_pay_record
            if (CollectionUtils.isNotEmpty(updatePayRecordList)) {
                for (OrderPayRecord orderPayRecord : updatePayRecordList) {
                    orderPayRecordService.updateByPrimaryKeySelective(orderPayRecord);
                }
            }
        }

        // 修改订单数据
        // 查询订单详情
        OrderDetail orderDetail = getOrderDetailByOrderCode(orderBasicInfo.getOrderCode());

        // 把交易记录中的用电量，金额等信息 更新到orderBasicInfo和orderDetail
        orderBasicInfo.setOrderAmount(orderAmount); // 订单总金额
        orderBasicInfo.setVirtualAmount(virtualAmount); // 虚拟金额
        orderBasicInfo.setSettleAmount(orderAmount.subtract(virtualAmount)); // 结算金额
        orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
        orderBasicInfo.setReason(data.getStopReasonMsg()); // 充电停止原因
        orderBasicInfo.setSettlementTime(DateUtils.getNowDate()); // 结算时间
        orderBasicInfo.setRefundAmount(residue); // 结算退款金额

        // 更新订单详情
        try {
            // 总电费金额
            BigDecimal totalElectricityAmount = BigDecimal.ZERO;

            // 尖时段用电量
            String sharpUsedElectricity = data.getSharpUsedElectricity();
            if (sharpUsedElectricity != null) {
                orderDetail.setSharpUsedElectricity(new BigDecimal(sharpUsedElectricity));
                if (data.getSharpPrice() != null) {
                    orderDetail.setSharpPrice(new BigDecimal(data.getSharpPrice()));
                }
                if (data.getSharpAmount() != null) {
                    orderDetail.setSharpAmount(new BigDecimal(data.getSharpAmount()));
                }
                // 计算该时段电费
                BigDecimal multiply = orderDetail.getSharpElectricityPrice().multiply(new BigDecimal(sharpUsedElectricity)).setScale(2, BigDecimal.ROUND_DOWN);
                totalElectricityAmount = totalElectricityAmount.add(multiply);
            }

            // 峰时段用电量
            String peakUsedElectricity = data.getPeakUsedElectricity();
            if (peakUsedElectricity != null) {
                orderDetail.setPeakUsedElectricity(new BigDecimal(peakUsedElectricity));
                if (data.getPeakPrice() != null) {
                    orderDetail.setPeakPrice(new BigDecimal(data.getPeakPrice()));
                }
                if (data.getPeakAmount() != null) {
                    orderDetail.setPeakAmount(new BigDecimal(data.getPeakAmount()));
                }
                // 计算该时段电费
                BigDecimal multiply = orderDetail.getPeakElectricityPrice().multiply(new BigDecimal(peakUsedElectricity)).setScale(2, BigDecimal.ROUND_DOWN);
                totalElectricityAmount = totalElectricityAmount.add(multiply);
            }

            // 平时段用电量
            String flatUsedElectricity = data.getFlatUsedElectricity();
            if (flatUsedElectricity != null) {
                orderDetail.setFlatUsedElectricity(new BigDecimal(flatUsedElectricity));
                if (data.getFlatPrice() != null) {
                    orderDetail.setFlatPrice(new BigDecimal(data.getFlatPrice()));
                }
                if (data.getFlatAmount() != null) {
                    orderDetail.setFlatAmount(new BigDecimal(data.getFlatAmount()));
                }
                // 计算该时段电费
                BigDecimal multiply = orderDetail.getFlatElectricityPrice().multiply(new BigDecimal(flatUsedElectricity)).setScale(2, BigDecimal.ROUND_DOWN);
                totalElectricityAmount = totalElectricityAmount.add(multiply);
            }

            // 谷时段用电量
            String valleyUsedElectricity = data.getValleyUsedElectricity();
            if (valleyUsedElectricity != null) {
                orderDetail.setValleyUsedElectricity(new BigDecimal(valleyUsedElectricity));
                if (data.getValleyPrice() != null) {
                    orderDetail.setValleyPrice(new BigDecimal(data.getValleyPrice()));
                }
                if (data.getValleyAmount() != null) {
                    orderDetail.setValleyAmount(new BigDecimal(data.getValleyAmount()));
                }
                // 计算该时段电费
                BigDecimal multiply = orderDetail.getValleyElectricityPrice().multiply(new BigDecimal(valleyUsedElectricity)).setScale(2, BigDecimal.ROUND_DOWN);
                totalElectricityAmount = totalElectricityAmount.add(multiply);
            }

            // 如果算出来的电费金额大于总消费金额，则电费金额等于总消费金额
            if (totalElectricityAmount.compareTo(orderAmount) > 0) {
                totalElectricityAmount = orderAmount;
            }
            orderDetail.setTotalElectricityAmount(totalElectricityAmount);
            orderDetail.setTotalServiceAmount(orderAmount.subtract(totalElectricityAmount));
            orderDetail.setTotalUsedElectricity(new BigDecimal(data.getTotalElectricity())); // 总用电量
            orderDetail.setTotalOrderAmount(orderAmount); // 订单总金额
        } catch (Exception e) {
            logger.error("设置订单详情参数发生异常", e);
        }

        OrderTransactionDTO dto = new OrderTransactionDTO();
        dto.setOrderBasicInfo(orderBasicInfo);
        dto.setOrderDetail(orderDetail);
        transactionService.doUpdateOrder(dto);
        logger.info("结算订单 end OrderTransactionDTO:{}", JSONObject.toJSONString(dto));

        try {
            // uniApp 发送停止充电订阅消息
            WechatSendMsgDTO wechatSendMsgDTO = new WechatSendMsgDTO();
            wechatSendMsgDTO.setOrderCode(orderBasicInfo.getOrderCode());
            Map<String, String> resultMap = wxAppletRemoteService.stopChargingSendMsg(wechatSendMsgDTO);
            logger.info("小程序发送充电停止推送消息 result:{}", JSON.toJSONString(resultMap));
        } catch (Exception e) {
            logger.error("小程序发送充电停止推送消息 error", e);
        }

        try {
            realTimeMonitorDataRedis2DB(orderBasicInfo.getTransactionCode(), orderBasicInfo.getOrderCode());
        } catch (Exception e) {
            logger.error("redis中取出实时记录保存到表 发生异常", e);
        }

    }

    /**
     * 临时订单退款
     */
    @Override
    public void tempOrderRefund() {
        // 查询出2023-05-29 12:00:00到2023-05-30 23:59:59中使用微信支付，并且有退款金额的订单
        String startTime = "2023-05-29 12:00:00";
        String endTime = "2023-05-30 23:59:59";
        List<OrderBasicInfo> orderList = orderBasicInfoMapper.tempQueryWeChatRefundOrders(startTime, endTime);
        Map<String, OrderBasicInfo> orderBasicInfoMap = orderList.stream().collect(Collectors.toMap(OrderBasicInfo::getOrderCode, Function.identity(), (k1, k2) -> k1));
        Set<String> orderCodes = orderBasicInfoMap.keySet();

        // 根据上面的订单号，查微信退款回调，找出没有记录的订单，重新发起一遍退款
        List<WxpayRefundCallback> wxpayRefundCallbacks = wxpayRefundCallbackService.selectByOrderCodeList(Lists.newArrayList(orderCodes));
        Set<String> refundOrders = wxpayRefundCallbacks.stream().map(WxpayRefundCallback::getOrderCode).collect(Collectors.toSet());

        // orderCodeList   refundOrders 取差集
        Sets.SetView<String> difference = Sets.difference(orderCodes, refundOrders);
        for (String orderCode : difference) {
            OrderBasicInfo orderBasicInfo = orderBasicInfoMap.get(orderCode);
            if (orderBasicInfo == null) {
                continue;
            }
            BigDecimal refundAmount = orderBasicInfo.getRefundAmount();
            // 微信退款逻辑
            WeChatRefundDTO weChatRefundDTO = new WeChatRefundDTO();
            weChatRefundDTO.setOrderCode(orderBasicInfo.getOrderCode());
            weChatRefundDTO.setRefundType("1");
            weChatRefundDTO.setRefundAmount(refundAmount);
            try {
                this.weChatRefund(weChatRefundDTO);
            } catch (Exception e) {
                logger.error("临时订单退款接口发生异常 orderCode:{}", orderBasicInfo.getOrderCode(), e);
            }
        }
    }

    /**
     * 从redis中取出实时记录保存到表中j
     * 当订单完成的时候调用
     */
    @Override
    public void realTimeMonitorDataRedis2DB(String transactionCode, String orderCode) {
        if (StringUtils.isBlank(transactionCode) || StringUtils.isBlank(orderCode)) {
            return;
        }
        // 校验有没有保存过
        OrderMonitorData orderMonitorData = orderMonitorDataService.selectByOrderCode(orderCode);
        if (orderMonitorData != null) {
            return;
        }
        List<RealTimeMonitorData> chargingRealTimeData = getChargingRealTimeData(transactionCode);
        if (CollectionUtils.isEmpty(chargingRealTimeData)) {
            return;
        }
        List<RealTimeMonitorData> list = Lists.newArrayList();
        for (RealTimeMonitorData data : chargingRealTimeData) {
            RealTimeMonitorData build = RealTimeMonitorData.builder()
                    .outputCurrent(data.getOutputCurrent())
                    .outputCurrent(data.getOutputCurrent()) // 电流
                    .outputVoltage(data.getOutputVoltage()) // 电压
                    .outputPower(data.getOutputPower())  // 功率
                    .SOC(data.getSOC()) // soc
                    .dateTime(data.getDateTime())  // 时间
                    .batteryMaxTemperature(data.getBatteryMaxTemperature())
                    .chargingAmount(data.getChargingAmount())
                    .chargingDegree(data.getChargingDegree())
                    .sumChargingTime(data.getSumChargingTime())
                    .timeRemaining(data.getTimeRemaining())
                    .gunLineTemperature(data.getGunLineTemperature())
                    .build();
            list.add(build);
        }

        OrderMonitorData record = new OrderMonitorData();
        record.setOrderCode(orderCode);
        record.setTransactionCode(transactionCode);
        record.setMonitorData(JSONObject.toJSONString(list));
        int insert = orderMonitorDataService.insertSelective(record);
        if (insert > 0) {
            // 删除redis中缓存
            String pileConnectorCode = transactionCode.substring(0, 16);
            String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + pileConnectorCode + "_" + transactionCode;
            redisCache.deleteObject(redisKey);
        }

    }

    @Override
    public void updateElecAmount() {
        // 查询 elecAmount为空的订单数据
        int pageNum = 1;
        int pageSize = 500;

        int total = 0;
        int batch = 1;
        while (true) {
            // 分页处理
            PageHelper.startPage(pageNum, pageSize);
            List<OrderDetail> list = orderBasicInfoMapper.queryElecAmountNullList();
            PageInfo<OrderDetail> pageInfo = new PageInfo<>(list);
            if (CollectionUtils.isEmpty(pageInfo.getList())) {
                break;
            }

            // 计算电量总金额
            List<OrderDetail> orderDetailList = calculateData(pageInfo.getList());

            // 更新数据库
            int i = orderBasicInfoMapper.batchUpdateOrderDetail(orderDetailList);
            total += i;
            logger.info("updateElecAmount==第{}批次更新完成", batch);
            batch += 1;
        }
        logger.info("updateElecAmount==共更新{}条数据", total);
    }

    // 计算数据
    private List<OrderDetail> calculateData(List<OrderDetail> list) {
        for (OrderDetail orderDetail : list) {
            try {
                // 总电费金额
                BigDecimal totalElectricityAmount = BigDecimal.ZERO;

                // 尖时段用电量
                BigDecimal sharpUsedElectricity = orderDetail.getSharpUsedElectricity();
                if (sharpUsedElectricity != null) {
                    // 计算该时段电费
                    BigDecimal multiply = orderDetail.getSharpElectricityPrice().multiply(sharpUsedElectricity).setScale(2, BigDecimal.ROUND_DOWN);
                    totalElectricityAmount = totalElectricityAmount.add(multiply);
                }

                // 峰时段用电量
                BigDecimal peakUsedElectricity = orderDetail.getPeakUsedElectricity();
                if (peakUsedElectricity != null) {
                    // 计算该时段电费
                    BigDecimal multiply = orderDetail.getPeakElectricityPrice().multiply(peakUsedElectricity).setScale(2, BigDecimal.ROUND_DOWN);
                    totalElectricityAmount = totalElectricityAmount.add(multiply);
                }

                // 平时段用电量
                BigDecimal flatUsedElectricity = orderDetail.getFlatUsedElectricity();
                if (flatUsedElectricity != null) {
                    // 计算该时段电费
                    BigDecimal multiply = orderDetail.getFlatElectricityPrice().multiply(flatUsedElectricity).setScale(2, BigDecimal.ROUND_DOWN);
                    totalElectricityAmount = totalElectricityAmount.add(multiply);
                }

                // 谷时段用电量
                BigDecimal valleyUsedElectricity = orderDetail.getValleyUsedElectricity();
                if (valleyUsedElectricity != null) {
                    // 计算该时段电费
                    BigDecimal multiply = orderDetail.getValleyElectricityPrice().multiply(valleyUsedElectricity).setScale(2, BigDecimal.ROUND_DOWN);
                    totalElectricityAmount = totalElectricityAmount.add(multiply);
                }

                orderDetail.setTotalElectricityAmount(totalElectricityAmount);
                orderDetail.setTotalServiceAmount(orderDetail.getTotalOrderAmount().subtract(totalElectricityAmount));
            } catch (Exception e) {
                logger.info("发生异常", e);
            }
        }
        return list;
    }

    /**
     * 余额支付 计算需要退回的金额
     *
     * @param principalPay
     * @param giftPay
     * @param orderAmount
     * @return
     */
    private Map<String, BigDecimal> calculateReturnAmount(BigDecimal principalPay, BigDecimal giftPay, BigDecimal orderAmount) {
        Map<String, BigDecimal> resultMap = Maps.newHashMap();

        // 消费金额优先使用本金
        BigDecimal returnPrincipal = null; // 退回本金金额
        BigDecimal returnGift = null; // 退回赠送金额

        // 余额支付 有3种情况
        if (principalPay != null && giftPay == null) {
            // 只有本金支付
            BigDecimal subtract = principalPay.subtract(orderAmount);
            if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                returnPrincipal = subtract;
            }
        }
        if (principalPay == null && giftPay != null) {
            // 只有赠送金额支付
            BigDecimal subtract = giftPay.subtract(orderAmount);
            if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                returnGift = subtract;
            }
        }
        if (principalPay != null && giftPay != null) {
            // 本金+赠送支付
            BigDecimal subtract = principalPay.subtract(orderAmount);
            if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                // 本金减掉订单金额后还有剩余，那就把剩余的退回，赠送原封不动退回
                returnPrincipal = subtract;
                returnGift = giftPay;
            } else if (subtract.compareTo(BigDecimal.ZERO) == 0) {
                // 本金刚好够，那赠送金额支付的原封不动退回
                returnGift = giftPay;
            } else {
                returnGift = giftPay.subtract(subtract.negate());
            }
        }

        resultMap.put("returnPrincipal", returnPrincipal);
        resultMap.put("returnGift", returnGift);
        return resultMap;
    }

    /**
     * 结算订单退款和用户余额退款调这个方法
     *
     * @param dto
     */
    @Override
    public void weChatRefund(WeChatRefundDTO dto) {
        // 退款有两种情况 1-订单结算退款  2-用户余额退款
        String refundType = dto.getRefundType();
        if (StringUtils.equals(refundType, "1")) {
            WechatPayRefundResponse response = refundForOrder(dto);
            logger.info("订单结算退款 result:{}", JSONObject.toJSONString(response));
        } else if (StringUtils.equals(refundType, "2")) {
            WechatPayRefundResponse response = refundForBalance(dto);
            logger.info("用户余额退款 result:{}", JSONObject.toJSONString(response));
        } else {
            logger.warn("没有找到退款处理逻辑");
        }
    }

    @Override
    public void saveAbnormalOrder(TransactionRecordsData data) {
        OrderAbnormalRecord record = new OrderAbnormalRecord();
        BeanUtils.copyBeanProp(record, data);
        orderAbnormalRecordService.insertOrderAbnormalRecord(record);

        // 保存到订单主表
        // 订单基本信息
        PileInfoVO pileInfoVO = pileBasicInfoService.selectPileInfoBySn(data.getPileSn());
        if (pileInfoVO == null) {
            return;
        }
        String orderCode = IdUtils.getOrderCode();
        OrderBasicInfo orderBasicInfo = OrderBasicInfo.builder().build();
        // 订单编号
        orderBasicInfo.setOrderCode(orderCode);
        // 交易流水号
        orderBasicInfo.setTransactionCode(data.getTransactionCode());
        // 站点id
        orderBasicInfo.setStationId(pileInfoVO.getStationId());
        // 充电桩编号
        orderBasicInfo.setPileSn(data.getPileSn());
        // 枪口号
        orderBasicInfo.setConnectorCode(data.getConnectorCode());
        // 枪口编号
        orderBasicInfo.setPileConnectorCode(pileInfoVO.getPileSn() + data.getConnectorCode());
        // 启动方式
        String transactionIdentifier = data.getTransactionIdentifier();
        String startMode = null;
        // if (StringUtils.equals(transactionIdentifier, "01")) {
        // 	startMode = StartModeEnum.APP.getValue();
        // } else if (StringUtils.equals(transactionIdentifier, "02")) {
        // 	// 卡启动
        // 	startMode = StartModeEnum.CARD.getValue();
        // }
        // 卡号
        if (StringUtils.isNotBlank(data.getLogicCard())) {
            startMode = StartModeEnum.OFFLINE_CARD.getValue();
            orderBasicInfo.setLogicCard(data.getLogicCard());
            // 订单状态 (2023.4.6 要求改成“订单完成”)
            orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
        } else {
            // 订单状态 可疑
            orderBasicInfo.setOrderStatus(OrderStatusEnum.SUSPICIOUS.getValue());
        }
        orderBasicInfo.setStartMode(startMode);
        // 支付方式
        orderBasicInfo.setPayMode(null);
        // 支付金额
        orderBasicInfo.setPayAmount(null);
        // 支付状态
        orderBasicInfo.setPayStatus(null);
        // 支付时间
        orderBasicInfo.setPayTime(null);
        // 订单金额
        orderBasicInfo.setOrderAmount(new BigDecimal(data.getConsumptionAmount()));
        // 虚拟金额
        orderBasicInfo.setVirtualAmount(new BigDecimal(data.getConsumptionAmount()));
        // 结算金额
        orderBasicInfo.setSettleAmount(BigDecimal.ZERO);
        // 充电开始时间
        orderBasicInfo.setChargeStartTime(DateUtils.parseDate(data.getStartTime()));
        // 充电结束时间
        orderBasicInfo.setChargeEndTime(DateUtils.parseDate(data.getEndTime()));
        // 停止原因
        orderBasicInfo.setReason(data.getStopReasonMsg());
        // 结算时间
        orderBasicInfo.setSettlementTime(DateUtils.getNowDate());
        // 创建人
        orderBasicInfo.setCreateBy(data.getLogicCard());


        // 订单详情
        OrderDetail orderDetail = OrderDetail.builder().build();
        // 订单编号
        orderDetail.setOrderCode(orderCode);
        // 订单总金额
        orderDetail.setTotalOrderAmount(new BigDecimal(data.getConsumptionAmount()));
        // 总用电量
        orderDetail.setTotalUsedElectricity(new BigDecimal(data.getTotalElectricity()));
        // 总服务费金额
        // orderDetail.setTotalServiceAmount();
        // 总电费金额
        // orderDetail.setTotalElectricityAmount();

        // 尖时段金额
        orderDetail.setSharpAmount(new BigDecimal(data.getSharpAmount()));
        // 尖时段单价
        orderDetail.setSharpPrice(new BigDecimal(data.getSharpPrice()));
        // 尖时段服务费单价
        // orderDetail.setSharpServicePrice();
        // 尖时段电费单价
        // orderDetail.setSharpElectricityPrice();
        // 尖时段用电量
        orderDetail.setSharpUsedElectricity(new BigDecimal(data.getSharpUsedElectricity()));

        // 峰时段金额
        orderDetail.setPeakAmount(new BigDecimal(data.getPeakAmount()));
        // 峰时段单价
        orderDetail.setPeakPrice(new BigDecimal(data.getPeakPrice()));
        // 峰时段服务费单价
        // orderDetail.setPeakServicePrice();
        // 峰时段电费单价
        // orderDetail.setPeakElectricityPrice();
        // 峰时段用电量
        orderDetail.setPeakUsedElectricity(new BigDecimal(data.getPeakUsedElectricity()));

        // 平时段金额
        orderDetail.setFlatAmount(new BigDecimal(data.getFlatAmount()));
        // 平时段单价
        orderDetail.setFlatPrice(new BigDecimal(data.getFlatPrice()));
        // 平时段服务费单价
        // orderDetail.setFlatServicePrice();
        // 平时段电费单价
        // orderDetail.setFlatElectricityPrice();
        // 平时段用电量
        orderDetail.setFlatUsedElectricity(new BigDecimal(data.getFlatUsedElectricity()));

        // 谷时段金额
        orderDetail.setValleyAmount(new BigDecimal(data.getValleyAmount()));
        // 谷时段单价
        orderDetail.setValleyPrice(new BigDecimal(data.getValleyPrice()));
        // 谷时段服务费单价
        // orderDetail.setValleyServicePrice();
        // 谷时段电费单价
        // orderDetail.setValleyElectricityPrice();
        // 谷时段用电量
        orderDetail.setValleyUsedElectricity(new BigDecimal(data.getValleyUsedElectricity()));

        if (data.getCreateTime() != null) {
            orderBasicInfo.setCreateTime(data.getCreateTime());
            orderDetail.setCreateTime(data.getCreateTime());
        }

        OrderTransactionDTO createOrderTransactionDTO = OrderTransactionDTO.builder()
                .orderBasicInfo(orderBasicInfo)
                .orderDetail(orderDetail)
                .build();
        pileTransactionService.doCreateOrder(createOrderTransactionDTO);
    }

    /**
     * 根据订单编号获取充电实时数据 时间倒序
     * 订单只有在充电中，才会把实时数据保存到redis
     *
     * @param transactionCode 订单编号
     * @return
     */
    @Override
    public List<RealTimeMonitorData> getChargingRealTimeData(String transactionCode) {
        List<RealTimeMonitorData> resultList = Lists.newArrayList();
        if (StringUtils.isBlank(transactionCode)) {
            return resultList;
        }
        String pileConnectorCode = transactionCode.substring(0, 16);
        String redisKey = CacheConstants.PILE_REAL_TIME_MONITOR_DATA + pileConnectorCode + "_" + transactionCode;
        // 拿到所有数据
        Map<Object, Object> map = redisCache.hmget(redisKey);
        if (map != null && !map.isEmpty()) {
            List<String> keyList = map.keySet().stream()
                    .map(x -> (String) x)
                    .sorted(Comparator.reverseOrder()) // 对keyList排序 时间倒序
                    .collect(Collectors.toList());
            for (String s : keyList) {
                Object o = map.get(s);
                RealTimeMonitorData data = JSONObject.parseObject((String) o, RealTimeMonitorData.class);
                resultList.add(data);
            }
        } else {
            logger.debug("redis中没有实时数据了，去数据库查");
            // redis中为空，去查库
            OrderMonitorData orderMonitorData = orderMonitorDataService.selectByTransactionCode(transactionCode);
            if (orderMonitorData != null) {
                String monitorData = orderMonitorData.getMonitorData();
                List<RealTimeMonitorData> dataList = JSON.parseArray(monitorData, RealTimeMonitorData.class);
                resultList.addAll(dataList);
            }
        }
        return resultList;
    }

    /**
     * 首页订单数据展示
     *
     * @param dto 首页信息查询dto
     * @return
     */
    @Override
    public List<IndexOrderInfoVO> getIndexOrderInfo(IndexQueryDTO dto) {
        AuthorizedDeptVO authorizedMap = SecurityUtils.getAuthorizedMap();
        if (authorizedMap == null) {
            return Lists.newArrayList();
        }
        List<String> stationIdList = Lists.newArrayList();
        List<String> stationDeptIds = authorizedMap.getStationDeptIds();
        if (CollectionUtils.isNotEmpty(stationDeptIds)) {
            // 根据部门id查询站点id
            List<String> list = pileStationInfoService.queryByStationDeptIds(stationDeptIds);
            if (CollectionUtils.isNotEmpty(list)) {
                stationIdList.addAll(list);
            }
        }
        List<String> merchantDeptIds = authorizedMap.getMerchantDeptIds();
        if (CollectionUtils.isNotEmpty(merchantDeptIds)) {
            // 根据运营商部门id查询下面所有站点id
            List<String> list = pileMerchantInfoService.queryByMerchantDeptIds(merchantDeptIds);
            if (CollectionUtils.isNotEmpty(list)) {
                stationIdList.addAll(list);
            }
        }
        dto.setStationIdList(stationIdList);
        return orderBasicInfoMapper.getIndexOrderInfo(dto);
    }

    /**
     * 获取超过15分钟的待支付状态订单
     *
     * @return
     */
    @Override
    public List<OrderBasicInfo> getUnpaidOrderListOver15Min() {
        Date now = DateUtils.addMinute(new Date(), -15);
        String nowString = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, now);
        return orderBasicInfoMapper.getUnpaidOrderListOver15Min(nowString);
    }

    /**
     * 根据orderId批量修改订单状态
     *
     * @param orderIds
     * @param orderStatus
     */
    @Override
    public void updateOrderStatusById(List<String> orderIds, String orderStatus) {
        orderBasicInfoMapper.updateOrderStatusById(orderIds, orderStatus);
    }

    @Override
    public int close15MinutesOfUnpaidOrders() {
        List<OrderBasicInfo> orderList = getUnpaidOrderListOver15Min();
        if (CollectionUtils.isNotEmpty(orderList)) {
            List<String> orderIdList = orderList.stream()
                    .map(x -> String.valueOf(x.getId()))
                    .collect(Collectors.toList());
            // 修改订单状态
            updateOrderStatusById(orderIdList, OrderStatusEnum.ORDER_CLOSE_TIMEOUT.getValue());

            for (OrderBasicInfo orderBasicInfo : orderList) {
                this.cleanCacheByOrderCode(orderBasicInfo.getOrderCode(), orderBasicInfo.getTransactionCode());
            }
        }
        return orderList.size();
    }

    /**
     * 订单退款处理逻辑
     */
    private WechatPayRefundResponse refundForOrder(WeChatRefundDTO dto) {
        // 查出来原来的支付信息
        WxpayCallbackRecord record = wxpayCallbackRecordService.selectByOrderCode(dto.getOrderCode());
        if (Objects.isNull(record)) {
            logger.error("orderCode:{}, 订单退款处理逻辑, 查询订单微信支付记录为空!", dto.getOrderCode());
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_CALLBACK_RECORD_ERROR);
        }

        // 判断支付金额和退款金额
        int refundAmountInt = dto.getRefundAmount().multiply(new BigDecimal("100")).intValue();
        int payerTotalInt = Integer.parseInt(record.getPayerTotal());
        if (refundAmountInt > payerTotalInt) {
            logger.error("订单号:{}, 退款金额:{}(分)，大于可退金额{}(分), 抛出异常", dto.getOrderCode(), refundAmountInt, payerTotalInt);
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_AMOUNT_ERROR);
        }

        // 调微信退款接口
        WechatPayRefundRequest request = new WechatPayRefundRequest();
        request.setTransaction_id(record.getTransactionId()); // 微信支付单号
        request.setOut_trade_no(record.getOutTradeNo()); // 商户订单号
        // 生成退款单号
        request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
        request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
        WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
        amount.setRefund(refundAmountInt); // 退款金额
        amount.setTotal(payerTotalInt); // 原订单金额
        request.setAmount(amount);
        request.setReason("订单结算退款");
        request.setFunds_account("AVAILABLE");
        try {
            return wechatPayService.ApplyForWechatPayRefundV3(request);
        } catch (JsonProcessingException e) {
            logger.error("调微信退款API发生异常", e);
        }
        return null;
    }

    /**
     * 余额退款处理逻辑
     *
     * @param dto
     */
    private WechatPayRefundResponse refundForBalance(WeChatRefundDTO dto) {
        // 查会员余额
        MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(dto.getMemberId());
        if (memberVO == null) {
            throw new BusinessException(ReturnCodeEnum.CODE_SELECT_MEMBER_NULL_ERROR);
        }
        // 校验退款金额
        BigDecimal principalBalance = memberVO.getPrincipalBalance();
        BigDecimal refundAmount = dto.getRefundAmount();
        if (refundAmount.compareTo(principalBalance) > 0) {
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_MEMBER_BALANCE_ERROR);
        }
        // 退款金额 元转分 123
        int refundTotalCents = refundAmount.multiply(new BigDecimal(100)).intValue();

        // 查询用户充值余额订单 过滤掉已经退款的充值订单 refundableOrder
        List<RefundableWxPayOrderData> recordList = queryRefundableOrder(dto.getMemberId());

        // 也许需要多笔支付订单才够退款
        List<WechatPayRefundRequest> requestList = Lists.newArrayList();
        WechatPayRefundRequest request;
        for (RefundableWxPayOrderData record : recordList) {
            int refundableTotal = record.getRefundableAmount().intValue(); // 该笔支付订单的可退金额，单位分
            int payerTotal = record.getPayerAmount().intValue(); // 该笔支付订单的支付金额，单位分
            // 用户申请退款金额-可退金额
            refundTotalCents = refundTotalCents - refundableTotal; // 123 - 100
            request = new WechatPayRefundRequest();
            request.setTransaction_id(record.getTransactionId()); // 微信支付单号
            request.setOut_trade_no(record.getOutTradeNo()); // 商户订单号
            request.setOut_refund_no(SnowflakeIdWorker.getSnowflakeId()); // 商户退款单号
            request.setNotify_url(WeChatPayParameter.refundNotifyUrl); // 回调接口
            request.setReason("用户余额退款");
            request.setFunds_account("AVAILABLE");
            if (refundTotalCents > 0) {
                // 如果大于0说明，这笔单退完也不够
                WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
                amount.setRefund(refundableTotal); // 退款金额
                amount.setTotal(payerTotal); // 原订单金额
                request.setAmount(amount);
                requestList.add(request);
            } else {
                // 如果小于0，这笔单退一部分
                // 生成退款单号
                WechatPayRefundRequest.Amount amount = new WechatPayRefundRequest.Amount();
                // 部分退
                int i = refundableTotal + refundTotalCents;
                amount.setRefund(i); // 退款金额
                amount.setTotal(payerTotal); // 原订单金额
                request.setAmount(amount);
                requestList.add(request);
                break;
            }
        }
        // 调微信退款api
        if (CollectionUtils.isNotEmpty(requestList)) {
            for (WechatPayRefundRequest refundRequest : requestList) {
                try {
                    return wechatPayService.ApplyForWechatPayRefundV3(refundRequest);
                    // logger.info("调微信退款API退款====={}", JSONObject.toJSONString(refundRequest));
                } catch (Exception e) {
                    logger.error("调微信退款API发生异常", e);
                }
            }
        }
        return null;
    }

    private List<RefundableWxPayOrderData> queryRefundableOrder(String memberId) {
        List<RefundableWxPayOrderData> resultList = Lists.newArrayList();
        // 查询最近一年余额充值订单
        List<WxpayCallbackRecord> recordList = wxpayCallbackRecordService.queryBalanceRechargeRecordOfTheLatestYear(memberId);
        if (CollectionUtils.isEmpty(recordList)) {
            return resultList;
        }
        // 拿到微信商户单号list
        List<String> outTradeNoList = recordList.stream()
                .map(WxpayCallbackRecord::getOutTradeNo)
                .collect(Collectors.toList());
        List<WxpayRefundCallback> wxpayRefundCallbacks = wxpayRefundCallbackService.selectWxpayRefundCallbackList(outTradeNoList);
        if (CollectionUtils.isEmpty(wxpayRefundCallbacks)) {
            // 退款记录为空，表示没有一笔退款
            for (WxpayCallbackRecord wxpayCallbackRecord : recordList) {
                resultList.add(
                        RefundableWxPayOrderData.builder()
                                .outTradeNo(wxpayCallbackRecord.getOutTradeNo())
                                .transactionId(wxpayCallbackRecord.getTransactionId())
                                .payerAmount(new BigDecimal(wxpayCallbackRecord.getPayerTotal()))
                                .refundableAmount(new BigDecimal(wxpayCallbackRecord.getPayerTotal()))
                                .build()
                );
            }
            return resultList;
        }

        // 退款记录转map  key:outTradeNo  value:退款记录
        Map<String, List<WxpayRefundCallback>> refundMap = wxpayRefundCallbacks.stream()
                .collect(Collectors.groupingBy(WxpayRefundCallback::getOutTradeNo));
        for (WxpayCallbackRecord wxpayCallbackRecord : recordList) {
            List<WxpayRefundCallback> refundCallbackList = refundMap.get(wxpayCallbackRecord.getOutTradeNo());
            if (CollectionUtils.isEmpty(refundCallbackList)) {
                // 这笔单没有申请过退款
                resultList.add(
                        RefundableWxPayOrderData.builder()
                                .outTradeNo(wxpayCallbackRecord.getOutTradeNo())
                                .transactionId(wxpayCallbackRecord.getTransactionId())
                                .payerAmount(new BigDecimal(wxpayCallbackRecord.getPayerTotal()))
                                .refundableAmount(new BigDecimal(wxpayCallbackRecord.getPayerTotal()))
                                .build()
                );
                continue;
            }
            // 支付订单产生过退款
            BigDecimal refundTotal = refundCallbackList.stream()
                    .map(x -> new BigDecimal(x.getAmountRefund()))
                    .reduce(BigDecimal::add)
                    .get();

            // 可退金额
            BigDecimal subtract = new BigDecimal(wxpayCallbackRecord.getPayerTotal()).subtract(refundTotal);
            if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                resultList.add(
                        RefundableWxPayOrderData.builder()
                                .outTradeNo(wxpayCallbackRecord.getOutTradeNo())
                                .transactionId(wxpayCallbackRecord.getTransactionId())
                                .payerAmount(new BigDecimal(wxpayCallbackRecord.getPayerTotal()))
                                .refundableAmount(subtract)
                                .build()
                );
            }
        }
        return resultList;
    }

    /**
     * 通过订单号查询订单详情
     *
     * @param orderCode 订单号
     * @return 订单详情
     */
    @Override
    public OrderDetail getOrderDetailByOrderCode(String orderCode) {
        return orderBasicInfoMapper.getOrderDetailByOrderCode(orderCode);
    }

    @Override
    public List<OrderDetail> getOrderDetailList(List<String> orderCodes) {
        return orderBasicInfoMapper.getOrderDetailList(orderCodes);
    }

    /**
     * 通过会员Id和订单状态查询订单信息
     *
     * @param memberId        会员id
     * @param orderStatusList 订单状态集合
     * @return
     */
    @Override
    public List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList) {
        return getListByMemberIdAndOrderStatus(memberId, orderStatusList, null, null);
    }

    @Override
    public List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList, LocalDateTime dateTime) {
        return getListByMemberIdAndOrderStatus(memberId, orderStatusList, dateTime, null);
    }

    @Override
    public List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList, LocalDateTime dateTime, String stationId) {
        return orderBasicInfoMapper.getListByMemberIdAndOrderStatus(memberId, orderStatusList, dateTime, stationId);
    }

    @Override
    public List<OrderVO> getListByOrderCodes(List<String> orderCodes) {
        return orderBasicInfoMapper.getListByOrderCodes(orderCodes);
    }

    /**
     * 个人桩查询充电数据
     *
     * @param dto
     * @return
     */
    @Override
    public List<PersonPileConnectorSumInfoVO> getAccumulativeInfo(QueryPersonPileDTO dto) {
        return orderBasicInfoMapper.getAccumulativeInfo(dto);
    }

    /**
     * 修改订单状态为异常（桩离线时调用）
     *
     * @param pileSn
     */
    @Override
    public void updateOrderStatusAsAbnormal(String pileSn) {
        // 先从redis判断是否有订单再进行查询
        // if (Objects.isNull(redisCache.getCacheObject(CacheConstants.PILE_IS_CHARGING + pileSn))) {
        //     return;
        // }
        // 将此桩正在进行充电的订单状态改为 异常
        List<OrderListVO> orderListVOS = selectChargingOrder(pileSn);
        if (CollectionUtils.isEmpty(orderListVOS)) {
            return;
        }
        for (OrderListVO orderListVO : orderListVOS) {
            if (StringUtils.equals(orderListVO.getOrderStatus(), OrderStatusEnum.IN_THE_CHARGING.getValue())) {
                // 修改数据库订单状态
                OrderBasicInfo info = OrderBasicInfo.builder()
                        .id(Long.parseLong(orderListVO.getId()))
                        .orderStatus(OrderStatusEnum.ABNORMAL.getValue())
                        .build();
                updateOrderBasicInfo(info);
                logger.info("充电桩:{}退出, 修改充电桩正在充电的订单状态为异常, orderCode: {}", pileSn, orderListVO.getOrderCode());
            }
        }
    }

    @Override
    public List<OrderBasicInfo> getAppointmentOrder(LocalDateTime dateTime) {
        return orderBasicInfoMapper.getAppointmentOrder(dateTime);
    }

    /**
     * 生成订单 返回交易流水号
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> generateOrderByCard(GenerateOrderDTO dto) {
        String pileSn = dto.getPileSn();
        String connectorCode = dto.getConnectorCode();
        String startMode = dto.getStartMode();
        String logicCard = "";
        String memberId = "";
        String vinCode = "";
        PileAuthCard pileAuthCardInfo = new PileAuthCard();
        // CarVinInfoVO carVinInfoVO = new CarVinInfoVO();
        MemberPlateNumberRelation relation = new MemberPlateNumberRelation();
        if (StringUtils.equals(StartModeEnum.AUTH_CARD.getValue(), startMode)) {
            // 刷卡启动充电
            pileAuthCardInfo = dto.getPileAuthCardInfo();
            memberId = pileAuthCardInfo.getMemberId();
            logicCard = pileAuthCardInfo.getLogicCard();
        }else if (StringUtils.equals(StartModeEnum.VIN_CODE.getValue(), startMode)) {
            logger.info("车辆vin启动充电 params:{}", JSON.toJSONString(dto));
            // vin启动充电
            relation = dto.getMemberPlateNumberRelation();
            memberId = relation.getMemberId();
            vinCode = relation.getVinCode();
        }
        // 通过memberId获取账户余额
        MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId);
        if (memberVO == null) {
            throw new BusinessException(ReturnCodeEnum.CODE_GET_MEMBER_ACCOUNT_AMOUNT_ERROR);
        }
        BigDecimal totalAccountAmount = memberVO.getTotalAccountAmount();
        if (totalAccountAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(ReturnCodeEnum.CODE_BALANCE_IS_INSUFFICIENT);
        }

        String transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode);
        // 通过桩号查询所属站点
        PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
        Long stationId = pileBasicInfo.getStationId();
        // 自动余额全部支付订单  个人桩站点不计费


        // 将此订单信息存入订单表
        String orderCode = IdUtils.getOrderCode();
        // 订单基本信息
        OrderBasicInfo orderBasicInfo = OrderBasicInfo.builder()
                .orderCode(orderCode)
                .transactionCode(transactionCode)
                .orderStatus(OrderStatusEnum.NOT_START.getValue())
                .memberId(memberVO.getMemberId())
                .stationId(String.valueOf(stationId))
                .pileSn(pileSn)
                .connectorCode(connectorCode)
                .pileConnectorCode(pileSn + connectorCode)
                .logicCard(logicCard)
                .vinCode(vinCode)
                .startMode(startMode)
                .payStatus(Constants.ONE)
                .payAmount(totalAccountAmount)
                .payTime(new Date())
                .payMode(OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())
                .orderAmount(BigDecimal.ZERO)
                .virtualAmount(BigDecimal.ZERO)
                .settleAmount(BigDecimal.ZERO)
                .build();
        // 根据桩编码查询当前计费模板
        BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileSn);
        // 订单详情
        OrderDetail orderDetail = OrderDetail.builder()
                .orderCode(orderCode)
                .sharpElectricityPrice(billingTemplateVO.getSharpElectricityPrice())
                .sharpServicePrice(billingTemplateVO.getSharpServicePrice())
                .peakElectricityPrice(billingTemplateVO.getPeakElectricityPrice())
                .peakServicePrice(billingTemplateVO.getPeakServicePrice())
                .flatElectricityPrice(billingTemplateVO.getFlatElectricityPrice())
                .flatServicePrice(billingTemplateVO.getFlatServicePrice())
                .valleyElectricityPrice(billingTemplateVO.getValleyElectricityPrice())
                .valleyServicePrice(billingTemplateVO.getValleyServicePrice())
                .build();

        OrderTransactionDTO createOrderTransactionDTO = OrderTransactionDTO.builder()
                .orderBasicInfo(orderBasicInfo)
                .orderDetail(orderDetail)
                .build();
        pileTransactionService.doCreateOrder(createOrderTransactionDTO);

        if (StringUtils.equals(StartModeEnum.AUTH_CARD.getValue(), startMode)) {
            // 将卡状态改为启动锁定
            PileAuthCard pileAuthCard = PileAuthCard.builder()
                    .id(pileAuthCardInfo.getId())
                    .logicCard(pileAuthCardInfo.getLogicCard())
                    .status("2")
                    .build();
            pileAuthCardService.updatePileAuthCard(pileAuthCard);
        } else if (StringUtils.equals(StartModeEnum.VIN_CODE.getValue(), startMode)) {
            // 将vin码改成启动锁定
            relation.setVinStatus("2");
            memberPlateNumberRelationService.updateMemberPlateNumberRelation(relation);
        }

        // 组装结果集
        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.put("orderCode", orderBasicInfo.getOrderCode());
        resultMap.put("transactionCode", orderBasicInfo.getTransactionCode());
        resultMap.put("accountBalance", totalAccountAmount);

        logger.info("生成订单 result:{}", JSON.toJSONString(resultMap));
        return resultMap;
    }

    /**
     * 联联平台 获取累计数据用
     *
     * @param dto
     * @return
     */
    @Override
    public List<AccumulativeInfoVO> getAccumulativeInfoForLianLian(QueryStationInfoDTO dto) {
        return orderBasicInfoMapper.getAccumulativeInfoForLianLian(dto);
    }

    /**
     * 联联平台生成订单
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> generateOrderForLianLian(QueryStartChargeDTO dto) {
        // 联联平台生成订单
        String orderCode = dto.getStartChargeSeq();
        String pileConnectorCode = dto.getConnectorID();
        String pileSn = StringUtils.substring(pileConnectorCode, 0, 14);
        String connectorCode = StringUtils.substring(pileConnectorCode, 14, 16);

        String transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode);

        // 通过桩号查询所属站点
        PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
        Long stationId = pileBasicInfo.getStationId();

        // 将此订单信息存入订单表
        // 订单基本信息
        OrderBasicInfo orderBasicInfo = OrderBasicInfo.builder()
                .orderCode(orderCode)
                .transactionCode(transactionCode)
                .orderStatus(OrderStatusEnum.NOT_START.getValue())
                // .memberId(memberVO.getMemberId())  // 会员memberId
                .stationId(String.valueOf(stationId))
                .pileSn(pileSn)
                .connectorCode(connectorCode)
                .pileConnectorCode(pileConnectorCode)
                // .logicCard(pileAuthCardInfo.getLogicCard())  // 卡号
                .startMode(StartModeEnum.LIAN_LIAN.getValue())
                .payStatus(Constants.ONE)
                .payAmount(new BigDecimal("500"))  // 支付金额 2023.05.31：联联平台不会传金额，所以先给500，默认是直到充满
                .payTime(new Date())
                // .payMode(PayModeEnum.PAYMENT_OF_BALANCE.getValue())  // 支付方式
                .orderAmount(BigDecimal.ZERO)
                .build();
        // 根据桩编码查询当前计费模板
        BillingTemplateVO billingTemplateVO = pileBillingTemplateService.selectBillingTemplateDetailByPileSn(pileSn);
        // 订单详情
        OrderDetail orderDetail = OrderDetail.builder()
                .orderCode(orderCode)
                .sharpElectricityPrice(billingTemplateVO.getSharpElectricityPrice())
                .sharpServicePrice(billingTemplateVO.getSharpServicePrice())
                .peakElectricityPrice(billingTemplateVO.getPeakElectricityPrice())
                .peakServicePrice(billingTemplateVO.getPeakServicePrice())
                .flatElectricityPrice(billingTemplateVO.getFlatElectricityPrice())
                .flatServicePrice(billingTemplateVO.getFlatServicePrice())
                .valleyElectricityPrice(billingTemplateVO.getValleyElectricityPrice())
                .valleyServicePrice(billingTemplateVO.getValleyServicePrice())
                .build();

        OrderTransactionDTO createOrderTransactionDTO = OrderTransactionDTO.builder()
                .orderBasicInfo(orderBasicInfo)
                .orderDetail(orderDetail)
                .build();
        pileTransactionService.doCreateOrder(createOrderTransactionDTO);

        // 组装结果集
        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.put("orderCode", orderBasicInfo.getOrderCode());
        resultMap.put("transactionCode", orderBasicInfo.getTransactionCode());
        resultMap.put("orderBasicInfo", orderBasicInfo);
        resultMap.put("orderDetail", orderDetail);
        // resultMap.put("accountBalance", totalAccountAmount);

        return resultMap;
    }

    @Override
    public List<OrderAmountDetailVO> queryOrderAmountDetail(List<String> orderCodes) {
        List<OrderDetail> orderDetailList = getOrderDetailList(orderCodes);
        if (CollectionUtils.isEmpty(orderDetailList)) {
            return Lists.newArrayList();
        }
        List<OrderAmountDetailVO> resultList = Lists.newArrayList();
        OrderAmountDetailVO vo = null;
        for (OrderDetail orderDetail : orderDetailList) {
            vo = new OrderAmountDetailVO();
            BeanUtils.copyBeanProp(vo, orderDetail);
            resultList.add(vo);
        }
        return resultList;
    }

    /**
     * 订单详情 转换为各个时段的详情
     */
    @Override
    public List<OrderPeriodAmountVO> transformPeriodAmountByOrderDetail(OrderDetail orderDetail) {
        // 尖时段
        OrderPeriodAmountVO sharp = new OrderPeriodAmountVO();
        sharp.setPeriodType(BillingTimeEnum.SHARP.getLabel());
        sharp.setElectricityPrice(orderDetail.getSharpElectricityPrice());
        sharp.setServicePrice(orderDetail.getSharpServicePrice());
        BigDecimal sharpUsedElectricity = orderDetail.getSharpUsedElectricity() == null ? BigDecimal.ZERO : orderDetail.getSharpUsedElectricity();
        sharp.setUsedElectricity(sharpUsedElectricity);
        sharp.setElectricityAmount(sharp.getElectricityPrice().multiply(sharp.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));
        sharp.setServiceAmount(sharp.getServicePrice().multiply(sharp.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));

        // 峰时段
        OrderPeriodAmountVO peak = new OrderPeriodAmountVO();
        peak.setPeriodType(BillingTimeEnum.PEAK.getLabel());
        peak.setElectricityPrice(orderDetail.getPeakElectricityPrice());
        peak.setServicePrice(orderDetail.getPeakServicePrice());
        BigDecimal peakUsedElectricity = orderDetail.getPeakUsedElectricity() == null ? BigDecimal.ZERO : orderDetail.getPeakUsedElectricity();
        peak.setUsedElectricity(peakUsedElectricity);
        peak.setElectricityAmount(peak.getElectricityPrice().multiply(peak.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));
        peak.setServiceAmount(peak.getServicePrice().multiply(peak.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));

        // 平时段
        OrderPeriodAmountVO flat = new OrderPeriodAmountVO();
        flat.setPeriodType(BillingTimeEnum.FLAT.getLabel());
        flat.setElectricityPrice(orderDetail.getFlatElectricityPrice());
        flat.setServicePrice(orderDetail.getFlatServicePrice());
        BigDecimal flatUsedElectricity = orderDetail.getFlatUsedElectricity() == null ? BigDecimal.ZERO : orderDetail.getFlatUsedElectricity();
        flat.setUsedElectricity(flatUsedElectricity);
        flat.setElectricityAmount(flat.getElectricityPrice().multiply(flat.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));
        flat.setServiceAmount(flat.getServicePrice().multiply(flat.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));

        // 谷时段
        OrderPeriodAmountVO valley = new OrderPeriodAmountVO();
        valley.setPeriodType(BillingTimeEnum.VALLEY.getLabel());
        valley.setElectricityPrice(orderDetail.getValleyElectricityPrice());
        valley.setServicePrice(orderDetail.getValleyServicePrice());
        BigDecimal valleyUsedElectricity = orderDetail.getValleyUsedElectricity() == null ? BigDecimal.ZERO : orderDetail.getValleyUsedElectricity();
        valley.setUsedElectricity(valleyUsedElectricity);
        valley.setElectricityAmount(valley.getElectricityPrice().multiply(valley.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));
        valley.setServiceAmount(valley.getServicePrice().multiply(valley.getUsedElectricity()).setScale(2, BigDecimal.ROUND_DOWN));

        return Lists.newArrayList(sharp, peak, flat, valley);
    }

    @Override
    public String tempUpdateVirtualAmount(QueryOrderDTO dto) {
        dto.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue());
        List<OrderListVO> orderListVOS = orderBasicInfoMapper.selectOrderBasicInfoList(dto);
        if (CollectionUtils.isEmpty(orderListVOS)) {
            return "没有订单需要修改";
        }
        int i = 0;
        for (OrderListVO orderListVO : orderListVOS) {
            try {
                tempUpdateVirtualAmount(orderListVO);
                i += 1;
            } catch (Exception e) {
                logger.error("修改虚拟金额字段失败", e);
            }
        }
        return "共查询到" + orderListVOS.size() + "条订单，修改成功" + i + "条订单数据";
    }

    @Override
    public void refundForOrderWithAdapay(WeChatRefundDTO dto) {
        logger.info("汇付支付订单:{}, 执行退款逻辑 param:{}", dto.getOrderCode(), JSON.toJSONString(dto));
        // 查出来原来的支付信息
        AdapayCallbackRecord record = adapayCallbackRecordService.selectByOrderCode(dto.getOrderCode());
        if (Objects.isNull(record)) {
            logger.error("汇付支付orderCode:{}, 订单退款处理逻辑, 查询订单微信支付记录为空!", dto.getOrderCode());
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_CALLBACK_RECORD_ERROR);
        }

        // 判断支付金额和退款金额
        BigDecimal refundAmount = dto.getRefundAmount();
        BigDecimal payAmt = record.getPayAmt();
        if (refundAmount.compareTo(payAmt) > 0) {
            logger.error("汇付支付订单号:{}, 退款金额:{}(元)，大于可退金额{}(元), 抛出异常", dto.getOrderCode(), refundAmount, payAmt);
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_ORDER_AMOUNT_ERROR);
        }

        // 创建汇付退款对象 在完成初始化设置情况下，调用方法，获取 Refund对象
        String id = record.getPaymentId();
        Map<String, Object> refundParams = Maps.newHashMap();
        String amount = AdapayUtil.formatAmount(dto.getRefundAmount());
        refundParams.put("refund_amt", amount);
        refundParams.put("refund_order_no", SnowflakeIdWorker.getSnowflakeId());
        refundParams.put("notify_url", ADAPAY_REFUND_CALLBACK_URL);

        // 分账对象信息
        OrderBasicInfo orderBasicInfo = getOrderInfoByOrderCode(dto.getOrderCode());
        if (orderBasicInfo != null) {
            String adapayMemberId = adapayMemberAccountService.selectAdapayMemberIdByStationId(orderBasicInfo.getStationId());
            if (StringUtils.isNotBlank(adapayMemberId)) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("member_id", adapayMemberId);
                jsonObject.put("amount", amount);
                jsonObject.put("fee_flag", Constants.Y);

                // 分账对象信息列表，最多仅支持7个分账方，json 数组形式
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(jsonObject);
                // 分账对象信息
                refundParams.put("div_members", jsonArray.toString());
            }
        }
        try {
            Map<String, Object> response = Refund.create(id, refundParams);
            logger.info("汇付支付创建退款对象:{}", JSON.toJSONString(response));
        } catch (BaseAdaPayException e) {
            logger.error("汇付支付创建退款对象error", e);
        }
    }

    @Override
    public void refundForBalanceWithAdapay(WeChatRefundDTO dto) {
        // 查会员余额
        MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(dto.getMemberId());
        if (memberVO == null) {
            throw new BusinessException(ReturnCodeEnum.CODE_SELECT_MEMBER_NULL_ERROR);
        }
        // 校验退款金额
        BigDecimal principalBalance = memberVO.getPrincipalBalance();
        BigDecimal refundAmount = dto.getRefundAmount();
        if (refundAmount.compareTo(principalBalance) > 0) {
            throw new BusinessException(ReturnCodeEnum.CODE_REFUND_MEMBER_BALANCE_ERROR);
        }

        // 查询用户充值余额订单 过滤掉已经退款的充值订单

        // 也许需要多笔支付订单才够退款
    }

    @Override
    public void generateDailyOrderReports(String stationId) {
        if (StringUtils.isBlank(stationId)) {
            return;
        }
        PileStationVO stationInfo = pileStationInfoService.getStationInfo(stationId);
        // 查询站点前一天完成的订单
        QueryOrderDTO dto = new QueryOrderDTO();
        dto.setStationId(stationId);
        LocalDate yesterday = LocalDate.now().plusDays(-1);
        dto.setStartTime(DateUtils.formatDateTime(LocalDateTime.of(yesterday, LocalTime.MIN)));
        dto.setEndTime(DateUtils.formatDateTime(LocalDateTime.of(yesterday, LocalTime.MAX)));
        List<OrderListVO> orderListVOS = orderBasicInfoMapper.selectOrderBasicInfoList(dto);
        if (CollectionUtils.isEmpty(orderListVOS)) {
            logger.warn("站点:{}, 在{}没有查询到订单数据", stationInfo.getStationName(), yesterday.toString());
            return;
        }
        // 统计出日报信息
        BigDecimal useElectricity = BigDecimal.ZERO;
        int chargeNum = 0;
        long chargeTime = 0L;
        BigDecimal totalElectricityAmount = BigDecimal.ZERO;
        BigDecimal totalServiceAmount = BigDecimal.ZERO;
        BigDecimal totalOrderAmount = BigDecimal.ZERO;
        BigDecimal totalVirtualAmount = BigDecimal.ZERO;
        BigDecimal totalSettleAmount = BigDecimal.ZERO;
        for (OrderListVO vo : orderListVOS) {
            BigDecimal chargingDegree = new BigDecimal(vo.getChargingDegree());
            if (chargingDegree.compareTo(BigDecimal.ZERO) <= 0) {
                // 只统计用电量大于0的
                continue;
            }
            // 充电度数
            useElectricity = useElectricity.add(chargingDegree);
            // 充电次数
            chargeNum += 1;
            // 充电时间
            long l = DateUtils.intervalTime(vo.getChargeStartTime(), vo.getChargeEndTime());
            chargeTime += l;
            // 电费金额
            totalElectricityAmount = totalElectricityAmount.add(vo.getTotalElectricityAmount());
            // 服务费金额
            totalServiceAmount = totalServiceAmount.add(vo.getTotalServiceAmount());
            // 订单金额
            totalOrderAmount = totalOrderAmount.add(new BigDecimal(vo.getOrderAmount()));
            // 虚拟金额
            totalVirtualAmount = totalVirtualAmount.add(new BigDecimal(vo.getVirtualAmount()));
            // 结算金额
            totalSettleAmount = totalSettleAmount.add(new BigDecimal(vo.getSettleAmount()));
        }
        // 保存到数据库
        SettleOrderReport settleOrderReport = new SettleOrderReport();
        settleOrderReport.setMerchantId(stationInfo.getMerchantId());
        settleOrderReport.setStationId(stationId);
        settleOrderReport.setUseElectricity(useElectricity);
        settleOrderReport.setChargeNum(chargeNum + "");
        settleOrderReport.setChargeTime(chargeTime + "");
        settleOrderReport.setElectricityAmount(totalElectricityAmount);
        settleOrderReport.setServiceAmount(totalServiceAmount);
        settleOrderReport.setTotalAmount(totalOrderAmount);
        settleOrderReport.setVirtualAmount(totalVirtualAmount);
        settleOrderReport.setTradeDate(yesterday.toString());
        // 计算手续费 = 结算金额 * 0.55%
        BigDecimal tradeFee = totalSettleAmount.multiply(new BigDecimal("0.0055"));
        settleOrderReport.setTradeFee(tradeFee);
        settleOrderReport.setTradeAmount(totalSettleAmount.subtract(tradeFee));
        settleOrderReportService.insertSettleOrderReport(settleOrderReport);
    }
}
