package com.yc.ship.module.trade.service.order.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.yc.ship.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.trade.api.sms.dto.SmsSendLogDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.check.CheckOrderPageVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.TradeDetailRespVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.TradeOrderPdaRespVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.TradeOrderRespVO;
import com.yc.ship.module.trade.controller.admin.smsSendconfig.vo.SmsSendconfigQueryRespVO;
import com.yc.ship.module.trade.controller.app.pda.vo.PdaQueryOrderReqVO;
import com.yc.ship.module.trade.controller.app.pda.vo.PdaQueryVoucherReqVO;
import com.yc.ship.module.trade.dal.dataobject.order.*;
import com.yc.ship.module.trade.dal.dataobject.orderjz.OrderJzDO;
import com.yc.ship.module.trade.dal.mysql.contract.ContractMapper;
import com.yc.ship.module.trade.dal.mysql.insurance.InsuranceMapper;
import com.yc.ship.module.trade.dal.mysql.order.*;
import com.yc.ship.module.trade.dal.mysql.orderjz.OrderJzMapper;
import com.yc.ship.module.trade.dal.mysql.orderjzdetail.OrderJzDetailMapper;
import com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderJzDetailDO;
import com.yc.ship.module.trade.enums.*;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.bo.*;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.product.enums.YesOrNoEnum.YES;
import static com.yc.ship.module.trade.enums.ApiConstants.*;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.ORDER_SAVE_EXCEPTION;


/**
 * &#064;Description ：订单数据service实现
 * @author ：qsl
 * &#064;Date ：2025/6/4 16:18
 */
@Service
@Slf4j
public class TradeOrderRepositoryServiceImpl implements TradeOrderRepositoryService {

    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private OrderJzMapper orderJzMapper;
    @Resource
    private OrderJzDetailMapper orderJzDetailMapper;
    @Resource
    private TradeDetailMapper tradeDetailMapper;
    @Resource
    private TradeDetailBaseMapper tradeDetailBaseMapper;
    @Resource
    private TradeVisitorMapper tradeVisitorMapper;
    @Resource
    private TradeOrderUserMapper tradeOrderUserMapper;
    @Resource
    private TradeOrderPayMapper tradeOrderPayMapper;
    @Resource
    private TradeMchInfoMapper tradeMchInfoMapper;
    @Resource
    private TradeOrderBindMapper tradeOrderBindMapper;
    @Resource
    private TradeOrderDispatchMapper tradeOrderDispatchMapper;
    @Resource
    private TradeOrderChangeDetailMapper tradeOrderChangeDetailMapper;
    @Resource
    private TradeOrderLogMapper tradeOrderLogMapper;
    @Resource
    private TradeOrderHotelMapper tradeOrderHotelMapper;
    @Resource
    private TradeDetailPriceMapper tradeDetailPriceMapper;
    @Resource
    private TradeOrderDeliveryMapper tradeOrderDeliveryMapper;
    @Resource
    private TradeOrderTravelService tradeOrderTravelService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ContractMapper contractMapper;
    @Resource
    private InsuranceMapper insuranceMapper;

    @Resource
    private TradeDetailBizMapper tradeDetailBizMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(TradeOrderBO tradeOrderBO) {
        try {

            tradeOrderMapper.insert(tradeOrderBO.getTradeOrderDO());
            orderJzMapper.insert(tradeOrderBO.getOrderJzDO());
            tradeOrderUserMapper.insert(tradeOrderBO.getTradeOrderUserDO());
            if (tradeOrderBO.getTradeOrderBindDO() != null) {
                tradeOrderBindMapper.insert(tradeOrderBO.getTradeOrderBindDO());
            }
            if (tradeOrderBO.getTradeOrderDeliveryDO() != null) {
                tradeOrderDeliveryMapper.insert(tradeOrderBO.getTradeOrderDeliveryDO());
            }

            tradeOrderBO.getTradeOrderDetailBOList().forEach(tradeOrderDetailBO -> {

                tradeDetailMapper.insertBatch(tradeOrderDetailBO.getTradeDetailDOList());
                tradeDetailBaseMapper.insertBatch(tradeOrderDetailBO.getTradeDetailBaseDOList());
                tradeVisitorMapper.insertBatch(tradeOrderDetailBO.getTradeVisitorDOList());

                if (tradeOrderDetailBO.getTradeOrderHotelDO() != null) {
                    tradeOrderHotelMapper.insert(tradeOrderDetailBO.getTradeOrderHotelDO());
                }
                if (CollUtil.isNotEmpty(tradeOrderDetailBO.getTradeDetailPriceDOList())) {
                    tradeDetailPriceMapper.insertBatch(tradeOrderDetailBO.getTradeDetailPriceDOList());
                }
            });

        } catch (Exception e) {
            log.error("订单保存异常", e);
            //极端情况下会出现，上层会回滚库存
            throw exception(ORDER_SAVE_EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyOrder(TradeOrderBO tradeOrderBO,TradeOrderDO oldOrder) {
        try {
            Long oldOrderId = oldOrder.getId();

            // ============ 先查询旧接站相关数据（在软删除之前），用于后续重建 ============
            List<OrderJzDO> oldJzList = orderJzMapper.selectList(new LambdaQueryWrapper<OrderJzDO>()
                    .eq(OrderJzDO::getOrderId, oldOrderId));
            List<Long> oldJzIdList = oldJzList.stream().map(OrderJzDO::getId).collect(Collectors.toList());
            List<OrderJzDetailDO> oldJzDetailList = Collections.emptyList();
            if (CollUtil.isNotEmpty(oldJzIdList)) {
                oldJzDetailList = orderJzDetailMapper.selectList(new LambdaQueryWrapper<OrderJzDetailDO>()
                        .in(OrderJzDetailDO::getJzId, oldJzIdList));
            }

            // ============ 软删除旧订单主表 ============
            tradeOrderMapper.updateOrderDeleted(oldOrderId,1);
            TradeOrderDO tradeOrderDO = tradeOrderBO.getTradeOrderDO();
            tradeOrderDO.setUpdateTime(LocalDateTime.now());
            tradeOrderMapper.insert(tradeOrderDO);

            // ============ 软删除旧接站头表 + 旧接站明细 ============
            orderJzMapper.updateDeleted(oldOrderId, 1);
            if (CollUtil.isNotEmpty(oldJzIdList)) {
                orderJzDetailMapper.updateDeletedByJzIds(oldJzIdList, 1);
            }

            // ============ 插入新接站头表（同步旧接站头表数据） ============
            OrderJzDO newOrderJzDO = tradeOrderBO.getOrderJzDO();
            // 将旧接站头表数据同步到新记录：前端未传的字段用旧值补齐
            if (CollUtil.isNotEmpty(oldJzList)) {
                OrderJzDO oldJzDO = oldJzList.get(0);
                if (newOrderJzDO.getIsJz() == null || newOrderJzDO.getIsJz() >= 0) {
                    newOrderJzDO.setIsJz(oldJzDO.getIsJz());
                }
                if (newOrderJzDO.getJzAddress() == null) {
                    newOrderJzDO.setJzAddress(oldJzDO.getJzAddress());
                }
                if (newOrderJzDO.getJzLinkName() == null) {
                    newOrderJzDO.setJzLinkName(oldJzDO.getJzLinkName());
                }
                if (newOrderJzDO.getJzLinkPhone() == null) {
                    newOrderJzDO.setJzLinkPhone(oldJzDO.getJzLinkPhone());
                }
                newOrderJzDO.setDeleted(false);
            }
            orderJzMapper.insert(newOrderJzDO);

            // ============ 为新订单重建接站明细 ============
            rebuildOrderJzDetail(oldJzDetailList, tradeOrderBO);

            tradeOrderBindMapper.update(new LambdaUpdateWrapper<TradeOrderBindDO>().set(TradeOrderBindDO::getDeleted, 1).set(TradeOrderBindDO::getUpdateTime, tradeOrderBO.getUpdateTime()==null?new Date():tradeOrderBO.getUpdateTime()).eq(TradeOrderBindDO::getOrderId, oldOrderId));
            if (tradeOrderBO.getTradeOrderBindDO() != null) {
                tradeOrderBindMapper.insert(tradeOrderBO.getTradeOrderBindDO());
            }
            tradeOrderUserMapper.updateDeleted(oldOrderId,1);
            tradeOrderUserMapper.insert(tradeOrderBO.getTradeOrderUserDO());

            tradeOrderBO.getTradeOrderDetailBOList().forEach(tradeOrderDetailBO -> {
                tradeDetailMapper.updateDeleted(oldOrderId,1);
                tradeDetailMapper.insertBatch(tradeOrderDetailBO.getTradeDetailDOList());
                tradeDetailBaseMapper.updateDeleted(oldOrderId,1);
                tradeDetailBaseMapper.insertBatch(tradeOrderDetailBO.getTradeDetailBaseDOList());
                tradeVisitorMapper.updateDeleted(oldOrderId,1);
                tradeVisitorMapper.insertBatch(tradeOrderDetailBO.getTradeVisitorDOList());

                if (CollUtil.isNotEmpty(tradeOrderDetailBO.getTradeDetailPriceDOList())) {
                    tradeDetailPriceMapper.update(new LambdaUpdateWrapper<TradeDetailPriceDO>()
                            .set(TradeDetailPriceDO::getDeleted, 1)
                            .set(TradeDetailPriceDO::getUpdateTime, tradeOrderBO.getUpdateTime()==null?new Date():tradeOrderBO.getUpdateTime())
                            .eq(TradeDetailPriceDO::getOrderId, oldOrderId)
                    );
                    tradeDetailPriceMapper.insertBatch(tradeOrderDetailBO.getTradeDetailPriceDOList());
                }
            });

        } catch (Exception e) {
            log.error("订单保存异常", e);
            //极端情况下会出现，上层会回滚库存
            throw exception(ORDER_SAVE_EXCEPTION);
        }
    }

    /**
     * 修改订单时，为新订单重建接站明细数据。
     * 通过旧接站明细的证件号（id_card）匹配新游客表（trade_visitor）中的记录，
     * 将新的 visitor_id 和新的 jz_id 写入新创建的 trade_order_jz_detail 记录中，
     * 确保 trade_order_jz_detail 与新订单的 trade_visitor 正确关联。
     *
     * @param oldJzDetailList 旧订单的接站明细列表（在软删除前已查询）
     * @param tradeOrderBO    订单业务对象（包含新游客列表和新接站头表）
     */
    private void rebuildOrderJzDetail(List<OrderJzDetailDO> oldJzDetailList, TradeOrderBO tradeOrderBO) {
        if (CollUtil.isEmpty(oldJzDetailList)) {
            return;
        }

        Long newJzId = tradeOrderBO.getOrderJzDO().getId();

        // 1. 构建证件号和游客姓名到新游客ID的映射（从新订单的游客列表中获取）
        Map<String, TradeVisitorDO> credentialNoToNewVisitorIdMap = new HashMap<>(16);
        Map<String, TradeVisitorDO> nameToNewVisitorIdMap = new HashMap<>(16);
        tradeOrderBO.getTradeOrderDetailBOList().forEach(detailBO -> {
            if (CollUtil.isNotEmpty(detailBO.getTradeVisitorDOList())) {
                detailBO.getTradeVisitorDOList().forEach(visitor -> {
                    if (visitor.getCredentialNo() != null || visitor.getName() != null) {
                        credentialNoToNewVisitorIdMap.put(visitor.getCredentialNo(), visitor);
                        nameToNewVisitorIdMap.put(visitor.getName(), visitor);
                    }
                });
            }
        });

        // 2. 基于旧接站明细重建新记录，关联新的 visitor_id 和 jz_id
        List<OrderJzDetailDO> newJzDetailList = new ArrayList<>();
        for (OrderJzDetailDO oldDetail : oldJzDetailList) {
            OrderJzDetailDO newDetail = new OrderJzDetailDO();
            newDetail.setId(IdWorker.getId());
            newDetail.setJzId(newJzId);
            // 通过证件号匹配新游客ID，确保 visitor_id 关联到新订单的游客
            TradeVisitorDO newVisitorId = credentialNoToNewVisitorIdMap.get(oldDetail.getIdCard());
            TradeVisitorDO newVisitorId2 = nameToNewVisitorIdMap.get(oldDetail.getName());
            newDetail.setVisitorId(newVisitorId != null ? newVisitorId.getId() : (newVisitorId2 != null ? newVisitorId2.getId() : oldDetail.getVisitorId()) );
            newDetail.setBatchNo(oldDetail.getBatchNo());
            newDetail.setArriveTime(oldDetail.getArriveTime());
            newDetail.setAddress(oldDetail.getAddress());
            newDetail.setName(newVisitorId != null ? newVisitorId.getName() : (newVisitorId2 != null ? newVisitorId2.getName() : oldDetail.getName()));
            newDetail.setIdCard(newVisitorId != null ? newVisitorId.getCredentialNo() : (newVisitorId2 != null ? newVisitorId2.getCredentialNo() : oldDetail.getIdCard()) );
            newDetail.setTenantId(oldDetail.getTenantId());
            String phone = (oldDetail.getPhone() != null && !oldDetail.getPhone().isEmpty()) ? oldDetail.getPhone()
                    : ((newVisitorId != null && newVisitorId.getMobile() != null && !newVisitorId.getMobile().isEmpty()) ? newVisitorId.getMobile()
                    : (newVisitorId2 != null && newVisitorId2.getMobile() != null && !newVisitorId2.getMobile().isEmpty()) ? newVisitorId2.getMobile() : null);
            newDetail.setPhone(phone);
            newDetail.setRemark(oldDetail.getRemark());
            newDetail.setStatus(oldDetail.getStatus());
            newDetail.setSignTime(oldDetail.getSignTime());
            newDetail.setSignMan(oldDetail.getSignMan());
            newDetail.setSignRemark(oldDetail.getSignRemark());
            newDetail.setSignImage(oldDetail.getSignImage());
            newDetail.setExtendOrderNo(oldDetail.getExtendOrderNo());
            newDetail.setExtendTicketNo(oldDetail.getExtendTicketNo());
            newDetail.setDeleted(newVisitorId == null && (newVisitorId2 == null));
            newDetail.setDispatchId(oldDetail.getDispatchId());
            newJzDetailList.add(newDetail);
        }

        // 3. 批量插入新接站明细
        if (CollUtil.isNotEmpty(newJzDetailList)) {
            orderJzDetailMapper.insertBatch(newJzDetailList);
        }
    }

    @Override
    public void updateOrderStatus(TradeOrderDO tradeOrderDO) {
        //订单状态
        LambdaUpdateWrapper<TradeOrderDO> orderUpdateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getOrderStatus, tradeOrderDO.getOrderStatus())
                .eq(TradeOrderDO::getId, tradeOrderDO.getId());
        tradeOrderMapper.update(orderUpdateWrapper);

    }

    @Override
    public void updateInvoiceStatusByOrderNo(List<String> orderNoList, Integer invoiceStatus) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getIsInvoice, invoiceStatus)
                .in(TradeOrderDO::getOrderNo, orderNoList);
        tradeOrderMapper.update(updateWrapper);
    }

    @Override
    public TradeOrderDO getById(Long id) {
        return tradeOrderMapper.selectById(id);
    }

    @Override
    public void savePayOrder(TradeOrderPayDO tradeOrderPayDO) {
        tradeOrderPayMapper.insert(tradeOrderPayDO);
    }

    @Override
    public void updatePayOrderStatus(TradeOrderPayDO tradeOrderPayDO) {
        LambdaUpdateWrapper<TradeOrderPayDO> orderPayUpdateWrapper = new LambdaUpdateWrapper<TradeOrderPayDO>()
                .set(TradeOrderPayDO::getPayStatus, tradeOrderPayDO.getPayStatus())
                .eq(TradeOrderPayDO::getId, tradeOrderPayDO.getId());
        if (ObjectUtil.equal(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.PAID.getStatus())) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getPaymentDate, tradeOrderPayDO.getPaymentDate());
        }
        if (StrUtil.isNotBlank(tradeOrderPayDO.getPaymentNo())) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getPaymentNo, tradeOrderPayDO.getPaymentNo());
        }
        if (tradeOrderPayDO.getPaymentType() != null) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getPaymentType, tradeOrderPayDO.getPaymentType());
        }
        if (tradeOrderPayDO.getBillNo() != null) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getBillNo, tradeOrderPayDO.getBillNo());
        }
        if (tradeOrderPayDO.getPosNo() != null) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getPosNo, tradeOrderPayDO.getPosNo());
        }
        tradeOrderPayMapper.update(orderPayUpdateWrapper);
    }

    @Override
    public BigDecimal getHadPayAmount(Long orderId) {
        return tradeOrderPayMapper.selectHadPayAmount(orderId);
    }


    @Override
    public void updateOrderAfterAllPay(TradeOrderDO tradeOrderDO) {
        LambdaUpdateWrapper<TradeOrderDO> orderUpdateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getOrderStatus, tradeOrderDO.getOrderStatus())
                .set(TradeOrderDO::getPaymentDate, tradeOrderDO.getPaymentDate())
                .set(TradeOrderDO::getPayStatus, tradeOrderDO.getPayStatus())
                .set(TradeOrderDO::getRealPayAmount, tradeOrderDO.getRealPayAmount())
                .eq(TradeOrderDO::getId, tradeOrderDO.getId());
        tradeOrderMapper.update(orderUpdateWrapper);

    }

    @Override
    public TradeOrderPayDO getPayOrderById(Long id) {
        return tradeOrderPayMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderAfterAllSupplierPay(TradeOrderDO tradeOrderDO) {
        LambdaUpdateWrapper<TradeOrderDO> orderUpdateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getOrderStatus, tradeOrderDO.getOrderStatus())
                .set(TradeOrderDO::getPayStatus, tradeOrderDO.getPayStatus())
                .set(TradeOrderDO::getTravelStatus, TradeOrderTravelEnum.Not_Traveled.getStatus())
                .eq(TradeOrderDO::getId, tradeOrderDO.getId());
        tradeOrderMapper.update(orderUpdateWrapper);

        LambdaUpdateWrapper<TradeDetailDO> orderDetailUpdateWrapper = new LambdaUpdateWrapper<TradeDetailDO>()
                .set(TradeDetailDO::getVoucherStatus, VoucherStatusEnum.UNUSED.getStatus())
                .eq(TradeDetailDO::getOrderId, tradeOrderDO.getId());
        tradeDetailMapper.update(orderDetailUpdateWrapper);

        tradeDetailBaseMapper.updateStatusByOrderId(tradeOrderDO.getId(), VoucherStatusEnum.UNUSED.getStatus());
    }

    @Override
    public void updateStatusAfterAllCheck(Long id) {
        tradeDetailMapper.updateStatusAfterAllCheck(id);
    }

    @Override
    public List<TradeVisitorBO> getVisitorVoucherListByOrderId(Long orderId) {
        return tradeVisitorMapper.selectVisitorVoucherListByOrderId(orderId);
    }

    @Override
    public TradeOrderDO getOrderByNo(String orderNo) {
        LambdaQueryWrapper<TradeOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeOrderDO::getOrderNo, orderNo);
        queryWrapper.eq(TradeOrderDO::getDeleted, 0);

        return tradeOrderMapper.selectOne(queryWrapper);
    }

    @Override
    public void updatePayOrderPayParams(TradeOrderPayDO tradeOrderPayDO) {
        LambdaUpdateWrapper<TradeOrderPayDO> orderPayUpdateWrapper = new LambdaUpdateWrapper<TradeOrderPayDO>()
                .eq(TradeOrderPayDO::getId, tradeOrderPayDO.getId());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getPayParams, tradeOrderPayDO.getPayParams());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getMerchantNo, tradeOrderPayDO.getMerchantNo());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getChannelId, tradeOrderPayDO.getChannelId());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getPosNo, tradeOrderPayDO.getPosNo());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getPosOut, tradeOrderPayDO.getPosOut());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getOpenId, tradeOrderPayDO.getOpenId());
        orderPayUpdateWrapper.set(TradeOrderPayDO::getReqParams, tradeOrderPayDO.getReqParams());
        if (StrUtil.isNotBlank(tradeOrderPayDO.getPaymentNo())) {
            orderPayUpdateWrapper.set(TradeOrderPayDO::getPaymentNo, tradeOrderPayDO.getPaymentNo());
        }
        tradeOrderPayMapper.update(orderPayUpdateWrapper);

    }

    @Override
    public List<TradeDetailDO> queryDetailByOrderId(Long orderId) {
        return tradeDetailMapper.selectList(TradeDetailDO::getOrderId, orderId);
    }

    @Override
    public List<TradeDetailDO> queryYcDetailByOrderId(Long orderId) {
        return tradeDetailMapper.selectList(new LambdaQueryWrapper<TradeDetailDO>().eq(TradeDetailDO::getOrderId, orderId).eq(TradeDetailDO::getProductType, 0));
    }


    @Override
    public TradeOrderDO getOrderByOtaAndExternalOrderNo(String otaOrderNo, String sourceId) {
        LambdaQueryWrapper<TradeOrderDO> queryWrapper = new LambdaQueryWrapper<TradeOrderDO>();
        queryWrapper.eq(TradeOrderDO::getExternalOrderNo, otaOrderNo);
        queryWrapper.eq(TradeOrderDO::getSourceId, sourceId);
        return tradeOrderMapper.selectOne(queryWrapper);
    }

    @Override
    public List<TradeVisitorDO> queryVisitorByDetailId(Long detailId) {

        return tradeVisitorMapper.selectList(TradeVisitorDO::getDetailId, detailId);
    }

    @Override
    public List<TradeDetailBO> getTradeDetailWithBase(Long orderId, Long tradeDetailId, List<String> voucherList) {
        return tradeDetailMapper.selectTradeDetailWithBase(orderId, tradeDetailId, voucherList, null);
    }

    @Override
    public List<TradeDetailBO> getTradeDetailWithBase(Long orderId, List<Long> detailIdList) {
        return tradeDetailMapper.selectTradeDetailWithBase(orderId, null, null, detailIdList);
    }

    @Override
    public TradeOrderUserDO getOrderUser(Long orderId) {
        return tradeOrderUserMapper.selectOne(TradeOrderUserDO::getOrderId, orderId);
    }

    @Override
    public Map<String, Object> queryDetailCountByOrderId(Long orderId) {
        return tradeDetailMapper.queryDetailCountByOrderId(orderId);
    }

    @Override
    public List<TradeOrderPayDO> getOrderPayList(Long orderId) {
        LambdaQueryWrapper<TradeOrderPayDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeOrderPayDO::getOrderId, orderId)
                .eq(TradeOrderPayDO::getPayStatus, PaymentStatusEnum.PAID.getStatus())
                .orderByDesc(TradeOrderPayDO::getPaymentType);
        return tradeOrderPayMapper.selectList(queryWrapper);
    }

    @Override
    public Map<String, Long> getRefundCount(Long orderId) {
        return tradeDetailMapper.selectRefundCount(orderId);
    }

    @Override
    public TradeMchInfoDO getByMchId(String mchId) {
        return tradeMchInfoMapper.selectById(mchId);
    }

    @Override
    public Long queryEffectyCount(Long orderId) {
        LambdaQueryWrapper<TradeDetailDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TradeDetailDO::getOrderId, orderId);
        wrapper.ge(TradeDetailDO::getVoucherStatus, VoucherStatusEnum.UNUSED.getStatus());
        wrapper.le(TradeDetailDO::getVoucherStatus, VoucherStatusEnum.TOOK.getStatus());
        return tradeDetailMapper.selectCount(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Long orderId) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TradeOrderDO::getId, orderId);
        updateWrapper.set(TradeOrderDO::getOrderStatus, TradeOrderStatusEnum.CANCELED.getStatus());
        updateWrapper.set(TradeOrderDO::getUpdateTime, new Date());
        tradeOrderMapper.update(null, updateWrapper);

        LambdaUpdateWrapper<TradeDetailDO> orderDetailUpdateWrapper = new LambdaUpdateWrapper<TradeDetailDO>()
                .set(TradeDetailDO::getVoucherStatus, VoucherStatusEnum.CANCELED.getStatus())
                .eq(TradeDetailDO::getOrderId, orderId);
        tradeDetailMapper.update(orderDetailUpdateWrapper);

        tradeDetailBaseMapper.updateStatusByOrderId(orderId, VoucherStatusEnum.CANCELED.getStatus());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrderFail(Long orderId) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TradeOrderDO::getId, orderId);
        updateWrapper.set(TradeOrderDO::getOrderStatus, TradeOrderStatusEnum.FAIL.getStatus());
        tradeOrderMapper.update(null, updateWrapper);

        LambdaUpdateWrapper<TradeDetailDO> orderDetailUpdateWrapper = new LambdaUpdateWrapper<TradeDetailDO>()
                .set(TradeDetailDO::getVoucherStatus, VoucherStatusEnum.FAIL.getStatus())
                .eq(TradeDetailDO::getOrderId, orderId);
        tradeDetailMapper.update(orderDetailUpdateWrapper);

        tradeDetailBaseMapper.updateStatusByOrderId(orderId, VoucherStatusEnum.FAIL.getStatus());
    }

    @Override
    public TradeDetailDO queryByOrderIdAndPassengerId(Long orderId, String passengerId) {
        MPJLambdaWrapper<TradeDetailDO> wrapper = new MPJLambdaWrapperX<TradeDetailDO>()
                .selectAll(TradeDetailDO.class)
                .innerJoin(TradeVisitorDO.class, TradeVisitorDO::getDetailId, TradeDetailDO::getId)
                .eq(TradeDetailDO::getOrderId, orderId)
                .eq(TradeVisitorDO::getOtaDetailId, passengerId);
        return tradeDetailMapper.selectJoinOne(TradeDetailDO.class, wrapper);
    }

    @Override
    public TradeDetailDO queryDetailVoucherCode(String code, Long orderId) {
        return tradeDetailMapper.selectOne(TradeDetailDO::getOrderId, orderId, TradeDetailDO::getVoucherCode, code);
    }


    @Override
    public TradeDetailDO getOrderAnyDetail(Long orderId) {
        Page<TradeDetailDO> page = new Page<>(1, 1);
        LambdaQueryWrapper<TradeDetailDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeDetailDO::getOrderId, orderId);
        return tradeDetailMapper.selectPage(page, queryWrapper).getRecords().get(0);
    }

    @Override
    @TenantIgnore
    public TradeOrderPayDO getPayOrderByIdIgnoreTenant(Long id) {
        return tradeOrderPayMapper.selectById(id);
    }

    @Override
    public List<Map<String, Object>> getDetailInfoByDetailId(Map<String, Object> params) {
        return tradeDetailMapper.getDetailInfoByDetailId(params);
    }

    @Override
    public void updateInvoiceStatus(List<TradeOrderDO> orderList, Integer invoiceStatus) {
        List<Long> orderIdList = orderList.stream().map(TradeOrderDO::getId).collect(Collectors.toList());
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getIsInvoice, invoiceStatus)
                .in(TradeOrderDO::getId, orderIdList);
        tradeOrderMapper.update(updateWrapper);
    }


    @Override
    public List<TradeVisitorBO> getInsureVisitor(Long orderId, Long productId) {
        return tradeVisitorMapper.selectInsureVisitor(orderId, productId);
    }

    @Override
    public List<Map<String, Object>> getInsuranceProductFromOrder(Long orderId) {
        return tradeDetailMapper.selectInsuranceProductFromOrder(orderId);
    }

    @Override
    public void updateOrderInsureStatus(Long orderId, Integer status) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getIsInsure, status)
                .eq(TradeOrderDO::getId, orderId);
        tradeOrderMapper.update(updateWrapper);
    }

    @Override
    public List<Map<String, Object>> getContractProductFromOrder(Long orderId) {
        return tradeDetailMapper.selectContractProductFromOrder(orderId);
    }

    @Override
    public List<TradeVisitorBO> getContractVisitor(Long orderId, Long productId) {
        return tradeVisitorMapper.selectContractVisitor(orderId, productId);
    }

    @Override
    public void updateOrderContractStatus(Long orderId, Integer status) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getIsContract, status)
                .eq(TradeOrderDO::getId, orderId);
        tradeOrderMapper.update(updateWrapper);
    }

    @Override
    public List<TradeDetailRespVO> getDetailAndVisitor(Long orderId, List<String> detailVoucherList) {
        return tradeDetailMapper.selectDetailAndVisitor(orderId, detailVoucherList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveVisitorList(List<TradeVisitorDO> tradeVisitorDOList) {
        tradeVisitorMapper.insertBatch(tradeVisitorDOList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBindOrder(TradeOrderBindDO tradeOrderBindDO) {

        tradeOrderBindMapper.insert(tradeOrderBindDO);
        if (ObjectUtil.equal(tradeOrderBindDO.getType(), TradeOrderBindEnum.ORDER_BIND.getType())) {
            //关联订单更新原订单
            TradeOrderDO updateDO = new TradeOrderDO();
            updateDO.setId(tradeOrderBindDO.getOrderId());
            updateDO.setIsBind(ORDER_BIND_TYPE_MAIN);
            tradeOrderMapper.updateById(updateDO);

            updateDO.setId(tradeOrderBindDO.getBindId());
            updateDO.setIsBind(ORDER_BIND_TYPE_ASSOCIATED);
            tradeOrderMapper.updateById(updateDO);
        } else if (ObjectUtil.equal(tradeOrderBindDO.getType(), TradeOrderBindEnum.CHANGE.getType())) {
            TradeOrderDO updateDO = new TradeOrderDO();
            updateDO.setId(tradeOrderBindDO.getOrderId());
            updateDO.setIsChangeOrder(ORDER_CHANGE_TYPE_OLD);
            tradeOrderMapper.updateById(updateDO);
        }
    }


    @Override
    public TradeOrderBindDO getBindOrder(Long orderId, Long bindId, Integer type) {
        return tradeOrderBindMapper.selectOne(new LambdaQueryWrapperX<TradeOrderBindDO>()
                .eq(TradeOrderBindDO::getOrderId, orderId)
                .eq(TradeOrderBindDO::getBindId, bindId)
                .eq(TradeOrderBindDO::getType, type)
        );
    }

    @Override
    public TradeOrderBindDO getBindOrder(Long bindId, Integer type) {
        return tradeOrderBindMapper.selectOne(new LambdaQueryWrapperX<TradeOrderBindDO>()
                .eq(TradeOrderBindDO::getBindId, bindId)
                .eq(TradeOrderBindDO::getType, type)
        );
    }

    @Override
    public TradeOrderBindDO getBindByOrder(Long orderId) {
        List<TradeOrderBindDO> list = tradeOrderBindMapper.selectList(new LambdaQueryWrapperX<TradeOrderBindDO>()
                .eq(TradeOrderBindDO::getOrderId, orderId).orderByDesc(TradeOrderBindDO::getCreateTime)
        );
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public void deleteOrderBind(Long id) {
        TradeOrderBindDO orderBindDO = tradeOrderBindMapper.selectById(id);

        tradeOrderBindMapper.deleteById(id);

        tradeOrderMapper.update(Wrappers.<TradeOrderDO>lambdaUpdate()
                .set(TradeOrderDO::getIsBind, null)
                .eq(TradeOrderDO::getId, orderBindDO.getBindId())
        );

        List<TradeOrderBindDO> bindDOList = tradeOrderBindMapper.selectList(new LambdaQueryWrapperX<TradeOrderBindDO>()
                .eq(TradeOrderBindDO::getOrderId, orderBindDO.getOrderId())
                .eq(TradeOrderBindDO::getType, orderBindDO.getType())
        );
        if (bindDOList.isEmpty()) {
            tradeOrderMapper.update(Wrappers.<TradeOrderDO>lambdaUpdate()
                    .set(TradeOrderDO::getIsBind, null)
                    .eq(TradeOrderDO::getId, orderBindDO.getOrderId())
            );
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelBindOrder(TradeOrderBindDO tradeOrderBindDO) {
        LambdaQueryWrapper<TradeOrderBindDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeOrderBindDO::getOrderId, tradeOrderBindDO.getOrderId())
                .eq(TradeOrderBindDO::getBindId, tradeOrderBindDO.getBindId())
                .eq(TradeOrderBindDO::getType, tradeOrderBindDO.getType());
        tradeOrderBindMapper.delete(queryWrapper);
        if (ObjectUtil.equal(tradeOrderBindDO.getType(), TradeOrderBindEnum.CHANGE.getType())) {

            //老订单要判断状态
            markChangeOrder(tradeOrderBindDO.getOrderId(), null);

            tradeOrderMapper.update(Wrappers.<TradeOrderDO>lambdaUpdate()
                    .set(TradeOrderDO::getIsChangeOrder, null)
                    .eq(TradeOrderDO::getId, tradeOrderBindDO.getBindId()));
        }
    }

    @Override
    public TradeOrderBindDO getBindOrderByBindId(Long bindId, TradeOrderBindEnum type) {
        LambdaQueryWrapper<TradeOrderBindDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeOrderBindDO::getBindId, bindId)
                .eq(TradeOrderBindDO::getType, type.getType());
        return tradeOrderBindMapper.selectOne(queryWrapper);
    }

    @Override
    public List<TradeOrderBindDO> getBindOrderByOrderId(Long orderId, TradeOrderBindEnum type) {
        LambdaQueryWrapper<TradeOrderBindDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TradeOrderBindDO::getOrderId, orderId)
                .eq(TradeOrderBindDO::getType, type.getType());
        return tradeOrderBindMapper.selectList(queryWrapper);
    }

    @Override
    public void insertOrUpdateVisitor(List<TradeVisitorDO> tradeVisitorDOList) {
        tradeVisitorMapper.insertOrUpdateBatch(tradeVisitorDOList);
    }

    @Override
    @TenantIgnore
    public void updateVis(Long id) {
        TradeVisitorDO updateDO = new TradeVisitorDO();
        updateDO.setId(id);
        updateDO.setIsPush(1);
        tradeVisitorMapper.updateById(updateDO);
    }


    @Override
    public void updateTransOrder(TradeOrderDO tradeOrderDO) {
        LambdaUpdateWrapper<TradeOrderDO> orderUpdateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getTransAmount, tradeOrderDO.getTransAmount())
                .set(TradeOrderDO::getTransDistributorId, tradeOrderDO.getTransDistributorId())
                .set(TradeOrderDO::getOrderStatus, tradeOrderDO.getOrderStatus())
                .eq(TradeOrderDO::getId, tradeOrderDO.getId());
        tradeOrderMapper.update(orderUpdateWrapper);
    }

    @Override
    public List<Map<String, Object>> queryNotifyFailedVoucherInfo(Map<String, Object> param) {
        return tradeDetailMapper.queryNotifyFailedVoucherInfo(param);
    }

    @Override
    public List<TradeDetailRespVO> getTradeDetailWithBaseByCodeAndIdcard(PdaQueryVoucherReqVO reqVO) {
        return tradeDetailMapper.getTradeDetailWithBaseByCodeAndIdcard(reqVO.getVoucherCode(), reqVO.getIdCard(), reqVO.getDispatchId(), reqVO.getChannelId());
    }


    @Override
    public TradeDetailRespVO getTradeDetailByCheckId(Long checkId) {
        return tradeDetailMapper.getTradeDetailByCheckId(checkId);
    }

    @Override
    public List<TradeOrderPdaRespVO> getOrderAndDetail(PdaQueryOrderReqVO reqVO) {
        return tradeOrderMapper.getOrderAndDetailInfo(reqVO.getOrderNo(), reqVO.getCardNo(), reqVO.getPhone(), reqVO.getDispatchId(), reqVO.getChannelId());
    }

    @Override
    public String getPlatOrderNo(String orderNo) {
        return tradeOrderMapper.getPlatOrderNo(orderNo);
    }

    @Override
    public BigDecimal getTotalPayByOrderNo(String orderNo) {
        return tradeOrderMapper.getTotalPayByOrderNo(orderNo);
    }

    @Override
    public IPage<TradeOrderRespVO> getCheckOrder(CheckOrderPageVO pageReqVO) {
        IPage<TradeOrderRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize(), false);
        IPage<TradeOrderRespVO> checkOrder = tradeOrderMapper.getCheckOrder(page, pageReqVO);
        checkOrder.setTotal(tradeOrderMapper.countCheckOrder(pageReqVO));
        return checkOrder;
    }

    @Override
    public void delOrderDispatch(TradeOrderDispatchDO tradeOrderDispatchDO) {
        tradeOrderDispatchMapper.delOrderDispatch(tradeOrderDispatchDO.getDispatchId(), tradeOrderDispatchDO.getProjectCode());
    }


    @Override
    public void saveOrderDispatch(List<TradeOrderDispatchDO> tradeOrderDispatchDOList) {
        tradeOrderDispatchMapper.insertBatch(tradeOrderDispatchDOList);
    }

    @Override
    public List<Long> getOrderIdListByDispatchId(String dispatchId, String projectCode) {
        return tradeOrderDispatchMapper.selectOrderIdListByDispatchId(dispatchId, projectCode);
    }


    @Override
    public void afterOrderDispatch(TreeSet<Long> orderIdList, Long tenantId) {

        if (CollUtil.isEmpty(orderIdList)) {
            return;
        }
        TenantUtils.execute(tenantId, () -> {
            List<Map<String, Object>> orderDispatchStatus = tradeOrderDispatchMapper.selectOrderDispatchStatus(orderIdList);
            List<TradeOrderDO> updateList = orderDispatchStatus.stream().map(item -> {
                TradeOrderDO tradeOrderDO = new TradeOrderDO();
                tradeOrderDO.setId(MapUtil.getLong(item, "id"));
                int dispatchStatus = MapUtil.getInt(item, "schedule_status");
                tradeOrderDO.setDispatchStatus(dispatchStatus);
                return tradeOrderDO;
            }).collect(Collectors.toList());
            updateOrderBatch(updateList);
        });
    }

    @Override
    public void updateOrderBatch(List<TradeOrderDO> tradeOrderDOList) {
        tradeOrderMapper.updateBatch(tradeOrderDOList);
    }

    @Override
    public Map<String, Long> getDispatchCount(Long orderId) {
        return tradeOrderDispatchMapper.selectDispatchCount(orderId);

    }

    @Override
    public List<Map<String, Object>> getOrderProduct(Long orderId) {
        return tradeDetailMapper.selectOrderProduct(orderId);

    }


    @Override
    public List<Map<String, Object>> getVisitorOrderProductCount(Long productId, LocalDateTime useDate, List<String> credentialNoList, Long excludeOrderId) {
        return tradeDetailMapper.selectVisitorOrderProductCount(productId, useDate, credentialNoList, excludeOrderId);
    }

    @Override
    public List<Map<String, Object>> getVisitorOrderProductBaseCount(Long productBaseId, LocalDateTime useDate, List<String> credentialNoList, Long excludeOrderId) {
        return tradeDetailBaseMapper.selectVisitorOrderProductBaseCount(productBaseId, useDate, credentialNoList, excludeOrderId);
    }


    @Override
    public void updatePayOrder(TradeOrderPayDO tradeOrderPayDO) {
        tradeOrderPayMapper.updateById(tradeOrderPayDO);
    }

    @TenantIgnore
    @Override
    public TradeOrderDO getOrderByOrderNoWithoutTenant(String orderNo) {
        return getOrderByNo(orderNo);
    }


    @Override
    public void saveChangeDetail(List<Long> detailList, Long orderId, Long originOrderId) {
        List<TradeOrderChangeDetailDO> insertList = detailList.stream().map(detailId -> {
            TradeOrderChangeDetailDO changeDetailDO = new TradeOrderChangeDetailDO();
            changeDetailDO.setId(IdWorker.getId());
            changeDetailDO.setOrderId(orderId);
            changeDetailDO.setOriginDetailId(detailId);
            changeDetailDO.setOriginOrderId(originOrderId);
            return changeDetailDO;
        }).collect(Collectors.toList());
        tradeOrderChangeDetailMapper.insertBatch(insertList);
    }

    @Override
    public List<TradeDetailDO> getDetailListByIds(List<Long> detailList, Long orderId) {
        LambdaQueryWrapper<TradeDetailDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TradeDetailDO::getId, detailList);
        queryWrapper.eq(TradeDetailDO::getOrderId, orderId);
        return tradeDetailMapper.selectList(queryWrapper);
    }

    @Override
    @TenantIgnore
    public List<TradeDetailDO> getPlatDetailByDetailIds(List<Long> detailList, Long orderId) {
        return tradeDetailMapper.selectPlatDetailByDetailIds(detailList, orderId);
    }

    @Override
    @TenantIgnore
    public List<TradeDetailDO> getPlatDetailByOrderId(Long orderId) {
        return tradeDetailMapper.getPlatDetailByOrderId(orderId);
    }

    @Override
    public List<TradeDetailDO> getChangeDetailList(Long orderId, Long originOrderId) {
        return tradeDetailMapper.selectChangeDetailList(orderId, originOrderId);
    }


    @Override
    public List<SmsSendconfigQueryRespVO> getOrderSmsInfo(Long orderId, Integer type) {
        return tradeDetailMapper.selectOrderSmsInfo(orderId, type);
    }

    @Override
    public List<SmsSendconfigQueryRespVO> getCreateOrderSmsInfo(Long orderId, Integer type) {
        return tradeDetailMapper.selectCreateOrderSmsInfo(orderId, type);
    }

    @Override
    public void insertSmsLog(SmsSendLogDTO smsSendLogDTO) {
        tradeDetailMapper.insertSmsLog(smsSendLogDTO);
    }

    @Override
    public void updatePayAmountByMarketingRefund(Long orderId, BigDecimal payAmount) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TradeOrderDO::getId, orderId);
        updateWrapper.set(TradeOrderDO::getPayAmount, payAmount);
        tradeOrderMapper.update(updateWrapper);
    }

    @Override
    public void updateSellNumByProduct(Long productId, int sellNum) {
        tradeOrderMapper.updateAppletProductSellNum(productId, sellNum);
    }

    @Override
    public IPage<TradeVisitorBO> getVisitorListByDate(IPage<TradeVisitorBO> page, Long orderId, Date useDate, Long tenantId) {
        return tradeVisitorMapper.selectVisitorListByDate(page, orderId, useDate, tenantId);
    }

    @Override
    public void batchUpdate(List<TradeDetailDO> tradeDetailDOList, List<TradeDetailBaseDO> tradeDetailBaseDOList) {
        if (CollUtil.isNotEmpty(tradeDetailDOList)) {
            tradeDetailMapper.updateBatch(tradeDetailDOList);
        }
        if (CollUtil.isNotEmpty(tradeDetailBaseDOList)) {
            tradeDetailBaseMapper.updateBatch(tradeDetailBaseDOList);
        }
    }

    @Override
    @TenantIgnore
    public void updateOrderStatusAfterCheck(Long orderId) {
        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectById(orderId);
        int afterStatus;
        int count = tradeDetailMapper.selectNoCheckCount(orderId);
        if (count > 0) {
            afterStatus = TradeOrderStatusEnum.PART_CHECK.getStatus();
        } else {
            afterStatus = TradeOrderStatusEnum.ALL_CHECK.getStatus();
        }
        // 存在全部核销门票 但订单状态是部分核销 或 已转交, 修改订单和操作记录状态
        List<TradeOrderLogDO> tradeOrderLogList = tradeOrderLogMapper.selectList(new LambdaQueryWrapperX<TradeOrderLogDO>()
                .eq(TradeOrderLogDO::getOrderId, orderId)
                .eq(TradeOrderLogDO::getOperateType, TradeOrderOperateTypeEnum.ORDER_CHECK.getType())
                .orderByDesc(TradeOrderLogDO::getCreateTime));
        if (tradeOrderLogList != null && !tradeOrderLogList.isEmpty()) {
            TradeOrderLogDO updateOrderLog = new TradeOrderLogDO();
            updateOrderLog.setId(tradeOrderLogList.get(0).getId());
            updateOrderLog.setBeforeStatus(tradeOrderDO.getOrderStatus());
            updateOrderLog.setAfterStatus(afterStatus);
            tradeOrderLogMapper.updateById(updateOrderLog);
        }

        if (afterStatus != tradeOrderDO.getOrderStatus()) {
            TradeOrderDO updateOrder = new TradeOrderDO();
            updateOrder.setId(orderId);
            updateOrder.setOrderStatus(afterStatus);
            log.error("更新订单状态{}状态{}", updateOrder.getOrderNo(), afterStatus);
            tradeOrderMapper.updateById(updateOrder);
        }
        // 出行状态设置
        tradeOrderTravelService.updateOrderTravelStatus(tradeOrderDO);
    }

    @Override
    public List<TradeOrderDO> getCanBindOrderList(TradeBindOrderQueryBO vo) {
        return tradeOrderMapper.selectCanBindOrderList(vo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAddOrder(TradeOrderDO addOrder, TradeOrderDO mainOrder) {
        LambdaUpdateWrapper<TradeDetailDO> updateDetailWrapper = new LambdaUpdateWrapper<>();
        updateDetailWrapper.eq(TradeDetailDO::getOrderId, addOrder.getId());
        updateDetailWrapper.set(TradeDetailDO::getOrderId, mainOrder.getId());
        tradeDetailMapper.update(updateDetailWrapper);


        LambdaUpdateWrapper<TradeDetailBaseDO> updateDetailBaseWrapper = new LambdaUpdateWrapper<>();
        updateDetailBaseWrapper.eq(TradeDetailBaseDO::getOrderId, addOrder.getId());
        updateDetailBaseWrapper.set(TradeDetailBaseDO::getOrderId, mainOrder.getId());
        tradeDetailBaseMapper.update(updateDetailBaseWrapper);

        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TradeOrderDO::getId, mainOrder.getId());
        updateWrapper.set(TradeOrderDO::getPayAmount, mainOrder.getPayAmount().add(addOrder.getPayAmount()));
        updateWrapper.set(TradeOrderDO::getAmount, mainOrder.getAmount().add(addOrder.getAmount()));
        tradeOrderMapper.update(updateWrapper);

        LambdaUpdateWrapper<TradeOrderPayDO> updatePayWrapper = new LambdaUpdateWrapper<>();
        updatePayWrapper.eq(TradeOrderPayDO::getOrderId, addOrder.getId());
        updatePayWrapper.set(TradeOrderPayDO::getOrderId, mainOrder.getId());
        tradeOrderPayMapper.update(updatePayWrapper);


        tradeOrderMapper.deleteOrderById(addOrder.getId());

        //更新保险、合同相关联数据
        contractMapper.updateAddOrderId(addOrder.getId(), mainOrder.getId());
        insuranceMapper.updateAddOrderId(addOrder.getId(), mainOrder.getId());
    }

    @Override
    public int getInvoiceOrderCount(String orderNo) {
        return tradeOrderMapper.getInvoiceOrderCount(orderNo);
    }


    @Override
    public List<TradeDetailDO> getUnUsedDetailList(Long orderId) {
        LambdaQueryWrapper<TradeDetailDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TradeDetailDO::getVoucherStatus, Arrays.asList(VoucherStatusEnum.UNUSED.getStatus(), VoucherStatusEnum.TOOK.getStatus()));
        queryWrapper.eq(TradeDetailDO::getOrderId, orderId);
        return tradeDetailMapper.selectList(queryWrapper);
    }

    @Override
    public Long getOrderDetailCount(Long orderId) {
        LambdaQueryWrapper<TradeDetailDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TradeDetailDO::getOrderId, orderId);
        return tradeDetailMapper.selectCount(wrapper);
    }

    @Override
    public BigDecimal getUnUsedAmount(Long orderId) {
        QueryWrapper<TradeDetailDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(" sum(actual_price) as actual_price ")
                .lambda()
                .in(TradeDetailDO::getVoucherStatus, Arrays.asList(VoucherStatusEnum.UNUSED.getStatus(), VoucherStatusEnum.TOOK.getStatus()))
                .eq(TradeDetailDO::getOrderId, orderId)
                .ge(TradeDetailDO::getValidityEndDate, new Date());
        TradeDetailDO result = tradeDetailMapper.selectOne(queryWrapper);
        return result != null ? result.getActualPrice() : BigDecimal.ZERO;
    }

    @Override
    public BigDecimal getPlatPayAmountByOriginOrderNo(String originOrderNo) {
        Map<String, Object> data = tradeOrderMapper.selectPlatPayAmountByOriginOrderNo(originOrderNo);
        return MapUtil.get(data, "totalPayAmount", BigDecimal.class, BigDecimal.ZERO);
    }

    @Override
    public void updateOrderPlatAmount(String orderNo, BigDecimal payAmount) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getPlatAmount, payAmount)
                .eq(TradeOrderDO::getOrderNo, orderNo);
        tradeOrderMapper.update(updateWrapper);
    }


    @Override
    public List<TradeDetailPriceDO> getDetailPriceByDetailIds(List<Long> detailIds) {
        return tradeDetailPriceMapper.selectByDetailIds(detailIds);
    }

    @Override
    public void batchUpdateDetailPrice(List<TradeDetailPriceDO> tradeDetailPriceDOList) {
        if (CollUtil.isEmpty(tradeDetailPriceDOList)) {
            return;
        }

        tradeDetailPriceMapper.updateBatch(tradeDetailPriceDOList);
    }

    @Override
    public List<TradeOrderHotelDO> getHotelBookingInfoByOrderId(Long id) {
        return tradeOrderHotelMapper.selectList(TradeOrderHotelDO::getOrderId, id);
    }

    @Override
    public void updateOrderConfirmType(Long orderId, Integer confirmType) {
        LambdaUpdateWrapper<TradeOrderDO> updateWrapper = new LambdaUpdateWrapper<TradeOrderDO>()
                .set(TradeOrderDO::getConfirmType, confirmType)
                .eq(TradeOrderDO::getId, orderId);
        tradeOrderMapper.update(updateWrapper);
    }

    @Override
    public List<TradeOrderDO> getByExternalOriginOrderNo(String externalOriginOrderNo) {
        LambdaQueryWrapper<TradeOrderDO> queryWrapper = new LambdaQueryWrapper<TradeOrderDO>()
                .eq(TradeOrderDO::getExternalOriginOrderNo, externalOriginOrderNo);
        return tradeOrderMapper.selectList(queryWrapper);
    }

    @Override
    public Long getCheckCount(Long orderId) {
        LambdaQueryWrapper<TradeDetailDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TradeDetailDO::getOrderId, orderId);
        wrapper.ge(TradeDetailDO::getCheckStatus, YES);
        return tradeDetailMapper.selectCount(wrapper);
    }


    @Override
    public List<Map<String, Object>> selectContractByOrderId(Long orderId) {
        return tradeDetailMapper.selectContractByOrderId(orderId);
    }


    @Override
    public void markChangeOrder(Long orderId, Integer type) {
        String lockKey = String.format(CHANGE_ORDER_LOCK, orderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock();
            if (type == null) {
                Integer count = tradeOrderMapper.selectChangeCountByOrderId(orderId);
                if (count != null && count > 0) {
                    return;
                }
            }

            LambdaUpdateWrapper<TradeOrderDO> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(TradeOrderDO::getIsChangeOrder, type);
            wrapper.eq(TradeOrderDO::getId, orderId);
            tradeOrderMapper.update(wrapper);
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }

    }

    @Override
    public int updateOrderFinishStatus(List<Integer> sellMethodList, String endDate) {
        return tradeOrderMapper.updateOrderFinishStatus(sellMethodList, endDate);
    }

    @Override
    public List<TradeDetailGuideRefundBO> getInnerTradeDetailWithBaseByGuideRefund(String refundId) {
        return tradeDetailBizMapper.selectInnerTradeDetailWithBaseByGuideRefund(refundId);
    }

    @Override
    public List<TradeDetailGuideRefundBO> getTradeDetailWithBaseByGuideRefund(String refundId) {
        return tradeDetailBizMapper.selectTradeDetailWithBaseByGuideRefund(refundId);
    }

    @Override
    public Map<String, BigDecimal> getSelfDetailTotalAmount(Long detailId) {
        return tradeDetailBizMapper.selectSelfDetailTotalAmount(detailId);
    }

    @Override
    public Integer getOrderVisitorCount(Long orderId) {
        return tradeVisitorMapper.selectOrderVisitorCount(orderId);
    }
}

