package com.sckw.order.serivce;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
import com.sckw.contract.api.model.vo.*;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.BusinessPlatfromException;
import com.sckw.core.exception.CustomPromptException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
import com.sckw.core.model.enums.*;
import com.sckw.core.model.page.PageHelperUtil;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.model.vo.TableBottom;
import com.sckw.core.model.vo.TableStatisticRes;
import com.sckw.core.model.vo.TableTop;
import com.sckw.core.utils.*;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.BaseResult;
import com.sckw.core.web.response.HttpResult;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.fleet.api.model.vo.TruckDispatchCoefficientVO;
import com.sckw.manage.api.RemoteManageService;
import com.sckw.manage.api.model.dto.res.FindEntCooperateResVo;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.order.api.model.*;
import com.sckw.order.dao.KwoTradeOrderGoodsMapper;
import com.sckw.order.dao.KwoTradeOrderArchiveMapper;
import com.sckw.order.dao.KwoTradeOrderMapper;
import com.sckw.order.enums.ContractStatusEnum;
import com.sckw.order.enums.*;
import com.sckw.order.model.*;
import com.sckw.order.model.dto.*;
import com.sckw.order.model.vo.KwoTradeOrderArchiveVo;
import com.sckw.order.model.vo.SaleTopVo;
import com.sckw.order.model.vo.req.ContractInfo;
import com.sckw.order.model.vo.req.*;
import com.sckw.order.model.vo.res.GoodsInfoDetailRes;
import com.sckw.order.model.vo.res.OrderDetailRes;
import com.sckw.order.model.vo.res.UnitInfoDetailRes;
import com.sckw.order.model.vo.res.*;
import com.sckw.order.repository.KwoTradeOrderUnitRepository;
import com.sckw.order.util.TradeOrderDashboardUtils;
import com.sckw.payment.api.dubbo.PayCenterDubboService;
import com.sckw.payment.api.dubbo.PaymentDubboService;
import com.sckw.payment.api.feign.PaymentFeignService;
import com.sckw.payment.api.model.constant.ChannelEnum;
import com.sckw.payment.api.model.dto.WalletDto;
import com.sckw.payment.api.model.dto.common.R;
import com.sckw.payment.api.model.feign.WalletPrepaidDto;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.AddressInfoDetail;
import com.sckw.product.api.model.GoodsDetail;
import com.sckw.product.api.model.GoodsUnitDetail;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.SckwBusSum;
import com.sckw.stream.model.SckwMessage;
import com.sckw.stream.model.UserInfo;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.feign.DataPermissionFeignService;
import com.sckw.system.api.model.dto.req.ActualDisPatchDto;
import com.sckw.system.api.model.dto.req.DataPermissionFilterReqDto;
import com.sckw.system.api.model.dto.res.*;
import com.sckw.transport.api.dubbo.ParkingWalletFeeRemoteService;
import com.sckw.transport.api.dubbo.TransportRemoteStatisticsService;
import com.sckw.transport.api.dubbo.TransportRemoteService;
import com.sckw.transport.api.feign.ParkingWalletFeeFeignService;
import com.sckw.transport.api.model.dto.RawOreOrderExecutionDto;
import com.sckw.transport.api.model.dto.TradeOrderWaybillAggDto;
import com.sckw.transport.api.model.param.AddLogisticOrderParam;
import com.sckw.transport.api.model.param.LogisticInfo;
import com.sckw.transport.api.model.param.OrderFinishParam;
import com.sckw.transport.api.model.param.ParkingWalletFeeFreezeParam;
import com.sckw.transport.api.model.vo.KwtLogisticsOrderVO;
import com.sckw.transport.api.model.vo.LogisticContractVo;
import com.sckw.transport.api.model.vo.ParkingWalletFeeFreezeResult;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @desc: 交易订单（采购订单/销售订单）service
 * @author: yzc
 * @date: 2023-06-25 14:28
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class KwoTradeOrderService {

    /**
     * Fixed enterprise scope for the public BI dashboard.
     */
    private static final List<Long> REPORT_ENT_IDS = List.of(
            538038314096136193L,
            538039617157337089L,
            538040297439891457L
    );

    private static final int ORDER_EXECUTION_DISPLAY_LIMIT = 500;

    /**
     * 贸易合同/贸易订单代理单位类型。
     */
    static final String AGENT_UNIT_TYPE = "3";

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteUserService remoteUserService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteManageService remoteManageService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private GoodsInfoService goodsInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteContractService remoteContractService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private PayCenterDubboService payCenterDubboService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private PaymentDubboService paymentDubboService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportRemoteService transportRemoteService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    private TransportRemoteStatisticsService transportRemoteStatisticsService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    protected RemoteFleetService remoteFleetService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    private ParkingWalletFeeRemoteService parkingWalletFeeRemoteService;

    @Autowired
    private ParkingWalletFeeFeignService parkingWalletFeeFeignService;


    @Autowired
    private PaymentFeignService paymentFeignService;

    private final KwoTradeOrderMapper kwoTradeOrderMapper;
    private final KwoTradeOrderArchiveMapper kwoTradeOrderArchiveMapper;
    private final StreamBridge streamBridge;
    private final KwoTradeOrderAddressService kwoTradeOrderAddressService;
    private final KwoTradeOrderUnitService kwoTradeOrderUnitService;
    private final KwoTradeOrderGoodsService kwoTradeOrderGoodsService;
    private final KwoTradeOrderContractService kwoTradeOrderContractService;
    private final KwoTradeOrderTrackService kwoTradeOrderTrackService;
    private final KwoTradeOrderGoodsUnitService kwoTradeOrderGoodsUnitService;
    private final KwoTradeOrderAmountService tradeOrderAmountService;
    private final KwoTradeOrderTransportService kwoTradeOrderTransportService;
    private final KwoTradeOrderUnitRepository kwoTradeOrderUnitRepository;
    @Resource
    private KwoTradeOrderGoodsMapper kwoTradeOrderGoodsMapper;
    @Resource
    private DataPermissionFeignService dataPermissionFeignService;
    @Value("${url.order.list.valet.pc}")
    private String pcValetListUrl;

    @Value("${url.order.list.valet.app}")
    private String appValetListUrl;

    @Value("${url.order.list.purchase.pc}")
    private String pcPurchaseListUrl;

    @Value("${url.order.list.purchase.app}")
    private String appPurchaseListUrl;

    /**
     * @desc: 采购下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderDraft(PurchaseOrderDraftParam param) {
        KwoTradeOrder order = BeanUtil.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(getOrderNo()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null).setSource(OrderSourceEnum.PURCHASE.getType()).setStatus(OrderStatusEnum.SAVED.getCode());
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtil.copyProperties(param, ValetOrderParam.class), false, true);
    }

    /**
     * @desc: 添加其他订单信息
     * @author: yzc
     * @date: 2023-07-13 8:53
     * @Param tradeOrder:
     * @Param param:
     * @Param isUpdate:
     * @return: void
     */
    private void addOtherOrderInfo(KwoTradeOrder tradeOrder, ValetOrderParam param, Boolean isUpdate, boolean isDraft) {
        Long id = tradeOrder.getId();
        String tOrderNo = tradeOrder.getTOrderNo();
        SckwTradeOrder order = new SckwTradeOrder();
        order.setFirmName(LoginUserHolder.getEntName()).setCreateByName(LoginUserHolder.getUserName()).setUpdateByName(LoginUserHolder.getUserName()).setTOrderId(id).setAssociateStatement(0).setPrice(Objects.isNull(tradeOrder.getPrice()) ? null : tradeOrder.getPrice().doubleValue()).setAmount(Objects.isNull(tradeOrder.getAmount()) ? null : tradeOrder.getAmount().doubleValue()).setEntrustAmount(Objects.isNull(tradeOrder.getEntrustAmount()) ? null : tradeOrder.getEntrustAmount().doubleValue()).setActualAmount(Objects.isNull(tradeOrder.getActualAmount()) ? null : tradeOrder.getActualAmount().doubleValue());

        BeanUtil.copyProperties(tradeOrder, order);

        //商品信息
        kwoTradeOrderGoodsService.delByOrderId(id);
        GoodsInfo goodsInfo = param.getGoodsInfo();
        KwoTradeOrderGoods goods = BeanUtil.copyProperties(goodsInfo, KwoTradeOrderGoods.class);
        if (Objects.nonNull(goods) && Objects.nonNull(goods.getGoodsId())) {
            GoodsDetail goodsDetail = goodsInfoService.getDetailById(goods.getGoodsId());
            if (Objects.isNull(goodsDetail) || !Objects.equals(goodsDetail.getStatus(), 1) || Objects.equals(goodsDetail.getDelFlag(), Global.YES)) {
                throw new BusinessException("商品不存在或已下架！");
            }
            goods.setTOrderId(id).setTOrderNo(tOrderNo).setGoodsType(goodsDetail.getGoodsType());
            kwoTradeOrderGoodsService.insert(goods);

            //商品辅助单位
            kwoTradeOrderGoodsUnitService.delByOrderId(id);
            List<GoodsUnitDetail> assistUnit = goodsDetail.getAssistUnit();
            if (CollUtil.isNotEmpty(assistUnit)) {
                List<KwoTradeOrderGoodsUnit> units = new ArrayList<>(assistUnit.size());
                assistUnit.forEach(e -> {
                    KwoTradeOrderGoodsUnit unit = BeanUtil.copyProperties(e, KwoTradeOrderGoodsUnit.class);
                    unit.setGoodsId(goodsDetail.getId());
                    unit.setTOrderId(id);
                    unit.setUnit(order.getUnit().equals(e.getFromUnit()) ? e.getToUnit() : e.getFromUnit());
                    units.add(unit);
                });
                kwoTradeOrderGoodsUnitService.insertBatch(units);
            }

            //订单关联商品信息
            order.setGoodsId(goodsDetail.getId()).setUnit(goodsDetail.getUnit()).setUnitPrice(goods.getUnitPrice().doubleValue()).setGoodsName(goodsDetail.getName()).setGoodsType(goodsDetail.getGoodsType()).setGoodsCode(goodsDetail.getCode()).setGoodsTaxRate(goodsDetail.getTaxRate()).setGoodsSpec(goodsDetail.getSpec()).setGoodsThumb(goodsDetail.getThumb());
        }
        if (Objects.isNull(order.getUnitPrice())) {
            order.setUnitPrice(BigDecimal.ZERO.doubleValue());
        }

        //单位信息
        kwoTradeOrderUnitService.delByOrderId(id);
        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollUtil.isNotEmpty(unitInfos)) {
            List<KwoTradeOrderUnit> list = new ArrayList<>(unitInfos.size());
            List<Long> entIds = unitInfos.stream().map(UnitInfo::getEntId).distinct().toList();
            Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
            unitInfos.forEach(e -> {
                EntCacheResDto ent = entMap.get(e.getEntId());
                if (Objects.isNull(ent)) {
                    throw new BusinessException("企业:" + e.getFirmName() + "的一级企业信息不存在！");
                }
                KwoTradeOrderUnit unit = BeanUtil.copyProperties(e, KwoTradeOrderUnit.class);
                unit.setTOrderId(id).setTOrderNo(tOrderNo).setTopEntId(ent.getId());
                list.add(unit);
                if (Objects.equals(e.getUnitType(), OrderUnitTypeEnum.PURCHASE.getType())) {
                    order.setProcureEntId(e.getEntId()).setProcureTopEntId(unit.getTopEntId()).setProcureFirmName(e.getFirmName()).setProcureContacts(e.getContacts()).setProcurePhone(e.getPhone()).setProcureContactsId(e.getContactsId());
                } else {
                    order.setSupplyEntId(e.getEntId()).setSupplyTopEntId(unit.getTopEntId()).setSupplyFirmName(e.getFirmName()).setSupplyContacts(e.getContacts()).setSupplyPhone(e.getPhone()).setSupplyContactsId(e.getContactsId());
                }
            });
            kwoTradeOrderUnitService.insertBatch(list);
        }

        //地址信息
        kwoTradeOrderAddressService.delByOrderId(id);
        tradeOrderAmountService.delByOrderId(id);
        List<AddressInfoDto> addressInfoDtos = param.getAddressInfoDto();
        if (CollUtil.isNotEmpty(addressInfoDtos)) {
            BigDecimal amount = Objects.isNull(param.getAmount()) ? BigDecimal.ZERO : param.getAmount();
            if (!isDraft) {
                boolean isPurchase = OrderSourceEnum.PURCHASE.getType().equals(tradeOrder.getSource());
                if (isPurchase) {
                    List<AddressInfoDto> loadAddress = addressInfoDtos.stream().filter(e -> Objects.equals(e.getAddressType(), OrderAddressTypeEnum.LOAD.getType())).toList();
                    if (CollUtil.isEmpty(loadAddress) || loadAddress.size() != 1) {
                        throw new BusinessException("采购下单装货地址信息有误！");
                    }
                }
                BigDecimal totalLoadAmount = BigDecimal.ZERO;
                BigDecimal totalUnloadAmount = BigDecimal.ZERO;
                boolean loadFlag = false;
                boolean unloadFlag = false;
                for (AddressInfoDto e : addressInfoDtos) {
                    if (Objects.equals(e.getAddressType(), OrderAddressTypeEnum.LOAD.getType())) {
                        if (isPurchase) {
                            e.setAmount(amount);
                        }
                        totalLoadAmount = totalLoadAmount.add(e.getAmount());
                        loadFlag = true;
                    } else {
                        totalUnloadAmount = totalUnloadAmount.add(e.getAmount());
                        unloadFlag = true;
                    }
                }
                if (loadFlag && totalLoadAmount.compareTo(amount) != 0) {
                    throw new BusinessException("装货分配量总量与订单总量不符！");
                }
                if (unloadFlag && totalUnloadAmount.compareTo(amount) != 0) {
                    throw new BusinessException("卸货分配量总量与订单总量不符！");
                }
            }
            AtomicInteger loadSort = new AtomicInteger(0);
            AtomicInteger unloadSort = new AtomicInteger(0);
            addressInfoDtos.forEach(e -> {
                KwoTradeOrderAddress address = BeanUtil.copyProperties(e, KwoTradeOrderAddress.class);
                address.setTOrderId(id).setTOrderNo(tOrderNo);
                //todo MongoDB如何存多个地址信息？
                if (Objects.equals(address.getAddressType(), OrderAddressTypeEnum.LOAD.getType())) {
                    address.setSort(loadSort.getAndIncrement());
                    order.setLoadName(e.getName()).setLoadType(e.getType()).setLoadContacts(e.getContacts()).setLoadPhone(e.getPhone()).setLoadCityCode(String.valueOf(e.getCityCode())).setLoadCityName(e.getCityName()).setLoadDetailAddress(e.getDetailAddress()).setLoadLat(e.getLat()).setLoadLng(e.getLng());
                } else {
                    address.setSort(unloadSort.getAndIncrement());
                    order.setUnloadName(e.getName()).setUnloadType(e.getType()).setUnloadContacts(e.getContacts()).setUnloadPhone(e.getPhone()).setUnloadCityCode(String.valueOf(e.getCityCode())).setUnloadCityName(e.getCityName()).setUnloadDetailAddress(e.getDetailAddress()).setUnloadLat(e.getLat()).setUnloadLng(e.getLng());
                }
                //地址信息
                Long addressId = kwoTradeOrderAddressService.add(address);
                //分配量信息
                KwoTradeOrderAmount orderAmount = new KwoTradeOrderAmount();
                orderAmount.setTOrderId(id).setAmount(e.getAmount()).setTAddressId(addressId);
                tradeOrderAmountService.add(orderAmount);
            });
        }

        //合同信息
        kwoTradeOrderContractService.delByOrderId(id);
        ContractInfo contractInfo = param.getContractInfo();
        KwoTradeOrderContract contract = BeanUtil.copyProperties(contractInfo, KwoTradeOrderContract.class);
        if (Objects.nonNull(contract)) {
            contract.setTOrderId(id).setTOrderNo(tOrderNo);
            kwoTradeOrderContractService.insert(contract);
            BeanUtil.copyProperties(contractInfo, order);
        }

        //状态信息（草稿更新不加状态记录）
        if (!isUpdate || !Objects.equals(OrderStatusEnum.SAVED.getCode(), tradeOrder.getStatus())) {
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(id).setTOrderNo(tOrderNo).setStatus(tradeOrder.getStatus()).setRemark(tradeOrder.getRemark());
            kwoTradeOrderTrackService.insert(track);
        }
        int method = isUpdate ? 2 : 1;
        //存MongoDb
        saveMongoDb(method, order);
    }

    /**
     * @desc: mq保存mongodb
     * @author: yzc
     * @date: 2023-07-17 8:43
     * @Param method:
     * @Param order:
     * @return: void
     */
    private void saveMongoDb(Integer method, Object order) {
        SckwBusSum busSum = new SckwBusSum();
        busSum.setBusSumType("tradeOrder");
        busSum.setMethod(method);
        busSum.setObject(order);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }


    /**
     * @desc: 代客下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addValetOrderDraft(ValetOrderDraftParam param) {
        KwoTradeOrder order = BeanUtil.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(getOrderNo()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null).setSource(OrderSourceEnum.SALE.getType()).setStatus(OrderStatusEnum.SAVED.getCode());
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtil.copyProperties(param, ValetOrderParam.class), false, true);
    }

    /**
     * @desc: 采购下单提交
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderSubmit(PurchaseOrderParam param) {
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo.getPriceRangeId())) {
            throw new BusinessException("采购下单价格梯度信息不能为空！");
        }
        OrderCheckDTO orderCheck = BeanUtil.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, param.getUnitInfo());
        orderCheck.setGoodsId(goodsInfo.getGoodsId()).setUnitPrice(goodsInfo.getUnitPrice()).setOrderSource(OrderSourceEnum.PURCHASE.getType());
        orderCheck(orderCheck, false);
        KwoTradeOrder order = BeanUtil.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(getOrderNo()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setUnit(param.getGoodsInfo().getUnit()).setSource(OrderSourceEnum.PURCHASE.getType()).setStatus(OrderStatusEnum.WAIT_ACCEPTED.getCode());
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //添加订单其他信息
        addOtherOrderInfo(order, BeanUtil.copyProperties(param, ValetOrderParam.class), false, false);
        //发送消息提醒
        submitOrderSendMsg(orderCheck, order.getTOrderNo());
    }

    /**
     * @desc: 提交订单发送message
     * @author: yzc
     * @date: 2023-09-01 14:35
     * @Param orderCheck:
     * @Param orderNo:
     * @return: void
     */
    private void submitOrderSendMsg(OrderCheckDTO orderCheck, String orderNo) {
        Map<String, Object> map = CollectionUtils.createHashMap();
        map.put("orderNo", orderNo);
        List<UserInfo> userInfos = new ArrayList<>();
        //提交人信息
        UserInfo createUser = new UserInfo();
        createUser.setUserId(LoginUserHolder.getUserId()).setEntId(LoginUserHolder.getEntId());
        userInfos.add(createUser);
        boolean flag = Objects.equals(orderCheck.getOrderSource(), OrderSourceEnum.PURCHASE.getType());
        UserInfo procureUser = orderCheck.getProcureUser();
        String procureFireName = orderCheck.getProcureFireName();
        UserInfo supplyUser = orderCheck.getSupplyUser();
        String supplyFireName = orderCheck.getSupplyFireName();
        //采购下单
        if (flag) {
            //给创建人及采购联系人发消息
            map.put("firmName", supplyFireName);
            if (!Objects.equals(procureUser.getUserId(), LoginUserHolder.getUserId())) {
                userInfos.add(procureUser);
            }
            sendMsg(MessageEnum.ORDER_INITIATE_PURCHASE, map, pcPurchaseListUrl, appPurchaseListUrl, userInfos);
            //给供应企业联系人发消息
            map.put("firmName", procureFireName);
            sendMsg(MessageEnum.ORDER_NEW_PENDING, map, pcValetListUrl, appValetListUrl, List.of(supplyUser));
        } else {
            //代客下单
            //给创建人及供应企业联系人发消息
            map.put("firmName", procureFireName);
            if (!Objects.equals(supplyUser.getUserId(), LoginUserHolder.getUserId())) {
                userInfos.add(supplyUser);
            }
            sendMsg(MessageEnum.ORDER_INITIATE_SALE, map, pcValetListUrl, appValetListUrl, userInfos);
            //给采购企业联系人发消息
            map.put("firmName", supplyFireName);
            sendMsg(MessageEnum.ORDER_NEW_VALET_MSG, map, pcPurchaseListUrl, appPurchaseListUrl, List.of(procureUser));
        }
    }

    /**
     * @desc: 发送消息
     * @author: yzc
     * @date: 2023-09-06 15:57
     * @Param msgEnum: 消息枚举
     * @Param params: 消息变量
     * @Param pcUrl: pc消息调转url
     * @Param appUrl: app消息调转url
     * @Param userInfos:  发送消息用户集合
     * @return: void
     */
    private void sendMsg(MessageEnum msgEnum, Map<String, Object> params, String pcUrl, String appUrl, List<UserInfo> userInfos) {
        Map<String, String> urls = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        urls.put(ClientTypeEnum.pc.getValue(), pcUrl);
        urls.put(ClientTypeEnum.app.getValue(), appUrl);
        SckwMessage msg = new SckwMessage(msgEnum);
        msg.setParams(params).setMsgUrls(urls).setUserInfos(userInfos).setCreateBy(LoginUserHolder.getUserId());
        log.info("有新的提醒消息：{}", JSON.toJSONString(msg));
        streamBridge.send("sckw-message", JSON.toJSONString(msg));
    }

    /**
     * @desc: 获取采购销售顶级企业id
     * @author: yzc
     * @date: 2023-07-25 10:03
     * @Param orderCheck:
     * @Param unitInfo:
     * @return: void
     */
    private void getTopEnt(OrderCheckDTO orderCheck, List<UnitInfo> unitInfo) {
        List<Long> entIds = unitInfo.stream().map(UnitInfo::getEntId).toList();
        Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
        unitInfo.forEach(e -> {
            Long entId = e.getEntId();
            EntCacheResDto ent = entMap.get(entId);
            if (Objects.isNull(ent)) {
                log.error("企业：{}找不到对应一级企业信息", entId);
                throw new BusinessException("一级企业信息不存在！");
            }
            if (Objects.equals(e.getUnitType(), OrderUnitTypeEnum.PURCHASE.getType())) {
                UserInfo procureUser = new UserInfo();
                orderCheck.setProcureTopEntId(ent.getId());
                orderCheck.setProcureEntId(entId);
                orderCheck.setProcureFireName(e.getFirmName());
                procureUser.setUserId(e.getContactsId()).setEntId(ent.getId());
                orderCheck.setProcureUser(procureUser);
            } else {
                UserInfo supplyUser = new UserInfo();
                orderCheck.setSupplyTopEntId(ent.getId());
                orderCheck.setSupplyEntId(entId);
                orderCheck.setSupplyFireName(e.getFirmName());
                supplyUser.setUserId(e.getContactsId()).setEntId(ent.getId());
                orderCheck.setSupplyUser(supplyUser);
            }
        });
    }

    /**
     * @desc: 订单提交校验
     * @author: yzc
     * @date: 2023-07-14 14:46
     * @Param param: 订单校验参数
     * @Param isAcceptanceOrder: 是否受理订单
     * @return: void
     */
    private void orderCheck(OrderCheckDTO param, Boolean isAcceptanceOrder) {
        BigDecimal amount = param.getAmount();
        String trading = param.getTrading();
        BigDecimal price = param.getPrice();
        KwpGoods goods = goodsInfoService.getGoodsById(param.getGoodsId());
        if (Objects.isNull(goods) || Objects.equals(goods.getDelFlag(), Global.YES)) {
            throw new BusinessException("商品不存在！");
        }
        if (Boolean.FALSE.equals(isAcceptanceOrder)) {
            if (price.compareTo(amount.multiply(param.getUnitPrice())) != 0) {
                throw new BusinessException("订单总金额不等于商品单价*订单总量！");
            }
            List<FindEntCooperateResVo> entCooperate;
            if (OrderSourceEnum.PURCHASE.getType().equals(param.getOrderSource())) {
                entCooperate = remoteManageService.findEntCooperate(param.getProcureEntId(), param.getSupplyEntId(), CooperateTypeEnum.SUPPLIER.getCode());
            } else {
                entCooperate = remoteManageService.findEntCooperate(param.getSupplyEntId(), param.getProcureEntId(), CooperateTypeEnum.PURCHASER.getCode());
            }
            if (CollectionUtils.isEmpty(entCooperate)) {
                throw new BusinessException("供采双方企业无合作关系！");
            }
            if (goods.getAmount().compareTo(amount) < 0) {
                throw new BusinessException("商品库存不足，请联系供应方！");
            }
        }
        //支付方式预付款校验
        if (trading.startsWith("1")) {
            BigDecimal decimal = Objects.isNull(goods.getAdvancePrice()) ? BigDecimal.ZERO : goods.getAdvancePrice();
            BigDecimal advancePrice = decimal.multiply(new BigDecimal("10000"));
            //直接采购下单才校验预付款限额
            if (Objects.equals(param.getOrderSource(), OrderSourceEnum.PURCHASE.getType()) && price.compareTo(advancePrice) < 0) {
                throw new BusinessException("您的订单总额未达到预付限额，请确认");
            }
            R<List<WalletDto>> wallet = payCenterDubboService.wallet(param.getProcureTopEntId(), ChannelEnum.getByCode(trading), param.getSupplyTopEntId());
            if (Objects.isNull(wallet) || Objects.equals(wallet.getCode(), 0)) {
                throw new BusinessException("校验预付钱包异常，请联系管理员！");
            }
            List<WalletDto> data = wallet.getData();
            if (CollectionUtils.isEmpty(data)) {
                throw new BusinessException("检测尚未创建对应预付款清单，请先创建！");
            }
            long money = data.get(0).getApMoney();
            if (money < advancePrice.multiply(new BigDecimal("100")).longValueExact()) {
                throw new BusinessException("您的预付清单可用余额不足，请先充值！");
            }
        }
    }

    /**
     * @desc: 代客下单提交
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param param:
     * @return: void
     */
    public void addValetOrderSubmit(ValetOrderParam param) {
        OrderCheckDTO orderCheck = BeanUtil.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, param.getUnitInfo());
        orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice()).setOrderSource(OrderSourceEnum.SALE.getType());
        orderCheck(orderCheck, false);
        ContractInfo contract = param.getContractInfo();
        contractCheck(contract);
        param.setContractInfo(contract);
        KwoTradeOrder order = BeanUtil.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(getOrderNo()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setUnit(param.getGoodsInfo().getUnit()).setSource(OrderSourceEnum.SALE.getType());
        String contractStatus = contract.getContractStatus();
        if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
        } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.EXECUTING.getCode());
        } else {
            throw new BusinessException("Invalid contract status");
        }
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //冻结金额
        if (param.getTrading().startsWith("1")) {
            HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(), ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                throw new BusinessException(freezeResult.getMsg());
            }
        }
        addOtherOrderInfo(order, BeanUtil.copyProperties(param, ValetOrderParam.class), false, false);
        //发送消息提醒
        submitOrderSendMsg(orderCheck, order.getTOrderNo());
    }


    /**
     * 生成贸易订单号
     *
     * @return 订单编号
     */
    private String getOrderNo() {
        Date date = new Date();
        String lockKey = String.format(RedisConstant.TORDER_NO_GENERATE_KEY, DateUtils.formatDateToYYMMDD(date));
        String key = OrderGenerateSeqNoUtils.getKey(RedisOrderGenerateEnum.TRADE_ORDER, OrderRuleEnum.TRADE_ORDER, date);
        try {
            if (Boolean.FALSE.equals(RedissonUtils.exists(key))) {
                if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
                    throw new BusinessException("业务繁忙，请稍后再试！");
                }
                DateTime dateTime = DateUtil.beginOfDay(date);
                String maxOrderNo = kwoTradeOrderMapper.getMaxOrderNoByDate(dateTime);
                if (StringUtils.isNotBlank(maxOrderNo)) {
                    Long maxNum = Long.valueOf(StringUtils.subStrFromIndexToEnd(maxOrderNo, 4));
                    RedissonUtils.setAtomicLong(key, maxNum, DateUtils.getSecondsDay());
                }
            }
            return OrderGenerateSeqNoUtils.getOtherSeqNo(RedisOrderGenerateEnum.TRADE_ORDER, OrderRuleEnum.TRADE_ORDER);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
    }

    /**
     * @desc: 合同校验
     * @author: yzc
     * @date: 2023-08-24 10:54
     * @Param contract:
     * @return: void
     */
    private void contractCheck(ContractInfo contract) {
        Map<Long, ContractCommonInfoResDto> map = remoteContractService.queryContractBaseInfo(List.of(contract.getContractId()));
        ContractCommonInfoResDto contractInfo = map.get(contract.getContractId());
        if (Objects.isNull(contractInfo)) {
            throw new BusinessException("不存在该合同信息！");
        }
        Integer status = contractInfo.getStatus();
        if (!Objects.equals(0, status) && !Objects.equals(1, status)) {
            throw new BusinessException("合同状态异常！");
        }
        contract.setContractName(contract.getContractName());
        contract.setContractNo(contractInfo.getContractCode());
        contract.setContractSigningWay(contractInfo.getSigningWayName());
        contract.setContractStatus(String.valueOf(status));
    }

    /**
     * @desc: 获取订单详情
     * @author: yzc
     * @date: 2023-08-18 11:18
     * @Param id:
     * @return: com.sckw.order.model.vo.res.OrderDetailRes
     */
    public OrderDetailRes getDetail(Long id) {
        OrderDetailRes detail = this.detail(id);
        List<KwoTradeOrderTrack> tracks = kwoTradeOrderTrackService.getByOrderId(id);
        if (CollectionUtils.isEmpty(tracks)) {
            return detail;
        }
        List<OrderProcess> orderProcesses = new ArrayList<>(tracks.size());
        List<Long> createBys = tracks.stream().map(KwoTradeOrderTrack::getCreateBy).distinct().toList();
        Map<Long, UserCacheResDto> map = remoteSystemService.queryUserCacheMapByIds(createBys);
        List<Integer> statusList = Arrays.asList(TradeOrderStatusEnum.AUDIT.getCode(), TradeOrderStatusEnum.ING.getCode(), TradeOrderStatusEnum.DEAL.getCode());
        tracks.forEach(e -> {
            OrderProcess process = BeanUtil.copyProperties(e, OrderProcess.class);
            UserCacheResDto user = map.get(process.getCreateBy());
            if (Objects.nonNull(user)) {
                process.setCreateByName(user.getName());
                if (CollUtil.isNotEmpty(user.getRoleInfo())) {
                    List<String> roleNames = user.getRoleInfo().stream().map(KwsRoleResDto::getName).distinct().toList();
                    process.setRoleName(String.join(",", roleNames));
                }
            }
            if (statusList.contains(process.getStatus())) {
                if (Objects.equals(process.getStatus(), TradeOrderStatusEnum.AUDIT.getCode())) {
                    process.setStatusLabel("订单创建");
                }
                if (Objects.equals(process.getStatus(), TradeOrderStatusEnum.ING.getCode())) {
                    process.setStatusLabel("审核");
                }
                if (Objects.equals(process.getStatus(), TradeOrderStatusEnum.DEAL.getCode())) {
                    process.setStatusLabel("结算");
                }
                orderProcesses.add(process);
            }
        });
        List<OrderProcess> orderProcesses1 = orderProcesses.stream().sorted(Comparator.comparing(OrderProcess::getCreateTime).reversed()).collect(Collectors.toList());

        detail.setOrderProcess(orderProcesses1);
        return detail;
    }

    /**
     * @desc: 订单详情
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param id:
     * @return: com.sckw.order.model.vo.res.OrderDetail
     */
    public OrderDetailRes detail(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("不存在该订单！");
        }
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.TRADE_TYPE.getType(), DictTypeEnum.PICKUP_TYPE.getType(), DictTypeEnum.DELIVERY_TYPE.getType(), DictTypeEnum.TORDER_SOURCE.getType(), DictTypeEnum.TORDER_STATUS.getType(), DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.UNIT_TYPE.getType(), DictTypeEnum.TAX_RATE.getType(), DictTypeEnum.TORDER_UNIT_TYPE.getType(), DictTypeEnum.TORDER_ADDRESS_TYPE.getType(), DictTypeEnum.ADDRESS_TYPE.getType(), DictTypeEnum.CONSIGNMENT_WAY.getType(), DictTypeEnum.CHARGING_TYPE.getType(), DictTypeEnum.GOODS_SPEC.getType()));
        Map<String, String> pickupMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> deleveryMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> sourceMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> statusMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> prodcutNameMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> unitMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> taxRateMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> chargeTypeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> consignmentWayMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> goodspec = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        Map<String, String> orderUnitMap, orderAddressMap, addressMap;
        if (CollUtil.isNotEmpty(dict)) {
            pickupMap = dict.get(DictTypeEnum.CONSIGNMENT_WAY.getType());
            deleveryMap = dict.get(DictTypeEnum.DELIVERY_TYPE.getType());
            sourceMap = dict.get(DictTypeEnum.TORDER_SOURCE.getType());
            statusMap = dict.get(DictTypeEnum.TORDER_STATUS.getType());
            prodcutNameMap = dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType());
            unitMap = dict.get(DictTypeEnum.UNIT_TYPE.getType());
            taxRateMap = dict.get(DictTypeEnum.TAX_RATE.getType());
            orderUnitMap = dict.get(DictTypeEnum.TORDER_UNIT_TYPE.getType());
            orderAddressMap = dict.get(DictTypeEnum.TORDER_ADDRESS_TYPE.getType());
            addressMap = dict.get(DictTypeEnum.ADDRESS_TYPE.getType());
            chargeTypeMap = dict.get(DictTypeEnum.CHARGING_TYPE.getType());
            consignmentWayMap = dict.get(DictTypeEnum.CONSIGNMENT_WAY.getType());
            goodspec = dict.get(DictTypeEnum.GOODS_SPEC.getType());
        } else {
            orderUnitMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            orderAddressMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            addressMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        }
        //订单基本信息
        OrderDetailRes detail = BeanUtil.copyProperties(order, OrderDetailRes.class);
        UserCacheResDto createUser = remoteSystemService.queryUserCacheById(detail.getCreateBy());
        EntCacheResDto ent = remoteSystemService.queryEntCacheById(detail.getEntId());
        String trading = order.getTrading();
        if (StrUtil.equals(trading, "1")) {
            detail.setTradingLabel("线上支付");
        } else {
            detail.setTradingLabel("线下支付");
        }
        detail.setFirmName(Objects.isNull(ent) ? null : ent.getFirmName()).setCreateByName(Objects.isNull(createUser) ? null : createUser.getName());
        detail.setPickupTypeLabel(CollUtil.isNotEmpty(pickupMap) ? pickupMap.get(detail.getPickupType()) : null).setDeliveryTypeLabel(CollUtil.isNotEmpty(deleveryMap) ? deleveryMap.get(detail.getDeliveryType()) : null);
        detail.setSourceLabel(CollUtil.isNotEmpty(sourceMap) ? sourceMap.get(detail.getSource()) : null).setStatusLabel(TradeOrderStatusEnum.getMsg(detail.getStatus()));
        detail.setChargeTypeLabel(CollUtil.isNotEmpty(chargeTypeMap) ? chargeTypeMap.get(String.valueOf(detail.getChargeType())) : null);
        detail.setConsignmentWayLabel(DictEnum.getLabel(DictTypeEnum.CONSIGNMENT_WAY.getType(), String.valueOf(detail.getConsignmentWay())));
        if (Objects.equals(detail.getChargeType(), 1)) {//按装货量
            detail.setDealAmount(detail.getLoadAmount());
        } else {
            detail.setDealAmount(detail.getUnloadAmount());
        }
        //商品信息
        KwoTradeOrderGoods orderGoods = kwoTradeOrderGoodsService.getByOrderId(id);
        if (Objects.nonNull(orderGoods)) {
            KwpGoods goods = goodsInfoService.getGoodsById(orderGoods.getGoodsId());
            if (Objects.nonNull(goods)) {
                EntCacheResDto entCache = remoteSystemService.queryEntCacheById(goods.getEntId());
                GoodsInfoDetailRes goodsDetail = new GoodsInfoDetailRes();
                goodsDetail.setGoodsTypeLabel(CollUtil.isNotEmpty(prodcutNameMap) ? prodcutNameMap.get(goods.getGoodsType()) : null).setUnitLabel(CollUtil.isNotEmpty(unitMap) ? unitMap.get(goods.getUnit()) : null).setTaxRateLabel(CollUtil.isNotEmpty(taxRateMap) ? taxRateMap.get(goods.getTaxRate()) : null).setGoodsAmount(goods.getAmount()).setGoodsId(goods.getId()).setCode(goods.getCode()).setName(goods.getName()).setGoodsType(goods.getGoodsType()).setTaxRate(goods.getTaxRate()).setSpec(goods.getSpec()).setUnit(goods.getUnit()).setPriceRangeId(orderGoods.getPriceRangeId()).setUnitPrice(orderGoods.getUnitPrice()).setSkuId(orderGoods.getSkuId()).setCollectionUnitId(goods.getEntId()).setGoodsThumb(goods.getThumb()).setPrepaidLimit(goods.getPrepaidLimit()).setAdvancePrice(goods.getAdvancePrice()).setCollectionUnit(Objects.isNull(entCache) ? null : entCache.getFirmName());
                goodsDetail.setSpec(CollUtil.isNotEmpty(goodspec) ? goodspec.get(goods.getSpec()) : null);
                detail.setGoodsInfo(goodsDetail);
                if (Objects.equals(detail.getChargeType(), 1)) {//按装货量
                    detail.setDealMoney(NumberUtil.mul(orderGoods.getUnitPrice(), detail.getLoadAmount()));
                } else {
                    detail.setDealMoney(NumberUtil.mul(orderGoods.getUnitPrice(), detail.getUnloadAmount()));
                }

            }
        }

        //单位信息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(id);
        if (CollUtil.isNotEmpty(units)) {
            List<UnitInfoDetailRes> unitInfos = new ArrayList<>(units.size());
            units.forEach(e -> {
                UnitInfoDetailRes unit = BeanUtil.copyProperties(e, UnitInfoDetailRes.class);
                unit.setUnitTypeLabel(CollUtil.isNotEmpty(orderUnitMap) ? orderUnitMap.get(unit.getUnitType()) : null);
                unitInfos.add(unit);
            });
            detail.setUnitInfo(unitInfos);
        }
        //地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderId(id);
        if (CollUtil.isNotEmpty(addressList)) {
            //分配量信息
            List<KwoTradeOrderAmount> amountList = tradeOrderAmountService.getByOrderId(id);
            Map<Long, KwoTradeOrderAmount> amountMap = amountList.stream().collect(Collectors.toMap(KwoTradeOrderAmount::getTAddressId, e -> e, (k1, k2) -> k1));
            List<AddressInfoDtoDetailRes> addressInfoDetails = new ArrayList<>(addressList.size());
            addressList.forEach(e -> {
                AddressInfoDtoDetailRes address = BeanUtil.copyProperties(e, AddressInfoDtoDetailRes.class);
                address.setAddressTypeLabel(CollUtil.isNotEmpty(orderAddressMap) ? orderAddressMap.get(address.getAddressType()) : null);
                address.setTypeLabel(CollUtil.isNotEmpty(addressMap) ? addressMap.get(address.getType()) : null);
                KwoTradeOrderAmount orderAmount = amountMap.get(e.getId());
                if (Objects.nonNull(orderAmount)) {
                    address.setAmount(orderAmount.getAmount());
                }
                addressInfoDetails.add(address);
            });
            detail.setAddressInfo(addressInfoDetails);
        }
        //合同信息
        KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(id);
        if (Objects.nonNull(contract)) {
            ContractInfo contractInfo = BeanUtil.copyProperties(contract, ContractInfo.class);
            Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(List.of(contractInfo.getContractId()));
            ContractCommonInfoResDto contractRes = contractMap.get(contractInfo.getContractId());
            if (Objects.nonNull(contractRes)) {
                contractInfo.setContractName(contractRes.getContactName());
                contractInfo.setContractSigningWay(contractRes.getSigningWayName());
                contractInfo.setContractStatus(contractRes.getStatusName());
                contractInfo.setDispatchWay(contractRes.getDispatchWay());
            }
            detail.setContractInfo(contractInfo);
        }
        //物流合同信息和承运单位信息
        List<KwoTradeOrderTransport> list = kwoTradeOrderTransportService.queryList(id);
        if (CollUtil.isNotEmpty(list)) {
            Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(list.stream().map(KwoTradeOrderTransport::getContractId).collect(Collectors.toList()));

            List<ContractInfo> collect = list.stream().map(d -> {
                ContractInfo contractInfo = new ContractInfo();
                contractInfo.setContractId(d.getContractId());
                contractInfo.setContractNo(d.getContractNo());
                Optional.ofNullable(contractMap.get(d.getContractId())).ifPresent(c -> {
                    contractInfo.setContractName(c.getContactName());
                    contractInfo.setContractSigningWay(c.getSigningWayName());
                    contractInfo.setContractStatus(c.getStatusName());
                    contractInfo.setDispatchWay(c.getDispatchWay());
                });
                return contractInfo;
            }).collect(Collectors.toList());
            detail.setContractInfoList(collect);

            List<TransportUnitInfo> collect1 = list.stream().map(d -> {
                TransportUnitInfo transportUnitInfo = new TransportUnitInfo();
                transportUnitInfo.setEntId(d.getEntId());
                transportUnitInfo.setFirmName(d.getFirmName());
                transportUnitInfo.setTransportPrice(d.getTransportPrice());
                transportUnitInfo.setContactsId(d.getContactsId());
                transportUnitInfo.setContacts(d.getContacts());
                transportUnitInfo.setPhone(d.getPhone());
                return transportUnitInfo;
            }).collect(Collectors.toList());
            detail.setUnitInfoList(collect1);
        } else {
            //自动派单
            if (detail.getContractInfo() != null && DispatchWayEnums.AUTO_DISPATCH.getCode().equals(detail.getContractInfo().getDispatchWay())) {
                //查询销售企业
                KwoTradeOrderUnit tradeOrderUnit = units.stream().filter(unit -> String.valueOf(Global.NUMERICAL_TWO).equals(unit.getUnitType())).findFirst().orElse(null);
                Long goodsId = detail.getGoodsInfo().getGoodsId();
                //查询满足自动派单的物流合同
                List<LogisticsEntDtoVO> contractLogisticsList = remoteContractService.queryAutoContractLogOrder(tradeOrderUnit.getEntId(), Lists.newArrayList(goodsId));
                if (CollectionUtils.isEmpty(contractLogisticsList)) {
                    throw new BusinessException("未找到该商品有效的自动派车物流合同，请先签订自动派车物流合同");
                }
                List<ContractInfo> contractInfoList = contractLogisticsList.stream().map(d -> {
                    ContractInfo contractInfo = new ContractInfo();
                    contractInfo.setContractId(d.getContractId());
                    contractInfo.setContractNo(d.getContractNo());

                    contractInfo.setContractName(d.getContractName());
                    contractInfo.setContractSigningWay(d.getContractSigningWay());
                    contractInfo.setContractStatus(d.getContractStatus());
                    contractInfo.setDispatchWay(DispatchWayEnums.AUTO_DISPATCH.getCode());

                    return contractInfo;
                }).collect(Collectors.toList());
                detail.setContractInfoList(contractInfoList);
            }
        }


        //todo 关联物流订单信息
        return detail;
    }

    /**
     * @desc: 修改订单
     * @author: yzc
     * @date: 2023-07-07 15:34
     * @Param param:
     * @return: void
     */
    public void update(UpdateOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        String source = order.getSource();
        Integer status = order.getStatus();
        if ((!Objects.equals(status, OrderStatusEnum.SAVED.getCode()) && !Objects.equals(status, OrderStatusEnum.RETURNED.getCode())) && Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
            throw new BusinessException("采购下单只能修改已保存及已退回状态的订单！");
        }
        if (Objects.equals(source, OrderSourceEnum.SALE.getType()) && !Objects.equals(status, OrderStatusEnum.SAVED.getCode())) {
            throw new BusinessException("代客下单只能修改已保存状态的订单！");
        }
        if (!Objects.equals(0, order.getStatus()) && kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), source)) {
            throw new BusinessException("无权限修改此订单！");
        }
        OrderCheckDTO orderCheck = new OrderCheckDTO();
        if (Objects.equals(param.getOperateType(), 1)) {
            checkParams(param, source);
            if (Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
                order.setStatus(OrderStatusEnum.WAIT_ACCEPTED.getCode());
            } else {
                ContractInfo contract = param.getContractInfo();
                contractCheck(contract);
                param.setContractInfo(contract);
                String contractStatus = contract.getContractStatus();
                if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
                    order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
                } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
                    order.setStatus(OrderStatusEnum.EXECUTING.getCode());
                } else {
                    throw new BusinessException("Invalid contract status");
                }
            }
            orderCheck = BeanUtil.copyProperties(param, OrderCheckDTO.class);
            getTopEnt(orderCheck, param.getUnitInfo());
            orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice()).setOrderSource(source);
            orderCheck(orderCheck, false);
            //扣减库存
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
            //代客下单冻结金额
            if (Objects.equals(source, OrderSourceEnum.SALE.getType()) && param.getTrading().startsWith("1")) {
                HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(), ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
                if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                    throw new BusinessException(freezeResult.getMsg());
                }
            }
        }
        order.setAmount(param.getAmount()).setUnit(Objects.isNull(param.getGoodsInfo()) ? null : param.getGoodsInfo().getUnit()).setPrice(param.getPrice()).setTrading(param.getTrading()).setPickupType(param.getPickupType()).setDeliveryType(param.getDeliveryType()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setRemark(param.getRemark());
        LambdaUpdateWrapper<KwoTradeOrder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(KwoTradeOrder::getAmount, order.getAmount()).set(KwoTradeOrder::getUnit, order.getUnit()).set(KwoTradeOrder::getPrice, order.getPrice()).set(KwoTradeOrder::getTrading, order.getTrading()).set(KwoTradeOrder::getPickupType, order.getPickupType()).set(KwoTradeOrder::getDeliveryType, order.getDeliveryType()).set(KwoTradeOrder::getStartTime, order.getStartTime()).set(KwoTradeOrder::getEndTime, order.getEndTime()).set(KwoTradeOrder::getRemark, order.getRemark()).set(KwoTradeOrder::getStatus, order.getStatus()).eq(KwoTradeOrder::getId, order.getId());
        kwoTradeOrderMapper.update(null, wrapper);
        ValetOrderParam valetOrderParam = BeanUtil.copyProperties(param, ValetOrderParam.class);

        addOtherOrderInfo(order, valetOrderParam, true, false);
        //订单提交发送提醒消息
        if (Objects.equals(param.getOperateType(), 1)) {
            submitOrderSendMsg(orderCheck, order.getTOrderNo());
        }
    }


    private void checkParams(UpdateOrderParam param, String source) {
        if (Objects.isNull(param.getAmount()) || param.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单总量不能为空且必须大于零！");
        }
        if (Objects.isNull(param.getPrice()) || param.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单金额不能为空且必须大于零！");
        }
        if (StringUtils.isBlank(param.getTrading())) {
            throw new BusinessException("交易方式不能为空!");
        }
        if (StringUtils.isBlank(param.getPickupType())) {
            throw new BusinessException("提货方式不能为空!");
        }
        if (Objects.isNull(param.getStartTime())) {
            throw new BusinessException("开始时间不能为空！");
        }
        if (Objects.isNull(param.getEndTime())) {
            throw new BusinessException("结束时间不能为空！");
        }
        if (StringUtils.isBlank(param.getDeliveryType())) {
            throw new BusinessException("交付类型不能为空!");
        }
        ContractInfo contractInfo = param.getContractInfo();
        if (Objects.equals(source, OrderSourceEnum.SALE.getType())) {
            if (Objects.isNull(contractInfo)) {
                throw new BusinessException("代客下单合同信息不能为空");
            }
            if (Objects.isNull(contractInfo.getContractId())) {
                throw new BusinessException("合同id不能为空！");
            }
        }
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo)) {
            throw new BusinessException("商品信息不能为空！");
        }
        if (Objects.isNull(goodsInfo.getGoodsId())) {
            throw new BusinessException("商品id不能为空！");
        }
        if (StringUtils.isBlank(goodsInfo.getUnit())) {
            throw new BusinessException("商品单位不能为空！");
        }
        if (Objects.isNull(goodsInfo.getPriceRangeId()) && Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
            throw new BusinessException("价格段id不能为空！");
        }
        if (Objects.isNull(goodsInfo.getUnitPrice()) || goodsInfo.getUnitPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单成交单价不能为空且必须大于零！");
        }

        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("单位信息不能为空！");
        }
        unitInfos.forEach(e -> {
            if (Objects.isNull(e.getUnitType())) {
                throw new BusinessException("单位类型不能为空！");
            }
            if (Objects.isNull(e.getEntId())) {
                throw new BusinessException("企业id不能为空！");
            }
            if (StringUtils.isBlank(e.getFirmName())) {
                throw new BusinessException("企业名称不能为空！");
            }
            if (Objects.isNull(e.getContactsId())) {
                throw new BusinessException("联系人id不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
        });
        List<AddressInfoDto> addressInfoDtos = param.getAddressInfoDto();
        if (CollectionUtils.isEmpty(addressInfoDtos)) {
            throw new BusinessException("地址信息不能为空！");
        }
        addressInfoDtos.forEach(e -> {
            if (StringUtils.isBlank(e.getAddressType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getName())) {
                throw new BusinessException("地址名称不能为空！");
            }
            if (StringUtils.isBlank(e.getType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
            if (Objects.isNull(e.getCityCode())) {
                throw new BusinessException("所在地区code不能为空！");
            }
            if (StringUtils.isBlank(e.getCityName())) {
                throw new BusinessException("所属区域名称不能为空！");
            }
            if (StringUtils.isBlank(e.getDetailAddress())) {
                throw new BusinessException("详细地址不能为空！");
            }
            if (StringUtils.isBlank(e.getLat())) {
                throw new BusinessException("纬度不能为空！");
            }
            if (StringUtils.isBlank(e.getLng())) {
                throw new BusinessException("经度不能为空！");
            }
        });

    }

    /**
     * @desc: 订单受理
     * @author: yzc
     * @date: 2023-07-14 16:59
     * @Param param:
     * @return: void
     */
    public void acceptanceOrder(AcceptanceOrderParam param) {
        BigDecimal amount = param.getAmount();
        List<UpdateAddressAmountParam> addressAmountParams = param.getAddressAmountParams();
        BigDecimal totalLoadAmount = addressAmountParams.stream().map(UpdateAddressAmountParam::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (amount.compareTo(totalLoadAmount) != 0) {
            throw new BusinessException("分配卸货量总量与订单总量不相符！");
        }
        List<AddressInfoDto> loadAddressInfoDto = param.getAddressInfoDto();
        long unloadCount = loadAddressInfoDto.stream().filter(e -> Objects.equals(OrderAddressTypeEnum.UNLOAD.getType(), e.getAddressType())).count();
        if (unloadCount > 0) {
            throw new BusinessException("装货地址类型信息有误！");
        }
        BigDecimal totalUnLoadAmount = loadAddressInfoDto.stream().map(AddressInfoDto::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (amount.compareTo(totalUnLoadAmount) != 0) {
            throw new BusinessException("分配装货量总量与订单总量不相符！");
        }
        if (param.getPrice().compareTo(param.getUnitPrice().multiply(param.getAmount())) != 0) {
            throw new BusinessException("订单总金额不等于商品单价*订单总量！");
        }
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(OrderStatusEnum.WAIT_ACCEPTED.getCode(), order.getStatus())) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        if (Objects.isNull(goods)) {
            throw new BusinessException("订单商品信息异常！");
        }
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(order.getId());
        Long saleUnitId = param.getSaleUnitParam().getId();
        KwoTradeOrderUnit saleUnit = units.stream().filter(e -> Objects.equals(e.getId(), saleUnitId) && Objects.equals(e.getUnitType(), OrderUnitTypeEnum.SALE.getType())).findFirst().orElse(null);
        if (Objects.isNull(saleUnit)) {
            throw new BusinessException("我方单位信息异常！");
        }
        Long contactsId = param.getSaleUnitParam().getContactsId();
        boolean updateUnit = !Objects.equals(contactsId, saleUnit.getContactsId());
        if (updateUnit) {
            UserCacheResDto contactsInfo = remoteSystemService.queryUserCacheById(contactsId);
            if (Objects.isNull(contactsInfo)) {
                throw new BusinessException("未查询到我方联系人信息");
            }
            saleUnit.setContactsId(contactsId).setContacts(contactsInfo.getName()).setPhone(contactsInfo.getPhone());
        }
        List<UnitInfo> unitInfos = BeanUtil.copyToList(units, UnitInfo.class);
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("订单企业信息异常！");
        }
        //受理订单总量-原订单总量=订单变化量
        BigDecimal changeAmount = amount.subtract(order.getAmount());
        OrderCheckDTO orderCheck = BeanUtil.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, unitInfos);
        orderCheck.setGoodsId(goods.getGoodsId()).setAmount(changeAmount);
        orderCheck(orderCheck, true);
        //冻结金额
        if (param.getTrading().startsWith("1")) {
            HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(), ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                throw new BusinessException(freezeResult.getMsg());
            }
        }
        //更新订单信息
        BeanUtil.copyProperties(param, order);
        ContractInfo contractInfo = param.getContractInfo();
        contractCheck(contractInfo);
        String contractStatus = contractInfo.getContractStatus();
        if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
        } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.EXECUTING.getCode());
        } else {
            throw new BusinessException("Invalid contract status");
        }
        order.setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()));
        kwoTradeOrderMapper.updateById(order);
        //更新商品价格
        kwoTradeOrderGoodsService.updateUnitPrice(param.getId(), param.getUnitPrice());
        //更新单位信息
        if (updateUnit) {
            kwoTradeOrderUnitService.updateById(saleUnit);
        }
        //更新装货地址信息
        List<Long> oldLoadAddressIds = kwoTradeOrderAddressService.getByOrderIdAndType(param.getId(), OrderAddressTypeEnum.LOAD.getType()).stream().map(KwoTradeOrderAddress::getId).toList();
        if (CollUtil.isNotEmpty(oldLoadAddressIds)) {
            kwoTradeOrderAddressService.delByIds(oldLoadAddressIds);
            tradeOrderAmountService.delByOrderIdAndAddressIds(param.getId(), oldLoadAddressIds);
        }
        AtomicInteger loadSort = new AtomicInteger(0);
        loadAddressInfoDto.forEach(e -> {
            KwoTradeOrderAddress address = BeanUtil.copyProperties(e, KwoTradeOrderAddress.class);
            address.setTOrderId(param.getId()).setTOrderNo(order.getTOrderNo()).setSort(loadSort.getAndIncrement());
            //地址信息
            Long addressId = kwoTradeOrderAddressService.add(address);
            //分配量信息
            KwoTradeOrderAmount orderAmount = new KwoTradeOrderAmount();
            orderAmount.setTOrderId(param.getId()).setAmount(e.getAmount()).setTAddressId(addressId);
            tradeOrderAmountService.add(orderAmount);
        });
        //更新卸货地址分配量信息
        addressAmountParams.forEach(tradeOrderAmountService::update);
        //保存合同信息
        KwoTradeOrderContract tradeOrderContract = BeanUtil.copyProperties(contractInfo, KwoTradeOrderContract.class);
        tradeOrderContract.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo());
        kwoTradeOrderContractService.insert(tradeOrderContract);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //更新库存
        if (amount.compareTo(BigDecimal.ZERO) != 0) {
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
        }
        //更新mongodb
        SckwTradeOrder updateParam = BeanUtil.copyProperties(param, SckwTradeOrder.class);
        updateParam.setTOrderId(param.getId()).setStatus(order.getStatus()).setStartTime(DateUtils.localDateToDateStart(param.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(param.getEndTime())).setPrice(order.getPrice().doubleValue()).setAmount(order.getAmount().doubleValue()).setUnitPrice(param.getUnitPrice().doubleValue()).setContractId(contractInfo.getContractId()).setContractNo(contractInfo.getContractNo()).setContractName(contractInfo.getContractName()).setContractSigningWay(contractInfo.getContractSigningWay()).setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
        saveMongoDb(3, updateParam);

    }

    /**
     * @desc: 订单驳回
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param param:
     * @return: void
     */
    public void rejectOrder(RejectOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(OrderStatusEnum.WAIT_ACCEPTED.getCode(), order.getStatus())) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        order.setStatus(OrderStatusEnum.RETURNED.getCode());
        kwoTradeOrderMapper.updateById(order);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //释放商品库存
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), order.getAmount().negate());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //mongodb更新订单状态
        SckwTradeOrder updateParam = new SckwTradeOrder();
        updateParam.setTOrderId(order.getId()).setStatus(order.getStatus()).setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
        saveMongoDb(3, updateParam);
        //发送提醒消息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(order.getId());
        rejectOrderSendMsg(units, order);
    }

    /**
     * @desc: 驳回订单发送消息
     * @author: yzc
     * @date: 2023-09-04 16:44
     * @Param units:
     * @Param order:
     * @return: void
     */
    private void rejectOrderSendMsg(List<KwoTradeOrderUnit> units, KwoTradeOrder order) {
        Map<String, Object> map = CollectionUtils.createHashMap();
        map.put("orderNo", order.getTOrderNo());
        Map<String, KwoTradeOrderUnit> unitMap = units.stream().collect(Collectors.toMap(KwoTradeOrderUnit::getUnitType, Function.identity()));
        KwoTradeOrderUnit purchase = unitMap.get(OrderUnitTypeEnum.PURCHASE.getType());
        KwoTradeOrderUnit supply = unitMap.get(OrderUnitTypeEnum.SALE.getType());
        //给供应企业联系人发消息
        map.put("firmName", purchase.getFirmName());
        UserInfo supplyUser = new UserInfo();
        supplyUser.setUserId(supply.getContactsId()).setEntId(supply.getTopEntId());
        sendMsg(MessageEnum.ORDER_REJECT_VALET, map, pcValetListUrl, appValetListUrl, List.of(supplyUser));
        //给订单创建人及采购企业联系人发消息
        map.put("firmName", supply.getFirmName());
        List<UserInfo> userInfos = new ArrayList<>();
        UserInfo createUser = new UserInfo();
        createUser.setUserId(order.getCreateBy()).setEntId(order.getEntId());
        userInfos.add(createUser);
        if (!Objects.equals(createUser.getUserId(), purchase.getContactsId())) {
            UserInfo purchaseUser = new UserInfo();
            purchaseUser.setUserId(purchase.getContactsId()).setEntId(purchase.getTopEntId());
            userInfos.add(purchaseUser);
        }
        sendMsg(MessageEnum.ORDER_REJECT_PURCHASE, map, pcPurchaseListUrl, appPurchaseListUrl, userInfos);
    }

    /**
     * @desc: 订单驳回查询
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param id:
     * @return: java.lang.String
     */
    public String rejectReason(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), null)) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderTrack track = kwoTradeOrderTrackService.getByOrderId(id, OrderStatusEnum.RETURNED.getCode());

        return Objects.isNull(track) ? null : track.getRemark();
    }

    /**
     * @desc: 完结订单
     * @author: yzc
     * @date: 2023-07-14 17:01
     * @Param param:
     * @return: void
     */
    public void completeOrder(CompleteOrderParam param) {
        BigDecimal actualAmount = param.getActualAmount();
        Long tOrderId = param.getId();
        KwoTradeOrder order = getById(tOrderId);
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(order.getStatus(), OrderStatusEnum.EXECUTING.getCode())) {
            throw new BusinessException("执行中的订单才能完结订单！");
        }
        if (kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        if (transportRemoteService.checkLogisticsOrderByTradeOrderId(tOrderId)) {
            throw new CustomPromptException(HttpStatus.COMPLETE_TORDER_FAIL_CODE, "订单存在未完成的物流托运，不可完结！");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, tOrderId);
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            throw new BusinessException("业务繁忙，请稍后再试!");
        }
        try {
            order.setActualAmount(actualAmount).setStatus(OrderStatusEnum.FINISHED.getCode());
            kwoTradeOrderMapper.updateById(order);
            //订单状态记录
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(tOrderId).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
            kwoTradeOrderTrackService.insert(track);
            if (actualAmount.compareTo(order.getAmount()) != 0) {
                KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(tOrderId);
                if (Objects.isNull(goods)) {
                    throw new BusinessException("商品信息异常！");
                }
                //更新库存
                BigDecimal amount = param.getActualAmount().subtract(order.getAmount());
                HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
                if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                    throw new BusinessException(updateResult.getMsg());
                }
            }
            //更新合同履约量
            KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(tOrderId);
            if (Objects.isNull(contract) || Objects.isNull(contract.getContractId())) {
                throw new BusinessException("订单合同信息异常");
            }
            remoteContractService.updatePerformed(contract.getContractId(), actualAmount);
            //mongodb更新订单状态
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId()).setActualAmount(order.getActualAmount().doubleValue()).setStatus(order.getStatus()).setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }

    }


    /**
     * @desc: 批量删除
     * @author: yzc
     * @date: 2023-07-17 20:35
     * @Param param:
     * @return: void
     */
    public void batchDelete(BatchDeleteParam param) {
        List<Long> ids = StringUtils.splitStrToList(param.getIds(), ",", Long.class);
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(KwoTradeOrder::getId, ids).ne(KwoTradeOrder::getStatus, 0).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        if (CollUtil.isNotEmpty(list)) {
            throw new BusinessException("删除操作仅针对“已保存”状态的订单");
        }
        //排除草稿状态权限匹配
        List<Long> filterIds = list.stream().filter(e -> !(Objects.equals(e.getStatus(), 0))).map(KwoTradeOrder::getId).toList();
        if (CollUtil.isNotEmpty(filterIds) && kwoTradeOrderUnitService.entBatchMatch(filterIds, LoginUserHolder.getEntId(), String.valueOf(param.getOrderType()))) {
            throw new BusinessException("无订单操作权限！");
        }
        LambdaUpdateWrapper<KwoTradeOrder> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(KwoTradeOrder::getDelFlag, Global.YES).in(KwoTradeOrder::getId, ids);
        kwoTradeOrderMapper.update(null, updateWrapper);
        kwoTradeOrderGoodsService.delByOrderIds(ids);
        kwoTradeOrderUnitService.delByOrderIds(ids);
        kwoTradeOrderAddressService.delByOrderIds(ids);
        tradeOrderAmountService.delByOrderIds(ids);
        kwoTradeOrderContractService.delByOrderIds(ids);
        //更新mongodb
        ids.forEach(id -> {
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(id).setDelFlag(Global.YES).setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        });

    }

    /**
     * @desc: 根据id获取订单
     * @author: yzc
     * @date: 2023-07-13 17:14
     * @Param id:
     * @return: com.sckw.order.model.KwoTradeOrder
     */
    public KwoTradeOrder getById(Long id) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getId, id).eq(KwoTradeOrder::getDelFlag, Global.NO).last("LIMIT 1");
        return kwoTradeOrderMapper.selectOne(wrapper);
    }

    /**
     * @desc: 根据id更新
     * @author: yzc
     * @date: 2023-07-20 10:24
     * @Param order:
     * @return: void
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateById(KwoTradeOrder order) {
        kwoTradeOrderMapper.updateById(order);
    }


    /**
     * @desc: 根据订单ids获取待签约订单
     * @author: yzc
     * @date: 2023-07-20 14:10
     * @Param tOrderIds:
     * @return: java.util.List<com.sckw.order.model.KwoTradeOrder>
     */
    public List<KwoTradeOrder> getWaitSignByIds(List<Long> tOrderIds) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getStatus, OrderStatusEnum.WAIT_SIGNED.getCode()).in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        return CollUtil.emptyIfNull(list);
    }

    /**
     * @desc: 根据订单ids变更待签约订单为执行中
     * @author: yzc
     * @date: 2023-07-20 11:57
     * @Param tOrderIds:
     * @Param updateBy:
     * @return: void
     */
    public void contractCompletedUpdate(List<Long> tOrderIds, Long updateBy) {
        LambdaUpdateWrapper<KwoTradeOrder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getStatus, OrderStatusEnum.WAIT_SIGNED.getCode()).eq(KwoTradeOrder::getDelFlag, Global.NO).set(KwoTradeOrder::getUpdateBy, updateBy).set(KwoTradeOrder::getStatus, OrderStatusEnum.EXECUTING.getCode());
        kwoTradeOrderMapper.update(null, wrapper);
    }

    /**
     * @desc: 获取贸易订单地址下拉列表
     * @author: yzc
     * @date: 2023-08-02 17:28
     * @return: com.sckw.order.model.vo.res.AddressDropListRes
     */
    public AddressDropListRes getAddressDropList() {
        AddressDropListRes res = new AddressDropListRes();
        Long entId = LoginUserHolder.getEntId();
        //一级企业匹配筛选订单id
        List<KwoTradeOrderUnit> unitInfo = kwoTradeOrderUnitService.getByTopEntId(entId);
        if (CollectionUtils.isEmpty(unitInfo)) {
            return res;
        }
        Set<Long> tOrderIds = unitInfo.stream().map(KwoTradeOrderUnit::getTOrderId).collect(Collectors.toSet());
        //订单ids获取地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderIds(tOrderIds);
        if (CollectionUtils.isEmpty(addressList)) {
            return res;
        }
        //装卸货地址类型分组获取装卸货cityCodes
        Map<String, List<Integer>> map = addressList.stream().collect(Collectors.groupingBy(KwoTradeOrderAddress::getAddressType, Collectors.mapping(KwoTradeOrderAddress::getCityCode, Collectors.toList())));
        //装货地址下拉列表树
        List<AreaTreeFrontResDto> loadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(OrderAddressTypeEnum.LOAD.getType()));
        //卸货地址下拉列表树
        List<AreaTreeFrontResDto> unloadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(OrderAddressTypeEnum.UNLOAD.getType()));
        res.setLoadAddressList(loadTree).setUnloadAddressList(unloadTree);
        return res;
    }

    /**
     * @desc: 根据ids获取进行中的订单
     * @author: yzc
     * @date: 2023-08-17 17:34
     * @Param tOrderIds:
     * @return: java.util.Collection<com.sckw.order.model.KwoTradeOrder>
     */
    public List<KwoTradeOrder> associateEnt(Collection<Long> tOrderIds) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getDelFlag, Global.NO).in(KwoTradeOrder::getStatus, 1, 2, 3, 4);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        return CollUtil.emptyIfNull(list);
    }

    /**
     * @desc: 根据一级企业id查询，企业类型分组，统计非草稿的订单数量
     * @author: yzc
     * @date: 2023-09-11 11:46
     * @Param topEntId:
     * @return: java.util.List<com.sckw.order.api.model.TradeOrderCountStatisticsDTO>
     */
    public List<TradeOrderCountStatisticsDTO> getOrderNumByTopEntId(Long topEntId, List<Long> enterpriseIds) {
        return kwoTradeOrderMapper.getOrderNumByTopEntId(topEntId, enterpriseIds);
    }

    /**
     * @desc: 工作台贸易订单表格统计
     * @author: yzc
     * @date: 2023-09-13 15:46
     * @Param reqDTO:
     * @return: java.util.List<com.sckw.order.model.dto.WbTOrderExcelStsResDTO>
     */
    public List<WbTOrderExcelStsResDTO> workbenchExcel(WbTOrderExcelStsReqDTO reqDTO) {
        List<WbTOrderExcelStsResDTO> list = kwoTradeOrderMapper.workbenchExcel(reqDTO);
        return CollUtil.emptyIfNull(list);
    }

    /**
     * @param tOrderId 贸易主键ID
     * @desc 查询贸易订单商品关联单位
     * @author zk
     * @date 2023/12/4
     **/
    public List<GoodsUnitRes> goodsUnit(Long tOrderId) {
        List<GoodsUnitRes> unitDetails = new ArrayList<>();
        KwoTradeOrder tradeOrder = kwoTradeOrderMapper.selectById(tOrderId);
        if (tradeOrder != null) {
            unitDetails.add(new GoodsUnitRes(tradeOrder.getUnit(), null, true));
        }

        //商品辅助单位
        List<GoodsUnitDetailRes> assistUnit = kwoTradeOrderGoodsUnitService.findGoodsUnitDetail(tOrderId);
        if (CollUtil.isNotEmpty(assistUnit)) {
            assistUnit.forEach(e -> {
                unitDetails.add(new GoodsUnitRes(e.getToUnit(), null, false));
            });
        }

        //数据组装
        if (CollUtil.isNotEmpty(unitDetails)) {
            //货物单位与合理损耗单位
            List<SysDictResDto> dicts = remoteSystemService.queryDictByType(DictTypeEnum.UNIT_LOSS_TYPE.getType());
            //单位
            Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
            Map<String, String> unitMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            if (CollUtil.isNotEmpty(dict)) {
                unitMap = dict.get(DictTypeEnum.UNIT_TYPE.getType());
            }
            Map<String, String> finalUnitMap = unitMap;
            unitDetails.forEach(e -> {
                e.setLabel(finalUnitMap != null ? finalUnitMap.get(e.getValue()) : null);
                //组装合理损耗
                if (CollUtil.isNotEmpty(dicts)) {
                    for (SysDictResDto ee : dicts) {
                        if (ee.getParentId().equals((long) NumberConstant.ZERO)) {
                            if (ee.getValue().equals(e.getValue())) {
                                List<Map<String, Object>> lossUnit = new ArrayList();
                                for (SysDictResDto eee : dicts) {
                                    if (eee.getParentId().equals(ee.getId())) {
                                        lossUnit.add(new HashMap<>(NumberConstant.SIXTEEN) {{
                                            put("value", eee.getValue());
                                            put("label", eee.getLabel());
                                        }});
                                    }
                                }
                                e.setLossUnit(lossUnit);
                            }
                        }
                    }
                }
            });
        }

        return unitDetails;
    }

    /**
     * @param id
     * @return com.sckw.order.model.vo.res.OrderAddressInfoRes
     * @desc 根据id获取地址信息
     * @author yzc
     * @date 2024/3/5 15:50
     */
    public OrderAddressInfoRes getAddressInfo(Long id) {
        OrderAddressInfoRes res = new OrderAddressInfoRes();
        List<String> loadNameList = new ArrayList<>();
        List<String> loadDetailAddressList = new ArrayList<>();
        List<String> unloadNameList = new ArrayList<>();
        List<String> unloadDetailAddressList = new ArrayList<>();
        List<KwoTradeOrderAddress> list = kwoTradeOrderAddressService.getByOrderId(id);
        list.forEach(e -> {
            if (OrderAddressTypeEnum.LOAD.getType().equals(e.getAddressType())) {
                loadNameList.add(e.getName());
                loadDetailAddressList.add(e.getCityName() + e.getDetailAddress());
            } else {
                unloadNameList.add(e.getName());
                unloadDetailAddressList.add(e.getCityName() + e.getDetailAddress());
            }
        });
        res.setLoadNameList(loadNameList).setLoadDetailAddressList(loadDetailAddressList).setUnloadNameList(unloadNameList).setUnloadDetailAddressList(unloadDetailAddressList);
        return res;
    }

    /**
     * @param params
     * @return com.sckw.core.model.page.PageResult
     * @desc 贸易订单列表分页查询
     * @author yzc
     * @date 2024/3/15 8:51
     */
    public PageResult tradeOrderSelect(TradeOrderListSelectParam params) {
        TradeOrderListSelectDTO dto = buildSelectParam(params);
        //数据权限过滤
        applyTradeOrderDataPermission(dto);
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<OrderListResDTO> list = kwoTradeOrderMapper.tradeOrderSelect(dto, dto.getGoodIds(), LoginUserHolder.getAuthUserIdList(), null);
        return buildResult(list, params.getPageSize());

    }

    /**
     * 应用贸易订单数据权限过滤
     * 根据当前用户的数据权限配置，设置DTO中的权限过滤参数
     *
     * @param dto 贸易订单列表查询DTO
     */
    private void applyTradeOrderDataPermission(TradeOrderListSelectDTO dto) {
        DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
        // 如果获取权限失败或不需要过滤，则直接返回
        if (perm == null || !perm.needFilter()) {
            return;
        }
        // 设置基础权限过滤标识
        dto.setDataPermissionFilter(Boolean.TRUE);
        dto.setDataPermissionAllVisible(perm.isAllVisible());
        dto.setDataPermissionPersonal(perm.isPersonalDataEnabled());
        dto.setDataPermissionUserId(perm.getUserId());
        // 设置可见企业ID列表，若为空则设为空列表
        dto.setDataPermissionEntIds(CollectionUtils.isEmpty(perm.getVisibleEntIds()) ? Collections.emptyList() : new ArrayList<>(perm.getVisibleEntIds()));

        // 如果不是全部可见且没有指定可见企业ID，则强制结果为空
        if (!perm.isAllVisible() && CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
            dto.setDataPermissionFilter(Boolean.FALSE);
            dto.setDataPermissionForceEmpty(Boolean.TRUE);
            return;
        }
        // 如果开启了个人数据权限但未获取到用户ID，则强制结果为空
        if (perm.isPersonalDataEnabled() && perm.getUserId() == null) {
            dto.setDataPermissionFilter(Boolean.FALSE);
            dto.setDataPermissionForceEmpty(Boolean.TRUE);
        }
    }

    /**
     * 获取当前用户的数据权限信息
     * 通过Feign调用远程服务获取数据权限过滤条件
     *
     * @return 数据权限DTO，获取失败时返回null
     */
    private DataPermissionDTO fetchDataPermissionForCurrentUser() {
        try {
            DataPermissionFilterReqDto reqDto = new DataPermissionFilterReqDto();
            // 设置当前登录用户的ID、角色ID和管理员标识
            reqDto.setUserId(LoginUserHolder.getUserId());
            reqDto.setRoleId(LoginUserHolder.getCurrentRoleId());
            reqDto.setManager(LoginUserHolder.isManager());
            return dataPermissionFeignService.getDataPermissionFilter(reqDto);
        } catch (Exception e) {
            // 记录警告日志，权限获取失败时跳过过滤，避免影响主业务流程
            log.warn("获取贸易订单数据权限失败，跳过本接口数据权限过滤: {}", e.getMessage());
            return null;
        }
    }

    /**
     * @param list
     * @param pageSize
     * @return com.sckw.core.model.page.PageRes
     * @desc 构建列表结果响应
     * @author yzc
     * @date 2024/3/15 14:23
     */
    public PageResult buildResult(List<OrderListResDTO> list, int pageSize) {
        if (CollUtil.isEmpty(list)) {
            return PageHelperUtil.getPageResult(new PageInfo<>());
        }
        List<OrderListResVO> result = new ArrayList<>();
        List<Long> goodIdList = new ArrayList<>();
        List<Long> contracIdList = new ArrayList<>();
        List<Long> createByIds = new ArrayList<>();
        list.forEach(e -> {
            goodIdList.add(e.getGoodsId());
            contracIdList.add(e.getContractId());
            createByIds.add(e.getCreateBy());
        });
        Map<Long, UserCacheResDto> userMap = remoteSystemService.queryUserCacheMapByIds(createByIds);
        Map<Long, KwpGoods> goodsMap = goodsInfoService.getGoodsByIds(goodIdList);
        Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(contracIdList);
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.TORDER_STATUS.getType(), DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.TRADE_TYPE.getType(), DictTypeEnum.SETTLEMENT_WAY.getType(), DictTypeEnum.CONSIGNMENT_WAY.getType(), DictTypeEnum.TORDER_SOURCE.getType(), DictTypeEnum.GOODS_SPEC.getType()));
        Map<String, SysDictResDto> unitType = remoteSystemService.queryDictMapByType(DictTypeEnum.UNIT_TYPE.getType());
        Map<String, String> tradeMap, deliveryMap, pickupMap, sourceMap, nameMap, specMap;
        if (CollUtil.isNotEmpty(dict)) {
            tradeMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TRADE_TYPE.getType())) ? dict.get(DictTypeEnum.TRADE_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            deliveryMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.SETTLEMENT_WAY.getType())) ? dict.get(DictTypeEnum.SETTLEMENT_WAY.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            pickupMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.CONSIGNMENT_WAY.getType())) ? dict.get(DictTypeEnum.CONSIGNMENT_WAY.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            sourceMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_SOURCE.getType())) ? dict.get(DictTypeEnum.TORDER_SOURCE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            nameMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType())) ? dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            specMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.GOODS_SPEC.getType())) ? dict.get(DictTypeEnum.GOODS_SPEC.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);

        } else {
            tradeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            deliveryMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            pickupMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            sourceMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            nameMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            specMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        }
        list.forEach(e -> {
            //装货地址
            List<KwoTradeOrderAddress> loadAddresses = kwoTradeOrderAddressService.findByAddress(e.getTOrderId(), AddressTypeEnum.SHIPMENT.getCode());
            //卸货地址
            List<KwoTradeOrderAddress> unloadAddresses = kwoTradeOrderAddressService.findByAddress(e.getTOrderId(), AddressTypeEnum.TAKE.getCode());
            Optional<KwoTradeOrderAddress> loadAddress = loadAddresses.stream().findFirst();
            //卸货地点点名称
            Optional<KwoTradeOrderAddress> unloadAddress = unloadAddresses.stream().findFirst();

            BigDecimal actualAmount = Objects.isNull(e.getActualAmount()) ? BigDecimal.ZERO : e.getActualAmount();
            BigDecimal unitPrice = Objects.isNull(e.getUnitPrice()) ? BigDecimal.ZERO : e.getUnitPrice();
            KwpGoods goods = goodsMap.get(e.getGoodsId());
            ContractCommonInfoResDto contract = contractMap.get(e.getContractId());
            UserCacheResDto userCache = userMap.get(e.getCreateBy());

            OrderListResVO vo = BeanUtil.copyProperties(e, OrderListResVO.class);
            vo.setStatusLabel(TradeOrderStatusEnum.getMsg(e.getStatus())).setTradingLabel(tradeMap.get(e.getTrading())).setTrading(tradeMap.get(e.getTrading())).setDeliveryType(deliveryMap.get(e.getDeliveryType())).setPickupTypeLabel(pickupMap.get(e.getPickupType())).setSourceLabel(sourceMap.get(e.getSource())).setSource(sourceMap.get(e.getSource())).setContractName(Objects.isNull(contract) ? null : contract.getContactName()).setContractSigningWay(Objects.isNull(contract) ? null : contract.getSigningWayName()).setGoodsName(Objects.isNull(goods) ? null : goods.getName());
            vo.setGoodsSpec(Objects.isNull(goods) ? "" : CollUtil.isNotEmpty(specMap) ? specMap.get(goods.getSpec()) : null);
            vo.setGoodsTaxRate(Objects.isNull(goods) ? null : goods.getTaxRate());
            vo.setGoodsThumb(Objects.isNull(goods) ? null : goods.getThumb());
            vo.setGoodsType(Objects.isNull(goods) ? null : goods.getGoodsType());
            vo.setGoodsTypeLabel(nameMap.get(Objects.isNull(goods) ? null : goods.getGoodsType()));
            vo.setWaitEntrustAmount(setScale(getWaitEntrustAmount(e.getAmount(), e.getEntrustAmount())));
            vo.setActualPrice(actualAmount.multiply(unitPrice).setScale(2, RoundingMode.HALF_UP)).setUnitPrice(setScale(e.getUnitPrice())).setPrice(setScale(e.getPrice())).setUnit(e.getUnit()).setUnitLabel(unitType == null ? e.getUnit() : (unitType.get(e.getUnit()) == null ? e.getUnit() : unitType.get(e.getUnit()).getLabel())).setAmount(setScale(vo.getAmount())).setEntrustAmount(setScale(e.getEntrustAmount())).setActualAmount(setScale(e.getActualAmount())).setCreateByName(Objects.isNull(userCache) ? null : userCache.getName());
            vo.setDeliveryTypeLabel(DictEnum.getLabel(DictTypeEnum.LOAD_UNLOAD_WAY.getType(), String.valueOf(e.getChargeType())));
            vo.setAddVehicles(e.getAddVehicles());
            if (Objects.equals(e.getChargeType(), 1)) { //按装货量
                vo.setDealAmount(e.getLoadAmount());
            } else {
                vo.setDealAmount(e.getUnloadAmount());
            }

            loadAddress.ifPresent(d -> {
                vo.setLoadName(d.getName());
                vo.setLoadAddress(d.getCityName() + " " + d.getDetailAddress());

            });
            unloadAddress.ifPresent(d -> {
                vo.setUnloadName(d.getName());
                vo.setUnloadAddress(d.getCityName() + " " + d.getDetailAddress());
                vo.setUnloadContact(d.getContacts());
                vo.setUnloadContactPhone(d.getPhone());
            });
            result.add(vo);
        });
        return PageHelperUtil.getPageResult(new PageInfo<>(result), list, pageSize);
    }

    /**
     * @param params
     * @return com.sckw.order.model.dto.TradeOrderListSelectDTO
     * @desc 构建贸易订单列表请求参数
     * @author yzc
     * @date 2024/3/15 8:52
     */
    public TradeOrderListSelectDTO buildSelectParam(TradeOrderListStatisticParam params) {
        TradeOrderListSelectDTO dto = BeanUtil.copyProperties(params, TradeOrderListSelectDTO.class);
        EntTypeResDto entTypeResDto = remoteSystemService.queryEntTypeById(LoginUserHolder.getEntId());
        dto.setEntId(LoginUserHolder.getEntId()).setManager(LoginUserHolder.isManager()).setEntType(Objects.nonNull(entTypeResDto) ? entTypeResDto.getType() : null).setEntList(LoginUserHolder.getChildEntList()).setIsMain(LoginUserHolder.getIsMain());
        //装卸货地址
        String loadCode = params.getShippingAddressCode();
        if (StringUtils.isNotBlank(loadCode) && Objects.nonNull(params.getShippingAddressLevel())) {
            switch (params.getShippingAddressLevel()) {
                case 1 -> dto.setLoadAddressCode(loadCode.substring(0, 2).trim());
                case 2 -> dto.setLoadAddressCode(loadCode.substring(0, 4).trim());
                case 3 -> dto.setLoadAddressCode(loadCode);
            }
        }
        String unloadCode = params.getUnloadingAddressCode();
        if (StringUtils.isNotBlank(unloadCode) && Objects.nonNull(params.getUnloadingAddressLevel())) {
            switch (params.getUnloadingAddressLevel()) {
                case 1 -> dto.setUnloadAddressCode(unloadCode.substring(0, 2).trim());
                case 2 -> dto.setUnloadAddressCode(unloadCode.substring(0, 4).trim());
                case 3 -> dto.setUnloadAddressCode(unloadCode);
            }
        }
        String keywords = params.getKeywords();
        if (StringUtils.isNotBlank(keywords)) {
            List<SysDictResDto> sysDictResDtos = remoteSystemService.queryGoodsDict(keywords);
            List<String> collect = new ArrayList<>();
            if (CollUtil.isNotEmpty(sysDictResDtos)) {
                collect = sysDictResDtos.stream().map(SysDictResDto::getValue).distinct().collect(Collectors.toList());
            }
            dto.setGoodIds(goodsInfoService.getGoodsByPara(keywords, collect, keywords));
        }
        return dto;
    }

    /**
     * @desc: 设置两位小数
     * @author: yzc
     * @date: 2023-09-26 10:11
     * @Param d:
     * @return: java.lang.BigDecimal
     */
    private BigDecimal setScale(BigDecimal d) {
        if (Objects.isNull(d) || BigDecimal.ZERO.compareTo(d) == 0) {
            return NumberConstant.ZERO_TWO;
        }
        return d.setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * @desc: 获取订单待分配运输量
     * @author: yzc
     * @date: 2023-08-25 10:32
     * @Param amount:
     * @Param entrustAmount:
     * @return: java.math.Double
     */
    private BigDecimal getWaitEntrustAmount(BigDecimal amount, BigDecimal entrustAmount) {
        if (Objects.isNull(amount) || Objects.isNull(entrustAmount)) {
            return amount;
        }
        return amount.subtract(entrustAmount);
    }

    /**
     * @param params
     * @return com.sckw.core.model.vo.TableStatisticRes
     * @desc 贸易订单列表统计
     * @author yzc
     * @date 2024/3/15 8:52
     */
    public TableStatisticRes tradeOrderStatistic(TradeOrderListSelectParam params) {
        TableStatisticRes res = new TableStatisticRes();
        TradeOrderListSelectDTO dto = buildSelectParam(params);
        dto.setStatus(null);
        //数据权限过滤
        applyTradeOrderDataPermission(dto);
        List<TableTop> tableTops = kwoTradeOrderMapper.tradeOrderStatistic(dto, dto.getGoodIds(), LoginUserHolder.getAuthUserIdList());
        Map<Integer, Integer> map = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        if (CollUtil.isNotEmpty(tableTops)) {
            map = tableTops.stream().collect(Collectors.toMap(TableTop::getValue, TableTop::getTotal, (k1, k2) -> k2));
        }
        List<TableTop> list = new ArrayList<>();
        int count = 0;
        for (TradeOrderStatusEnum e : TradeOrderStatusEnum.getSortList()) {
            Integer value = e.getCode();
            int total = Objects.isNull(map.get(value)) ? 0 : map.get(value);
            TableTop tableTop = new TableTop();
            tableTop.setName(e.getMsg()).setValue(value).setTotal(total);
            list.add(tableTop);
            count = count + total;
        }
        TableTop all = new TableTop();
        all.setName("全部").setTotal(count);
        list.add(0, all);
        TableBottom tableBottom = new TableBottom();
        tableBottom.setTotal(count);
        res.setTableTops(list).setTableBottom(tableBottom);
        return res;
    }

    /**
     * @desc: app主界面贸易订单统计
     * @author: yzc
     * @date: 2023-08-21 17:39
     * @Param params:
     * @return: java.util.List<com.sckw.order.model.vo.res.TradeOrderAppStatisticVO>
     */
    public List<TradeOrderAppStatisticVO> appStatistic(TradeOrderAppStatisticParam params) {
        TradeOrderAppStatisticParamDTO dto = new TradeOrderAppStatisticParamDTO();
        dto.setOrderType(params.getOrderType()).setIsMain(LoginUserHolder.getIsMain()).setEntId(LoginUserHolder.getEntId());
        List<Integer> statuses = Arrays.asList(1, 4, 5, 7);
        List<Long> authUserIds = LoginUserHolder.getAuthUserIdList();
        List<TradeOrderAppStatisticVO> tableTops = kwoTradeOrderMapper.appStatistic(dto, statuses, authUserIds);
        Map<Integer, Integer> map = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        if (CollUtil.isNotEmpty(tableTops)) {
            map = tableTops.stream().collect(Collectors.toMap(TradeOrderAppStatisticVO::getValue, TradeOrderAppStatisticVO::getTotal, (k1, k2) -> k2));
        }
        List<TradeOrderAppStatisticVO> statistics = new ArrayList<>();
        for (Integer e : statuses) {
            int total = Objects.isNull(map.get(e)) ? 0 : map.get(e);
            TradeOrderAppStatisticVO statistic = new TradeOrderAppStatisticVO();
            statistic.setValue(e).setTotal(total);
            statistics.add(statistic);
        }
        return statistics;
    }

    /**
     * 贸易订单详情看板：完成率、今日/本月完成量、已派车次数（与贸易订单关联运单，按计费方式统计装卸货量）
     *
     * @param tOrderId 贸易订单主键
     * @return 看板数据
     */
    public TradeOrderDashboardVO tradeOrderDashboardStatistic(Long tOrderId) {
        if (Objects.isNull(tOrderId) || tOrderId <= 0) {
            throw new BusinessException("贸易订单主键不能为空");
        }
        KwoTradeOrder order = kwoTradeOrderMapper.selectById(tOrderId);
        if (order == null) {
            throw new BusinessException("不存在该订单！");
        }
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        LocalDate today = LocalDate.now(zone);
        LocalDateTime dayStart = today.atStartOfDay();
        LocalDateTime dayEnd = dayStart.plusDays(1);
        LocalDateTime monthStart = today.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
        LocalDateTime monthEnd = monthStart.plusMonths(1);

        BigDecimal completionRate = TradeOrderDashboardUtils.completionRateOf(order);
        Long tripCount = getDispatchedWaybillCount(tOrderId);

        Integer chargeType = order.getChargeType();
        BigDecimal todayVol = BigDecimal.ZERO;
        BigDecimal monthVol = BigDecimal.ZERO;
        if (Objects.equals(chargeType, ChargingTypeEnum.ON.getCode())
                || Objects.equals(chargeType, ChargingTypeEnum.OFF.getCode())) {
            todayVol = getCompletedWaybillVolume(tOrderId, chargeType, dayStart, dayEnd);
            monthVol = getCompletedWaybillVolume(tOrderId, chargeType, monthStart, monthEnd);
        }
        todayVol = todayVol.setScale(2, RoundingMode.HALF_UP);
        monthVol = monthVol.setScale(2, RoundingMode.HALF_UP);

        return new TradeOrderDashboardVO()
                .setCompletionRate(completionRate)
                .setTodayTotalVolume(todayVol)
                .setTripCount(tripCount)
                .setMonthTotalVolume(monthVol);
    }

    /**
     * 获取贸易订单已派车次。
     *
     * @param tOrderId 贸易订单ID
     * @return 已派车次数
     */
    private Long getDispatchedWaybillCount(Long tOrderId) {
        log.info("[车次]开始计算贸易订单已派车次：{}", JSON.toJSONString(tOrderId));
        try {
            return Optional.ofNullable(transportRemoteStatisticsService.countDispatchedWaybillsByTradeOrderId(tOrderId))
                    .orElse(0L);
        } catch (Exception e) {
            log.error("查询贸易订单已派车次失败，tOrderId={}", tOrderId, e);
            throw new BusinessException("查询贸易订单已派车次失败");
        }
    }

    /**
     * 获取贸易订单指定时间范围内的运单完成量。
     *
     * @param tOrderId   贸易订单ID
     * @param chargeType 计费方式
     * @param startTime  开始时间
     * @param endTime    结束时间
     * @return 运单完成量
     */
    private BigDecimal getCompletedWaybillVolume(Long tOrderId, Integer chargeType,
                                                 LocalDateTime startTime, LocalDateTime endTime) {
        try {
            return Optional.ofNullable(transportRemoteStatisticsService.sumCompletedWaybillVolumeByTimeRange(
                            tOrderId, chargeType, startTime, endTime))
                    .orElse(BigDecimal.ZERO);
        } catch (Exception e) {
            log.error("查询贸易订单运单完成量失败，tOrderId={}, chargeType={}, startTime={}, endTime={}",
                    tOrderId, chargeType, startTime, endTime, e);
            throw new BusinessException("查询贸易订单运单完成量失败");
        }
    }

    /**
     * @desc: 贸易订单列表导出
     * @author: yzc
     * @date: 2023-07-17 18:05
     * @Param params:
     * @return: java.util.List<com.sckw.report.service.param.TradeOrderListExport>
     */


    public TradeOrderCountResp countStatistic() {
        Long entId = LoginUserHolder.getEntId();
        Set<Long> tradeOrderIds = kwoTradeOrderUnitRepository
                .queryByEntIdAndUnitType(entId, OrderUnitTypeEnum.PURCHASE.getType())
                .stream()
                .map(KwoTradeOrderUnit::getTOrderId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Long totalCount = 0L;
        Map<Integer, Long> statusCountMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        if (CollUtil.isNotEmpty(tradeOrderIds)) {
            QueryWrapper<KwoTradeOrder> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("status", "COUNT(1) AS statusCount")
                    .eq("del_flag", Global.NO)
                    .in("id", tradeOrderIds)
                    .groupBy("status")
                    .orderByAsc("status");

            List<Map<String, Object>> statisticMaps = kwoTradeOrderMapper.selectMaps(queryWrapper);
            if (CollUtil.isNotEmpty(statisticMaps)) {
                statusCountMap = statisticMaps.stream()
                        .filter(item -> Objects.nonNull(item.get("status")))
                        .collect(Collectors.toMap(item -> Integer.parseInt(String.valueOf(item.get("status"))),
                                item -> Long.parseLong(String.valueOf(item.get("statusCount"))),
                                Long::sum));
            }

            totalCount = Optional.ofNullable(kwoTradeOrderMapper.selectCount(
                    new LambdaQueryWrapper<KwoTradeOrder>()
                            .eq(KwoTradeOrder::getDelFlag, Global.NO)
                            .in(KwoTradeOrder::getId, tradeOrderIds))).orElse(0L);
        }

        Set<Integer> statuses = new TreeSet<>();
        TradeOrderStatusEnum.getSortList().stream().map(TradeOrderStatusEnum::getCode).forEach(statuses::add);
        statuses.addAll(statusCountMap.keySet());

        List<TradeOrderCountResp.TradeOrderCountItem> items = new ArrayList<>(statuses.size());
        for (Integer status : statuses) {
            TradeOrderCountResp.TradeOrderCountItem item = new TradeOrderCountResp.TradeOrderCountItem();
            item.setStatus(status)
                    .setStatusDesc(getTradeOrderStatusDesc(status))
                    .setStatusCount(statusCountMap.getOrDefault(status, 0L));
            items.add(item);
        }
        return new TradeOrderCountResp().setTotalCount(totalCount).setItems(items);
    }

    private String getTradeOrderStatusDesc(Integer status) {
        String statusDesc = TradeOrderStatusEnum.getMsg(status);
        if (StrUtil.isNotBlank(statusDesc)) {
            return statusDesc;
        }
        statusDesc = OrderStatusEnum.getMsg(status);
        return StrUtil.isNotBlank(statusDesc) ? statusDesc : "unknown";
    }

    public List<TradeOrderListExport> export(TradeOrderListExportParam params) {
        TradeOrderListSelectDTO dto = new TradeOrderListSelectDTO();
        List<Long> ids = new ArrayList<>();
        if (StringUtils.isNotBlank(params.getIds())) {
            ids = StringUtils.splitStrToList(params.getIds(), ",", Long.class);
            dto.setEntId(LoginUserHolder.getEntId()).setOrderType(params.getOrderType());
        } else {
            dto = buildSelectParam(params);
        }
        List<OrderListResDTO> orders = kwoTradeOrderMapper.tradeOrderExport(dto, dto.getGoodIds(), LoginUserHolder.getAuthUserIdList(), ids);
        if (CollUtil.isEmpty(orders)) {
            return new ArrayList<>();
        }
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.TORDER_STATUS.getType(), DictTypeEnum.PICKUP_TYPE.getType(), DictTypeEnum.DELIVERY_TYPE.getType(), DictTypeEnum.TORDER_SOURCE.getType(), DictTypeEnum.TRADE_TYPE.getType()));
        Map<String, String> statusMap, pickupMap, deliveryMap, sourceMap, tradeMap;
        if (CollUtil.isNotEmpty(dict)) {
            statusMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_STATUS.getType())) ? dict.get(DictTypeEnum.TORDER_STATUS.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            pickupMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.PICKUP_TYPE.getType())) ? dict.get(DictTypeEnum.PICKUP_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            deliveryMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.DELIVERY_TYPE.getType())) ? dict.get(DictTypeEnum.DELIVERY_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            sourceMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_SOURCE.getType())) ? dict.get(DictTypeEnum.TORDER_SOURCE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            tradeMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TRADE_TYPE.getType())) ? dict.get(DictTypeEnum.TRADE_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
        } else {
            statusMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            pickupMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            deliveryMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            sourceMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            tradeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        }
        List<Long> goodIdList = new ArrayList<>();
        List<Long> contracIdList = new ArrayList<>();
        List<Long> createByIds = new ArrayList<>();
        orders.forEach(e -> {
            goodIdList.add(e.getGoodsId());
            contracIdList.add(e.getContractId());
            createByIds.add(e.getCreateBy());
        });
        Map<Long, UserCacheResDto> userMap = remoteSystemService.queryUserCacheMapByIds(createByIds);
        Map<Long, KwpGoods> goodsMap = goodsInfoService.getGoodsByIds(goodIdList);
        Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(contracIdList);
        List<TradeOrderListExport> list = new ArrayList<>();
        orders.forEach(e -> {
            TradeOrderListExport vo = BeanUtil.copyProperties(e, TradeOrderListExport.class);
            List<LoadAddressDTO> loadAddresses = e.getLoadAddresses();
            if (CollUtil.isNotEmpty(loadAddresses)) {
                StringBuilder loadName = new StringBuilder();
                StringBuilder loadDetailAddressInfo = new StringBuilder();
                for (int i = 0; i < loadAddresses.size(); i++) {
                    LoadAddressDTO l = loadAddresses.get(i);
                    if (i != loadAddresses.size() - 1) {
                        loadName.append(l.getLoadName()).append("，");
                        loadDetailAddressInfo.append(l.getLoadCityName()).append(l.getLoadDetailAddress()).append("，");
                    } else {
                        loadName.append(l.getLoadName());
                        loadDetailAddressInfo.append(l.getLoadCityName()).append(l.getLoadDetailAddress());
                    }
                }
                vo.setLoadName(loadName.toString()).setLoadDetailAddressInfo(loadDetailAddressInfo.toString());
            }
            List<UnloadAddressDTO> unloadAddresses = e.getUnloadAddresses();
            if (CollUtil.isNotEmpty(unloadAddresses)) {
                StringBuilder unloadName = new StringBuilder();
                StringBuilder unloadDetailAddressInfo = new StringBuilder();
                for (int i = 0; i < unloadAddresses.size(); i++) {
                    UnloadAddressDTO ul = unloadAddresses.get(i);
                    if (i != unloadAddresses.size() - 1) {
                        unloadName.append(ul.getUnloadName()).append("，");
                        unloadDetailAddressInfo.append(ul.getUnloadCityName()).append(ul.getUnloadDetailAddress()).append("，");
                    } else {
                        unloadName.append(ul.getUnloadName());
                        unloadDetailAddressInfo.append(ul.getUnloadCityName()).append(ul.getUnloadDetailAddress());
                    }
                }
                vo.setUnloadName(unloadName.toString()).setUnloadDetailAddressInfo(unloadDetailAddressInfo.toString());
            }
            KwpGoods goods = goodsMap.get(e.getGoodsId());
            ContractCommonInfoResDto contract = contractMap.get(e.getContractId());
            UserCacheResDto userCache = userMap.get(e.getCreateBy());
            BigDecimal waitEntrustAmount = getWaitEntrustAmount(e.getAmount(), e.getEntrustAmount());
            vo.setStatus(statusMap.get(String.valueOf(vo.getStatus()))).setGoodsName(Objects.isNull(goods) ? null : goods.getName()).setGoodsSpec(Objects.isNull(goods) ? null : goods.getSpec()).setUnitPrice(String.valueOf(setScale(e.getUnitPrice()))).setAmount(String.valueOf(setScale(e.getAmount()))).setPrice(String.valueOf(setScale(e.getPrice()))).setGoodsTaxRate(Objects.isNull(goods) ? null : goods.getTaxRate()).setEntrustAmount(String.valueOf(setScale(e.getEntrustAmount()))).setActualAmount(String.valueOf(setScale(e.getActualAmount()))).setWaitEntrustAmount(String.valueOf(setScale(waitEntrustAmount))).setPickupType(pickupMap.get(e.getPickupType())).setDeliveryType(deliveryMap.get(e.getDeliveryType())).setSource(sourceMap.get(e.getSource())).setTrading(tradeMap.get(e.getTrading())).setStartTime(Objects.isNull(e.getStartTime()) ? null : e.getStartTime().toString()).setEndTime(Objects.isNull(e.getEndTime()) ? null : e.getEndTime().toString()).setContractSigningWay(Objects.isNull(contract) ? null : contract.getSigningWayName()).setCreateByName(Objects.isNull(userCache) ? null : userCache.getName()).setCreateTime(com.sckw.excel.utils.DateUtil.getDateTime(e.getCreateTime()));
            list.add(vo);
        });
        return list;
    }

    /**
     * @desc: 贸易订单对账单分页列表查询
     * @author: yzc
     * @date: 2023-07-20 15:03
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult tradeOrderStatementList(TradeOrderStatementList params) {
        TradeOrderStatementListParamDTO dto = BeanUtil.copyProperties(params, TradeOrderStatementListParamDTO.class);
        List<Long> excludeIds = new ArrayList<>();
        if (StringUtils.isNotBlank(params.getExcludeIds())) {
            excludeIds = StringUtils.splitStrToList(params.getExcludeIds(), ",", Long.class);
        }
        dto.setEntId(LoginUserHolder.getEntId());
        List<Long> goodsIds = goodsInfoService.getGoodsByGoodsNameAndTaxRate(params.getGoodsName(), params.getGoodsTaxRate());
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<OrderListResDTO> list = kwoTradeOrderMapper.tradeOrderStatementList(dto, goodsIds, excludeIds);
        return buildResult(list, params.getPageSize());
    }

    /**
     * @desc: 合同关联订单列表
     * @author: yzc
     * @date: 2023-07-27 17:05
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult tradeOrderContractList(TradeOrderContractParam params) {
        TradeOrderContractParamDTO dto = BeanUtil.copyProperties(params, TradeOrderContractParamDTO.class);
        dto.setEntId(LoginUserHolder.getEntId());
        List<Long> contractIds = StringUtils.splitStrToList(params.getContractIds(), ",", Long.class);
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<OrderListResDTO> list = kwoTradeOrderMapper.tradeOrderContractList(dto, contractIds);
        return buildResult(list, params.getPageSize());
    }


    public List<OrderSaleVo> queryRecentSale(LocalDateTime start, LocalDateTime end) {
        return kwoTradeOrderMapper.querySaleOrder(start, end);
    }

    /**
     * 新增贸易订单
     *
     * @param tradeOrderParam
     */
    @Transactional(rollbackFor = Exception.class)
    public void addTradeOrder(TradeOrderParam tradeOrderParam) {
        KwoTradeOrder order = new KwoTradeOrder();
        order.setId(new IdWorker(1).nextId());
        //商品信息
        KwpGoods goodsById = goodsInfoService.getGoodsById(tradeOrderParam.getGoodsId());

        TradeContractResDto tradeContractResDto = checkPara(tradeOrderParam, order, goodsById);

        // ====== 下单前校验 start ======

        // 2. 验证商品是否开启库存（amount不为null代表已开启库存，null代表无限库存无需验证）
        if (goodsById.getAmount() != null && goodsById.getAmount().compareTo(tradeOrderParam.getAmount()) < 0) {
            if (!Boolean.TRUE.equals(tradeOrderParam.getConfirmInsufficientStock())) {
                throw new CustomPromptException(HttpStatus.STOCK_INSUFFICIENT_CONFIRM_CODE, "当前库存可能不足，是否依旧下单？");
            }
        }

        // 5. 验证贸易合同限量采购，若为限量采购则校验剩余可采购数量并扣减本次下单量
        GoodsInfoDto contractGoodsInfo = tradeContractResDto.getGoodsInfoDto();
        if (contractGoodsInfo.getAmount() != null && contractGoodsInfo.getAmount().compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal performed = contractGoodsInfo.getPerformedAmount() != null ? contractGoodsInfo.getPerformedAmount() : BigDecimal.ZERO;
            BigDecimal remaining = contractGoodsInfo.getAmount().subtract(performed);
            if (tradeOrderParam.getAmount().compareTo(remaining) > 0) {
                throw new BusinessException("当前贸易合同该商品为限量采购，剩余可采购数量为" + remaining.stripTrailingZeros().toPlainString() + "，本次下单数量超出限额");
            }
            remoteContractService.updateTradeContractGoodsPerformed(tradeOrderParam.getTradeContractId(), tradeOrderParam.getGoodsId(), tradeOrderParam.getAmount());
        }
        // ====== 下单前校验 end ======

        // 收费策略开启时冻结采购方服务费，并记录订单收费策略信息
        Long purchaseEntId = resolvePurchaseEntId(tradeContractResDto.getUnitList());
        Long supplyEntId = resolveSupplyEntId(tradeContractResDto.getUnitList());
        ParkingWalletFeeFreezeParam feeFreezeParam = new ParkingWalletFeeFreezeParam();
        feeFreezeParam.setOrderNo(order.getTOrderNo());
        feeFreezeParam.setProEntId(purchaseEntId);
        feeFreezeParam.setSupEntId(551429255406292993L);
        feeFreezeParam.setPurchaseQuantity(tradeOrderParam.getAmount());
        feeFreezeParam.setOperatorId(LoginUserHolder.getUserId());
        log.info("贸易订单下单应用收费策略，orderNo:{}, feeFreezeParam:{}", order.getTOrderNo(), JSON.toJSONString(feeFreezeParam));
        ParkingWalletFeeFreezeResult feeFreezeResult = resolveParkingWalletFeeFeignResult(
                parkingWalletFeeFeignService.applyChargeStrategyFreeze(feeFreezeParam), "服务费冻结");
        fillChargeStrategyInfo(order, feeFreezeResult);
        log.info("贸易订单收费策略处理完成，orderNo:{}, feeFreezeResult:{}", order.getTOrderNo(), JSON.toJSONString(feeFreezeResult));

        //商品地址信息
        AddressInfoDetail goodsAddress = goodsInfoService.getGoodsAddress(tradeOrderParam.getGoodsId());
        if (Objects.isNull(goodsAddress)) {
            throw new BusinessException("商品发货地址信息不存在");
        }
        order.setSettlement(tradeContractResDto.getSettlement());
        kwoTradeOrderMapper.insert(order);//贸易订单
//        walletFreeze.setTTradeOrderId(order.getId());

        GoodsInfoDto goodsInfoDto = tradeContractResDto.getGoodsInfoDto();//贸易合同，下合同关联的商品信息
        KwoTradeOrderGoods kwoTradeOrderGoods = new KwoTradeOrderGoods();
        kwoTradeOrderGoods.setId(new IdWorker(1).nextId());
        kwoTradeOrderGoods.setTOrderId(order.getId());
        kwoTradeOrderGoods.setTOrderNo(order.getTOrderNo());
        kwoTradeOrderGoods.setGoodsId(tradeOrderParam.getGoodsId());
        kwoTradeOrderGoods.setGoodsType(goodsById.getGoodsType());
        kwoTradeOrderGoods.setSkuId(goodsInfoDto.getSkuId());
        kwoTradeOrderGoods.setUnit(goodsById.getUnit());
        kwoTradeOrderGoods.setUnitPrice(goodsInfoDto.getPrice());
        kwoTradeOrderGoods.setPriceRangeId(0L);//
        kwoTradeOrderGoods.setGoodsName(goodsById.getName());
        kwoTradeOrderGoods.setRemark("");
        kwoTradeOrderGoods.setStatus(0);
        kwoTradeOrderGoods.setCreateBy(LoginUserHolder.getUserId());
        kwoTradeOrderGoods.setCreateTime(new Date());
        kwoTradeOrderGoods.setDelFlag(0);
        kwoTradeOrderGoodsService.insert(kwoTradeOrderGoods);

        KwoTradeOrderAddress kwoTradeOrderAddress = new KwoTradeOrderAddress();
        kwoTradeOrderAddress.setId(new IdWorker(1).nextId());
        kwoTradeOrderAddress.setTOrderId(order.getId());
        kwoTradeOrderAddress.setTOrderNo(order.getTOrderNo());
        kwoTradeOrderAddress.setAddressType("1");
        kwoTradeOrderAddress.setName(goodsAddress.getName());
        kwoTradeOrderAddress.setType(goodsAddress.getType());
        kwoTradeOrderAddress.setContacts(goodsAddress.getContacts());
        kwoTradeOrderAddress.setPhone(goodsAddress.getPhone());
        kwoTradeOrderAddress.setCityCode(goodsAddress.getCityCode());
        kwoTradeOrderAddress.setCityName(goodsAddress.getCityName());
        kwoTradeOrderAddress.setDetailAddress(goodsAddress.getDetailAddress());
        kwoTradeOrderAddress.setLat(goodsAddress.getLat());
        kwoTradeOrderAddress.setLng(goodsAddress.getLng());
        kwoTradeOrderAddress.setFence(goodsAddress.getFence());
        kwoTradeOrderAddress.setSort(1);
        kwoTradeOrderAddress.setRemark("");
        kwoTradeOrderAddress.setStatus(0);
        kwoTradeOrderAddress.setCreateBy(LoginUserHolder.getUserId());
        kwoTradeOrderAddress.setCreateTime(new Date());
        kwoTradeOrderAddress.setDelFlag(0);
        kwoTradeOrderAddressService.add(kwoTradeOrderAddress);

        AddressInfoPara addressInfo = tradeOrderParam.getAddressInfo();
        KwoTradeOrderAddress kwoTradeOrderAddress2 = new KwoTradeOrderAddress();
        kwoTradeOrderAddress2.setId(new IdWorker(1).nextId());
        kwoTradeOrderAddress2.setTOrderId(order.getId());
        kwoTradeOrderAddress2.setTOrderNo(order.getTOrderNo());
        kwoTradeOrderAddress2.setAddressType("2");
        kwoTradeOrderAddress2.setName(addressInfo.getName());
        kwoTradeOrderAddress2.setType(addressInfo.getType());
        kwoTradeOrderAddress2.setContacts(addressInfo.getContacts());
        kwoTradeOrderAddress2.setPhone(addressInfo.getPhone());
        kwoTradeOrderAddress2.setCityCode(addressInfo.getCityCode());
        kwoTradeOrderAddress2.setCityName(addressInfo.getCityName());
        kwoTradeOrderAddress2.setDetailAddress(addressInfo.getDetailAddress());
        kwoTradeOrderAddress2.setLat(addressInfo.getLat());
        kwoTradeOrderAddress2.setLng(addressInfo.getLng());
        kwoTradeOrderAddress2.setFence(addressInfo.getFence());
        kwoTradeOrderAddress2.setSort(2);
        kwoTradeOrderAddress2.setRemark("");
        kwoTradeOrderAddress2.setStatus(0);
        kwoTradeOrderAddress2.setCreateBy(LoginUserHolder.getUserId());
        kwoTradeOrderAddress2.setCreateTime(new Date());
        kwoTradeOrderAddress2.setDelFlag(0);
        kwoTradeOrderAddressService.add(kwoTradeOrderAddress2);

        KwoTradeOrderContract kwoTradeOrderContract = new KwoTradeOrderContract();
        kwoTradeOrderContract.setContractId(tradeOrderParam.getTradeContractId());
        kwoTradeOrderContract.setContractNo(tradeOrderParam.getTradeContractNo());
        kwoTradeOrderContract.setTOrderId(order.getId());
        kwoTradeOrderContract.setTOrderNo(order.getTOrderNo());
        kwoTradeOrderContract.setId(new IdWorker(1).nextId());
        kwoTradeOrderContract.setRemark("");
        kwoTradeOrderContract.setStatus(0);
        kwoTradeOrderContract.setCreateBy(LoginUserHolder.getUserId());
        kwoTradeOrderContract.setCreateTime(new Date());
        kwoTradeOrderContract.setDelFlag(0);
        kwoTradeOrderContractService.insert(kwoTradeOrderContract);//贸易合同信息

        List<LogisticsEntDto> logisticsContractId = tradeOrderParam.getLogisticsContractList();
        if (Objects.equals(tradeContractResDto.getConsignment(), 1) && CollUtil.isNotEmpty(logisticsContractId)) {
            for (LogisticsEntDto logisticsEntDto : logisticsContractId) {
                KwoTradeOrderTransport kwoTradeOrderTransport = new KwoTradeOrderTransport();
                kwoTradeOrderTransport.setId(new IdWorker(1).nextId());
                kwoTradeOrderTransport.setTOrderId(order.getId());
                kwoTradeOrderTransport.setTOrderNo(order.getTOrderNo());
                kwoTradeOrderTransport.setEntId(logisticsEntDto.getEntId());
                kwoTradeOrderTransport.setFirmName(logisticsEntDto.getEntName());
                kwoTradeOrderTransport.setContractId(logisticsEntDto.getContractId());
                kwoTradeOrderTransport.setContractNo(logisticsEntDto.getContractNo());
                kwoTradeOrderTransport.setTransportPrice(logisticsEntDto.getTransportPrice());
                kwoTradeOrderTransport.setContactsId(logisticsEntDto.getContactsId());
                kwoTradeOrderTransport.setContacts(logisticsEntDto.getContacts());
                kwoTradeOrderTransport.setPhone(logisticsEntDto.getPhone());
                kwoTradeOrderTransport.setRemark("");
                kwoTradeOrderTransport.setStatus(0);
                kwoTradeOrderTransport.setCreateBy(LoginUserHolder.getUserId());
                kwoTradeOrderTransport.setCreateTime(LocalDateTime.now());
                if (Objects.equals(logisticsEntDto.getContractId(), 0L)) {//查询平台默认物流对应的企业id
                    kwoTradeOrderTransport.setEntId(1L);//todo 硬编码，平台默认物流企业
                    kwoTradeOrderTransport.setFirmName("平台默认物流");
                }

                kwoTradeOrderTransportService.insert(kwoTradeOrderTransport);
            }
        }
        List<TradeContractUnitDto> unitList = tradeContractResDto.getUnitList();
        List<KwoTradeOrderUnit> list = new ArrayList<>();
        WalletPrepaidDto walletFreeze = new WalletPrepaidDto();
        walletFreeze.setOrderNo(order.getTOrderNo());
        walletFreeze.setTradeAmount(order.getPrice());
        unitList.forEach(e -> {
            KwoTradeOrderUnit unit = BeanUtil.copyProperties(e, KwoTradeOrderUnit.class);
            unit.setId(new IdWorker(1).nextId());
            unit.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setTopEntId(e.getEntId());
            unit.setUnitType(StrUtil.equals(e.getUnitType(), "1") ? "2" : "1");//贸易合同和订单的单位类型相反
            if (StrUtil.equals(unit.getUnitType(), "1")) {
//                walletFreeze.setBuyEntId(unit.getEntId());
                walletFreeze.setProEntId(unit.getEntId());
            }
            if (StrUtil.equals(unit.getUnitType(), "2")) {
//                walletFreeze.setSaleEntId(unit.getEntId());
                walletFreeze.setSupEntId(unit.getEntId());
            }
            list.add(unit);
        });
        kwoTradeOrderUnitService.insertBatch(list);
        //钱包
//        BaseResult<Boolean> booleanBaseResult = paymentDubboService.freezeMoney(walletFreeze);
        BaseResult<Object> freezeBaseResult = new BaseResult<>();
        if (Objects.equals(tradeContractResDto.getSettlement(), 1)) {
            // todo 普通结算冻结

        } else if (Objects.equals(tradeContractResDto.getSettlement(), 2)) {
            //预付制结算冻结
            walletFreeze.setOrderType(4);
            walletFreeze.setTradeType(4);
            walletFreeze.setRemark("贸易订单号：" + walletFreeze.getOrderNo() + ",下单冻结");
            log.info("贸易订单号：{}，订单下单调用钱包服务冻结预付余额，参数：{}", walletFreeze.getOrderNo(), JSON.toJSONString(walletFreeze));
            freezeBaseResult = paymentFeignService.updatePrepaidBalance(walletFreeze);
        }

        if (freezeBaseResult.getCode() != 60200) {
            throw new BusinessException(freezeBaseResult.getMessage());
        }
    }

    /**
     * 将贸易合同单位类型转换为贸易订单单位类型。
     * <p>
     * 贸易合同中的供应/采购单位与贸易订单中的采购/销售单位方向相反；
     * 代理单位不参与方向反转，固定落库为类型3。
     * </p>
     *
     * @param contractUnitType 贸易合同单位类型
     * @return 贸易订单单位类型
     */
    static String convertContractUnitTypeToOrderUnitType(String contractUnitType) {
        if (StrUtil.equals(contractUnitType, AGENT_UNIT_TYPE)) {
            return AGENT_UNIT_TYPE;
        }
        return StrUtil.equals(contractUnitType, "1") ? "2" : "1";
    }

    /**
     * 解析贸易合同中的采购方企业id
     */
    private Long resolvePurchaseEntId(List<TradeContractUnitDto> unitList) {
        if (CollUtil.isEmpty(unitList)) {
            throw new BusinessException("贸易合同企业信息不存在");
        }
        return unitList.stream()
                .filter(unit -> StrUtil.equals(convertContractUnitTypeToOrderUnitType(unit.getUnitType()), "1"))
                .map(TradeContractUnitDto::getEntId)
                .filter(Objects::nonNull)
                .findFirst()
                .orElseThrow(() -> new BusinessException("采购方企业信息不存在"));
    }

    /**
     * 解析贸易合同中的供应方企业id
     */
    private Long resolveSupplyEntId(List<TradeContractUnitDto> unitList) {
        if (CollUtil.isEmpty(unitList)) {
            throw new BusinessException("贸易合同企业信息不存在");
        }
        return unitList.stream()
                .filter(unit -> StrUtil.equals(convertContractUnitTypeToOrderUnitType(unit.getUnitType()), "2"))
                .map(TradeContractUnitDto::getEntId)
                .filter(Objects::nonNull)
                .findFirst()
                .orElseThrow(() -> new BusinessException("供应方企业信息不存在"));
    }

    /**
     * 回填贸易订单收费策略信息
     */
    private void fillChargeStrategyInfo(KwoTradeOrder order, ParkingWalletFeeFreezeResult feeFreezeResult) {
        if (feeFreezeResult == null) {
            order.setApplyChargeStrategy(Global.NO);
            return;
        }
        order.setApplyChargeStrategy(feeFreezeResult.getApplyChargeStrategy() == null ? Global.NO : feeFreezeResult.getApplyChargeStrategy());
        order.setChargeStrategyId(feeFreezeResult.getChargeStrategyId());
        order.setChargeStrategyDesc(feeFreezeResult.getChargeStrategyDesc());
        order.setChargeStrategyAmount(feeFreezeResult.getChargeStrategyAmount());
    }

    /**
     * 买家撤销贸易订单
     */
    public void cancelTradeOrder(CancelTradeOrderParam param) {
        KwoTradeOrder order = kwoTradeOrderMapper.selectOne(
                new LambdaQueryWrapper<KwoTradeOrder>()
                        .eq(KwoTradeOrder::getId, param.getTradeContractId())
                        .eq(KwoTradeOrder::getDelFlag, 0)
        );
        if (Objects.isNull(order)) {
            throw new BusinessException("贸易订单不存在");
        }
        if (!Objects.equals(order.getStatus(), TradeOrderStatusEnum.AUDIT.getCode())) {
            throw new BusinessException("当前订单状态不允许撤销");
        }
        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(param.getTradeContractId(), param.getGoodsId());
        // 1. 线下钱包加回预付余额、减冻结金额
        List<TradeContractUnitDto> unitList = tradeContractResDto.getUnitList();
        WalletPrepaidDto freezeDto = new WalletPrepaidDto();
        unitList.forEach(e -> {
            KwoTradeOrderUnit unit = BeanUtil.copyProperties(e, KwoTradeOrderUnit.class);
            unit.setId(new IdWorker(1).nextId());
            unit.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setTopEntId(e.getEntId());
            unit.setUnitType(StrUtil.equals(e.getUnitType(), "1") ? "2" : "1");//贸易合同和订单的单位类型相反
            if (StrUtil.equals(unit.getUnitType(), "1")) {
                freezeDto.setProEntId(unit.getEntId());
            }
            if (StrUtil.equals(unit.getUnitType(), "2")) {
                freezeDto.setSupEntId(unit.getEntId());
            }
        });
        freezeDto.setOrderNo(order.getTOrderNo());
        freezeDto.setOrderType(4);
        freezeDto.setTradeType(5);
        freezeDto.setRemark("贸易订单号：" + freezeDto.getOrderNo() + ",撤销订单");
        BaseResult<Object> balanceResult;
        try {
            log.info("贸易订单号：{}，订单撤销调用钱包服务解冻预付余额，参数：{}", freezeDto.getOrderNo(), JSON.toJSONString(freezeDto));
            balanceResult = paymentFeignService.updatePrepaidBalance(freezeDto);
        } catch (Exception e) {
            String errMsg = freezeDto.getRemark() + "异常";
            log.error(errMsg, e);
            throw new BusinessException(errMsg);
        }
        if (balanceResult == null || balanceResult.getCode() != HttpStatus.SUCCESS_CODE || !Boolean.TRUE.equals(balanceResult.getData())) {
            String errMsg = freezeDto.getRemark() + "失败";
            log.error("{}:{}", errMsg, balanceResult != null ? balanceResult.getMessage() : "");
            throw new BusinessException(errMsg);
        }

        // 3. 贸易合同该商品有采购数量，则更新采购数量（加回本单总量）
        KwoTradeOrderGoods orderGoods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        KwoTradeOrderContract orderContract = kwoTradeOrderContractService.getByOrderId(order.getId());
        if (Objects.nonNull(orderGoods) && Objects.nonNull(orderContract)) {
            TradeContractResDto contractRes = remoteContractService.queryTradeContract(orderContract.getContractId(), orderGoods.getGoodsId());
            if (Objects.nonNull(contractRes) && Objects.nonNull(contractRes.getGoodsInfoDto())) {
                GoodsInfoDto goodsInfo = contractRes.getGoodsInfoDto();
                if (goodsInfo.getAmount() != null && goodsInfo.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                    remoteContractService.updateTradeContractGoodsPerformed(
                            orderContract.getContractId(), orderGoods.getGoodsId(), order.getAmount().negate()
                    );
                }
            }
        }

        // 4. 更新贸易订单状态为"取消"
        order.setStatus(TradeOrderStatusEnum.CANCEL.getCode());
        kwoTradeOrderMapper.updateById(order);
    }

    private TradeContractResDto checkPara(TradeOrderParam tradeOrderParam, KwoTradeOrder order, KwpGoods goodsById) {
        if (Objects.isNull(goodsById) || Objects.equals(goodsById.getDelFlag(), Global.YES)) {
            throw new BusinessException("商品信息不存在");
        }
        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(tradeOrderParam.getTradeContractId(), tradeOrderParam.getGoodsId());
        if (Objects.isNull(tradeContractResDto)) {
            throw new BusinessException("贸易合同不存在");
        }
        if (!Objects.equals(tradeContractResDto.getStatus(), Integer.parseInt(ContractStatusEnum.SIGNED.getCode()))) {
            throw new BusinessException("当前贸易合同未签约");
        }
        Integer consignment = tradeContractResDto.getConsignment();
        if (Objects.equals(consignment, 1) && CollUtil.isEmpty(tradeOrderParam.getLogisticsContractList())) {//采购方托运
            throw new BusinessException("采购方托运时，物流合同信息不能为空");
        }
        GoodsInfoDto goodsInfoDto = tradeContractResDto.getGoodsInfoDto();
        if (Objects.isNull(goodsInfoDto)) {
            throw new BusinessException("当前贸易订单不存在交易商品");
        }

        //结算方式校验余额
        BigDecimal orderAmount = NumberUtil.mul(tradeOrderParam.getAmount(), goodsInfoDto.getPrice());
        Integer settlement = tradeContractResDto.getSettlement();
        if (Objects.equals(settlement, 1)) {
            // todo 普通结算

        } else {
            //预付制结算
            BaseResult<BigDecimal> prepaidBalanceResult = null;
            try {
                prepaidBalanceResult = paymentFeignService.queryPrepaidBalance(goodsById.getSupplyEntId());
            } catch (Exception e) {
                log.error("查询线下钱包服务异常", e);
                throw new BusinessException("查询线下钱包服务异常，请稍后再试");
            }
            if (prepaidBalanceResult.getCode() == HttpStatus.SUCCESS_CODE) {
                if (orderAmount.compareTo(prepaidBalanceResult.getData()) > 0) {
                    throw new BusinessException("当前贸易订单金额大于可用预付余额");
                }
            } else {
                throw new BusinessException("查询对应供应商预付余额失败");
            }
        }
        tradeOrderParam.setTradeContractNo(tradeContractResDto.getContractNo());
        order.setUnit(goodsById.getUnit());
        order.setPickupType(String.valueOf(tradeContractResDto.getConsignment()));//来源于合同约束的托运方式
        order.setDeliveryType("");
        order.setTrading(String.valueOf(tradeContractResDto.getSigningWay()));//签约方式
        order.setPrice(orderAmount);//总金额
        order.setActualAmount(new BigDecimal("0"));
        order.setAssociateStatement(0);
        order.setLoadAmount(new BigDecimal("0"));
        order.setUnloadAmount(new BigDecimal("0"));
        order.setChargeType(tradeContractResDto.getUnloadWay());
        order.setDispatchWay(tradeContractResDto.getDispatchWay());
        order.setConsignmentWay(tradeContractResDto.getConsignment());
        order.setDispatchWay(tradeContractResDto.getDispatchWay());
        order.setEntId(LoginUserHolder.getEntId()).setTOrderNo(getOrderNo()).setAmount(tradeOrderParam.getAmount()).setStartTime(DateUtils.localDateToDateStart(tradeOrderParam.getStartTime())).setEndTime(DateUtils.localDateToDateEnd(tradeOrderParam.getEndTime())).setSource(OrderSourceEnum.PURCHASE.getType()).setStatus(TradeOrderStatusEnum.AUDIT.getCode()).setRemark(tradeOrderParam.getRemark());
        return tradeContractResDto;
    }

    /**
     * 订单审核
     *
     * @param tradeOrderAuditParam
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public TradeOrderAuditResp auditOrder(TradeOrderAuditParam tradeOrderAuditParam) {
        KwoTradeOrder kwoTradeOrder = kwoTradeOrderMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrder>().eq(KwoTradeOrder::getId, tradeOrderAuditParam.getId()).eq(KwoTradeOrder::getDelFlag, 0));
        if (Objects.isNull(kwoTradeOrder)) {
            throw new BusinessException("贸易订单不存在");
        }
        KwoTradeOrderGoods byOrderId = kwoTradeOrderGoodsService.getByOrderId(kwoTradeOrder.getId());
        if (Objects.isNull(byOrderId)) {
            throw new BusinessException("贸易订单关联商品信息不存在");
        }
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderId(kwoTradeOrder.getId());
        if (CollUtil.isEmpty(addressList)) {
            throw new BusinessException("贸易订单运输地址信息不存在");
        }
        Map<String, List<KwoTradeOrderAddress>> addressMap = addressList.stream().collect(Collectors.groupingBy(KwoTradeOrderAddress::getAddressType));
        if (CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.SHIPMENT.getCode()))) && CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.BOTH.getCode())))) {
            throw new BusinessException("装货地址信息不存在");
        }
        if (CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.TAKE.getCode()))) && CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.BOTH.getCode())))) {
            throw new BusinessException("卸货地址信息不存在");
        }
        List<KwoTradeOrderUnit> orderUnits = kwoTradeOrderUnitService.getByOrderId(kwoTradeOrder.getId());
        if (CollUtil.isEmpty(orderUnits)) {
            throw new BusinessException("贸易订单企业信息不存在");
        }
        Map<String, KwoTradeOrderUnit> unitMap = orderUnits.stream().collect(Collectors.toMap(KwoTradeOrderUnit::getUnitType, e -> e, (a, b) -> a));
        if (unitMap.keySet().size() < 2) {
            throw new BusinessException("贸易订单企业信息缺失");
        }

        if (Objects.equals(tradeOrderAuditParam.getStatus(), 2)) {
            BigDecimal serviceFeeBalance = null;
            // 审核拒绝：若应用了收费策略，解冻并返还采购方服务费余额
            if (Objects.equals(kwoTradeOrder.getApplyChargeStrategy(), Global.YES)) {
                ParkingWalletFeeFreezeParam serviceFeeUnfreezeParam = new ParkingWalletFeeFreezeParam();
                serviceFeeUnfreezeParam.setOrderNo(kwoTradeOrder.getTOrderNo());
                serviceFeeUnfreezeParam.setProEntId(unitMap.get(String.valueOf(1)).getEntId());
                serviceFeeUnfreezeParam.setSupEntId(551429255406292993L);
                serviceFeeUnfreezeParam.setOperatorId(LoginUserHolder.getUserId());
                log.info("贸易订单审核拒绝解冻服务费，orderNo:{}, param:{}",
                        kwoTradeOrder.getTOrderNo(), JSON.toJSONString(serviceFeeUnfreezeParam));
                ParkingWalletFeeFreezeResult unfreezeResult = resolveParkingWalletFeeFeignResult(
                        parkingWalletFeeFeignService.unfreezeChargeStrategy(serviceFeeUnfreezeParam), "服务费解冻");
                serviceFeeBalance = unfreezeResult.getServiceFeeBalance();
            }

            //钱包退回金额
            WalletPrepaidDto walletFreeze = new WalletPrepaidDto();
//            walletFreeze.setTTradeOrderId(kwoTradeOrder.getId());
            walletFreeze.setOrderNo(kwoTradeOrder.getTOrderNo());
            walletFreeze.setProEntId(unitMap.get(String.valueOf(1)).getEntId());
            walletFreeze.setSupEntId(unitMap.get(String.valueOf(2)).getEntId());
            walletFreeze.setOrderType(4);
            walletFreeze.setTradeType(5);
            walletFreeze.setRemark("贸易订单：" + walletFreeze.getOrderNo() + ",审核拒绝解冻");
//            BaseResult<Boolean> booleanBaseResult = paymentDubboService.unfreezeMoney(walletFreeze);

            BaseResult<Object> booleanBaseResult = new BaseResult<>();
            if (Objects.equals(kwoTradeOrder.getSettlement(), 1)) {
                // todo 普通结算解冻结

            } else if (Objects.equals(kwoTradeOrder.getSettlement(), 2)) {
                //预付制结算解冻
                log.info("贸易订单号：{}，订单审核拒绝调用钱包服务解冻预付余额，参数：{}", walletFreeze.getOrderNo(), JSON.toJSONString(walletFreeze));
                booleanBaseResult = paymentFeignService.updatePrepaidBalance(walletFreeze);
            }
            if (booleanBaseResult.getCode() != 60200) {
                throw new BusinessException(booleanBaseResult.getMessage());
            }

            KwoTradeOrderTrack kwoTradeOrderTrack = new KwoTradeOrderTrack();
            kwoTradeOrderTrack.setTOrderId(kwoTradeOrder.getId());
            kwoTradeOrderTrack.setTOrderNo(kwoTradeOrder.getTOrderNo());
            kwoTradeOrderTrack.setId(new IdWorker(1).nextId());
            kwoTradeOrderTrack.setRemark(tradeOrderAuditParam.getRemark());
            kwoTradeOrderTrack.setStatus(tradeOrderAuditParam.getStatus());//2-拒绝
            kwoTradeOrderTrack.setCreateBy(LoginUserHolder.getUserId());
            kwoTradeOrderTrack.setCreateTime(new Date());
            kwoTradeOrderTrack.setDelFlag(0);
            kwoTradeOrderTrackService.insert(kwoTradeOrderTrack);
            kwoTradeOrder.setStatus(Objects.equals(tradeOrderAuditParam.getStatus(), 2) ? TradeOrderStatusEnum.BACK.getCode() : TradeOrderStatusEnum.ING.getCode());
            kwoTradeOrderMapper.updateById(kwoTradeOrder);
            return buildAuditServiceFeeBalanceResp(kwoTradeOrder, unitMap, serviceFeeBalance);
        }
        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(tradeOrderAuditParam.getTradeContractId(), byOrderId.getGoodsId());
        if (Objects.isNull(tradeContractResDto)) {
            throw new BusinessException("贸易合同不存在");
        }
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        List<LogisticsEntDtoVO> validContractLog = new ArrayList<>();
        List<LogisticsEntDto> logisticsContractId = new ArrayList<>();
        if (Objects.equals(DispatchWayEnums.AUTO_DISPATCH.getCode(), tradeContractResDto.getDispatchWay()) && Objects.equals(tradeOrderAuditParam.getStatus(), Global.NUMERICAL_ONE)) {
            //自动派单校验： 判断当前有无包含该商品的有效自动派车物流合同
            validContractLog = checkAutoContractLogOrder(unitMap, byOrderId, tradeContractResDto);
        } else {
            logisticsContractId = tradeOrderAuditParam.getLogisticsContractList();
            if (Objects.equals(tradeContractResDto.getConsignment(), 2) && CollUtil.isEmpty(logisticsContractId)) {
                throw new BusinessException("卖方托运时，物流合同不能为空");
            }
        }

        KwoTradeOrderTrack kwoTradeOrderTrack = new KwoTradeOrderTrack();
        kwoTradeOrderTrack.setTOrderId(kwoTradeOrder.getId());
        kwoTradeOrderTrack.setTOrderNo(kwoTradeOrder.getTOrderNo());
        kwoTradeOrderTrack.setId(new IdWorker(1).nextId());
        kwoTradeOrderTrack.setRemark(tradeOrderAuditParam.getRemark());
        kwoTradeOrderTrack.setStatus(tradeOrderAuditParam.getStatus());//1-通过
        kwoTradeOrderTrack.setCreateBy(LoginUserHolder.getUserId());
        kwoTradeOrderTrack.setCreateTime(new Date());
        kwoTradeOrderTrack.setDelFlag(0);
        kwoTradeOrderTrackService.insert(kwoTradeOrderTrack);
        if (DispatchWayEnums.AUTO_DISPATCH.getCode().equals(kwoTradeOrder.getDispatchWay())) {
            for (LogisticsEntDtoVO logisticsEntDtoVO : validContractLog) {
                KwoTradeOrderTransport kwoTradeOrderTransport = new KwoTradeOrderTransport();
                kwoTradeOrderTransport.setId(new IdWorker(1).nextId());
                kwoTradeOrderTransport.setTOrderId(kwoTradeOrder.getId());
                kwoTradeOrderTransport.setTOrderNo(kwoTradeOrder.getTOrderNo());
                kwoTradeOrderTransport.setEntId(logisticsEntDtoVO.getEntId());
                kwoTradeOrderTransport.setFirmName(logisticsEntDtoVO.getEntName());
                kwoTradeOrderTransport.setContractId(logisticsEntDtoVO.getContractId());
                kwoTradeOrderTransport.setContractNo(logisticsEntDtoVO.getContractNo());
                kwoTradeOrderTransport.setTransportPrice(logisticsEntDtoVO.getTransportPrice());
                kwoTradeOrderTransport.setContactsId(logisticsEntDtoVO.getContactsId());
                kwoTradeOrderTransport.setContacts(logisticsEntDtoVO.getContacts());
                kwoTradeOrderTransport.setPhone(logisticsEntDtoVO.getPhone());
                kwoTradeOrderTransport.setRemark("");
                kwoTradeOrderTransport.setStatus(0);
                kwoTradeOrderTransport.setCreateBy(LoginUserHolder.getUserId());
                kwoTradeOrderTransport.setCreateTime(LocalDateTime.now());
                kwoTradeOrderTransportService.insert(kwoTradeOrderTransport);
            }
        } else {
            for (LogisticsEntDto logisticsEntDto : logisticsContractId) {
                KwoTradeOrderTransport kwoTradeOrderTransport = new KwoTradeOrderTransport();
                kwoTradeOrderTransport.setId(new IdWorker(1).nextId());
                kwoTradeOrderTransport.setTOrderId(kwoTradeOrder.getId());
                kwoTradeOrderTransport.setTOrderNo(kwoTradeOrder.getTOrderNo());
                kwoTradeOrderTransport.setEntId(logisticsEntDto.getEntId());
                kwoTradeOrderTransport.setFirmName(logisticsEntDto.getEntName());
                kwoTradeOrderTransport.setContractId(logisticsEntDto.getContractId());
                kwoTradeOrderTransport.setContractNo(logisticsEntDto.getContractNo());
                kwoTradeOrderTransport.setTransportPrice(logisticsEntDto.getTransportPrice());
                kwoTradeOrderTransport.setContactsId(logisticsEntDto.getContactsId());
                kwoTradeOrderTransport.setContacts(logisticsEntDto.getContacts());
                kwoTradeOrderTransport.setPhone(logisticsEntDto.getPhone());
                kwoTradeOrderTransport.setRemark("");
                kwoTradeOrderTransport.setStatus(0);
                kwoTradeOrderTransport.setCreateBy(LoginUserHolder.getUserId());
                kwoTradeOrderTransport.setCreateTime(LocalDateTime.now());
                kwoTradeOrderTransportService.insert(kwoTradeOrderTransport);
            }
        }
        //下游新增物流订单
        AddLogisticOrderParam addLogisticOrderParam = new AddLogisticOrderParam();
        if (DispatchWayEnums.AUTO_DISPATCH.getCode().equals(kwoTradeOrder.getDispatchWay())) {
            // 自动派车物流合同
            List<LogisticInfo> logisticInfoList = validContractLog.stream().map(d -> {
                LogisticInfo logisticInfo = new LogisticInfo();
                logisticInfo.setContractId(d.getContractId());
                logisticInfo.setContractNo(d.getContractNo());
                logisticInfo.setContractName("");
                logisticInfo.setAcceptCompanyId(d.getEntId());
                logisticInfo.setAcceptContactPhone("");
                logisticInfo.setAcceptContacts(d.getContacts());
                logisticInfo.setAcceptContactsId(d.getContactsId());
                logisticInfo.setAcceptCompany("");
                logisticInfo.setPrice(d.getTransportPrice());
                logisticInfo.setPriceType(0L);
                logisticInfo.setAmount(kwoTradeOrder.getAmount());
                logisticInfo.setAmountUnit(kwoTradeOrder.getUnit());
                logisticInfo.setLoss(new BigDecimal("0"));
                logisticInfo.setPayment(0L);
                logisticInfo.setSigningWay(0);
                logisticInfo.setLossUnit("");
                logisticInfo.setRemark("");
                logisticInfo.setType(0);

                return logisticInfo;
            }).collect(Collectors.toList());
            addLogisticOrderParam.setLogisticInfo(logisticInfoList);
            addLogisticOrderParam.setDispatchWay(DispatchWayEnums.AUTO_DISPATCH.getCode());

            //实际派车数
            Integer actualDisPatch = getActualDisPatch(kwoTradeOrder, unitMap, addressList);
            addLogisticOrderParam.setActualDisPatch(actualDisPatch);

        } else if (Objects.equals(tradeContractResDto.getConsignment(), 2)) {
            List<LogisticInfo> collect = logisticsContractId.stream().map(d -> {
                LogisticInfo logisticInfo = new LogisticInfo();
                logisticInfo.setContractId(d.getContractId());
                logisticInfo.setContractNo(d.getContractNo());
                logisticInfo.setContractName("");
                logisticInfo.setAcceptCompanyId(d.getEntId());
                logisticInfo.setAcceptContactPhone("");
                logisticInfo.setAcceptContacts(d.getContacts());
                logisticInfo.setAcceptContactsId(d.getContactsId());
                logisticInfo.setAcceptCompany("");
                logisticInfo.setPrice(d.getTransportPrice());
                logisticInfo.setPriceType(0L);
                logisticInfo.setAmount(kwoTradeOrder.getAmount());
                logisticInfo.setAmountUnit(kwoTradeOrder.getUnit());
                logisticInfo.setLoss(new BigDecimal("0"));
                logisticInfo.setPayment(0L);
                logisticInfo.setSigningWay(0);
                logisticInfo.setLossUnit("");
                logisticInfo.setRemark("");
                logisticInfo.setType(0);

                return logisticInfo;
            }).collect(Collectors.toList());
            addLogisticOrderParam.setLogisticInfo(collect);
            addLogisticOrderParam.setDispatchWay(DispatchWayEnums.MANUAL_DISPATCH.getCode());
        } else {
            List<KwoTradeOrderTransport> list = kwoTradeOrderTransportService.queryList(kwoTradeOrder.getId());
            if (CollUtil.isNotEmpty(list)) {
                //Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(list.stream().map(KwoTradeOrderTransport::getContractId).collect(Collectors.toList()));
                List<LogisticInfo> collect = list.stream().map(d -> {
                    LogisticInfo logisticInfo = new LogisticInfo();
                    logisticInfo.setContractId(d.getContractId());
                    logisticInfo.setContractNo(d.getContractNo());
                    logisticInfo.setContractName("");
                    logisticInfo.setAcceptCompanyId(d.getEntId());
                    logisticInfo.setAcceptContactPhone(d.getPhone());
                    logisticInfo.setAcceptContacts(d.getContacts());
                    logisticInfo.setAcceptContactsId(d.getContactsId());
                    logisticInfo.setAcceptCompany(d.getFirmName());
                    logisticInfo.setPrice(d.getTransportPrice());
                    logisticInfo.setPriceType(0L);
                    logisticInfo.setAmount(kwoTradeOrder.getAmount());
                    logisticInfo.setAmountUnit(kwoTradeOrder.getUnit());
                    logisticInfo.setLoss(new BigDecimal("0"));
                    logisticInfo.setPayment(0L);
                    logisticInfo.setSigningWay(0);
                    logisticInfo.setLossUnit("");
                    logisticInfo.setRemark("");
                    logisticInfo.setType(0);

                    return logisticInfo;
                }).collect(Collectors.toList());
                addLogisticOrderParam.setLogisticInfo(collect);
            }

        }
        addLogisticOrderParam.setTradeOrderId(kwoTradeOrder.getId());
        addLogisticOrderParam.setTradeOrderNo(kwoTradeOrder.getTOrderNo());
        addLogisticOrderParam.setBillingMode(String.valueOf(kwoTradeOrder.getChargeType()));
        addLogisticOrderParam.setStartTime(DateUtils.dateToLocalDate(kwoTradeOrder.getStartTime()));
        addLogisticOrderParam.setEndTime(DateUtils.dateToLocalDate(kwoTradeOrder.getEndTime()));
        if (Objects.equals(tradeContractResDto.getConsignment(), 1)) {//买方托运
            KwoTradeOrderUnit kwoTradeOrderUnit = unitMap.get("1");//买方
            if (Objects.nonNull(kwoTradeOrderUnit)) {
                addLogisticOrderParam.setConsignCompany(kwoTradeOrderUnit.getFirmName());
                addLogisticOrderParam.setConsignCompanyId(kwoTradeOrderUnit.getEntId());
                addLogisticOrderParam.setConsignContactPhone(kwoTradeOrderUnit.getPhone());
                addLogisticOrderParam.setConsignContacts(kwoTradeOrderUnit.getContacts());
                addLogisticOrderParam.setConsignContactsId(kwoTradeOrderUnit.getContactsId());
            }
            KwoTradeOrderUnit kwoTradeOrderUnit2 = unitMap.get("2");//卖方
            if (Objects.nonNull(kwoTradeOrderUnit2)) {
                addLogisticOrderParam.setNonConsignCompany(kwoTradeOrderUnit2.getFirmName());
                addLogisticOrderParam.setNonConsignCompanyId(kwoTradeOrderUnit2.getEntId());
                addLogisticOrderParam.setNonConsignContactPhone(kwoTradeOrderUnit2.getPhone());
                addLogisticOrderParam.setNonConsignContacts(kwoTradeOrderUnit2.getContacts());
                addLogisticOrderParam.setNonConsignContactsId(kwoTradeOrderUnit2.getContactsId());
            }

        } else {
            KwoTradeOrderUnit kwoTradeOrderUnit = unitMap.get("2");//卖方
            if (Objects.nonNull(kwoTradeOrderUnit)) {
                addLogisticOrderParam.setConsignCompany(kwoTradeOrderUnit.getFirmName());
                addLogisticOrderParam.setConsignCompanyId(kwoTradeOrderUnit.getEntId());
                addLogisticOrderParam.setConsignContactPhone(kwoTradeOrderUnit.getPhone());
                addLogisticOrderParam.setConsignContacts(kwoTradeOrderUnit.getContacts());
                addLogisticOrderParam.setConsignContactsId(kwoTradeOrderUnit.getContactsId());
            }
            KwoTradeOrderUnit kwoTradeOrderUnit2 = unitMap.get("1");//买方
            if (Objects.nonNull(kwoTradeOrderUnit2)) {
                addLogisticOrderParam.setNonConsignCompany(kwoTradeOrderUnit2.getFirmName());
                addLogisticOrderParam.setNonConsignCompanyId(kwoTradeOrderUnit2.getEntId());
                addLogisticOrderParam.setNonConsignContactPhone(kwoTradeOrderUnit2.getPhone());
                addLogisticOrderParam.setNonConsignContacts(kwoTradeOrderUnit2.getContacts());
                addLogisticOrderParam.setNonConsignContactsId(kwoTradeOrderUnit2.getContactsId());
            }
        }

        addLogisticOrderParam.setGoodsId(byOrderId.getGoodsId());
        addLogisticOrderParam.setGoodsName(byOrderId.getGoodsName());
        addLogisticOrderParam.setGoodsType(byOrderId.getGoodsType());
        addLogisticOrderParam.setGoodsPrice(byOrderId.getUnitPrice());
        Map<String, String> map = dict.get(DictTypeEnum.UNIT_TYPE.getType());
        if (CollUtil.isNotEmpty(map)) {
            addLogisticOrderParam.setGoodsUnit(map.get(byOrderId.getUnit()));
        }
        addLogisticOrderParam.setGoodsPriceUnit(byOrderId.getUnit());
        List<KwoTradeOrderAddress> kwoTradeOrderAddresses = addressMap.get(String.valueOf(AddressTypeEnum.SHIPMENT.getCode()));
        KwoTradeOrderAddress kwoTradeOrderAddress = kwoTradeOrderAddresses.get(0);
        if (Objects.nonNull(kwoTradeOrderAddress)) {
            addLogisticOrderParam.setLoadName(kwoTradeOrderAddress.getName());
            addLogisticOrderParam.setLoadCityCode(kwoTradeOrderAddress.getCityCode());
            addLogisticOrderParam.setLoadCityName(kwoTradeOrderAddress.getCityName());
            addLogisticOrderParam.setLoadContacts(kwoTradeOrderAddress.getContacts());
            addLogisticOrderParam.setLoadPhone(kwoTradeOrderAddress.getPhone());
            addLogisticOrderParam.setLoadDetailAddress(kwoTradeOrderAddress.getDetailAddress());
            addLogisticOrderParam.setLoadLat(kwoTradeOrderAddress.getLat());
            addLogisticOrderParam.setLoadLng(kwoTradeOrderAddress.getLng());
        }

        List<KwoTradeOrderAddress> kwoTradeOrderAddresses2 = addressMap.get(String.valueOf(AddressTypeEnum.TAKE.getCode()));
        KwoTradeOrderAddress unloadAddress = kwoTradeOrderAddresses2.get(0);
        if (Objects.nonNull(unloadAddress)) {
            addLogisticOrderParam.setUnloadId(unloadAddress.getId());
            addLogisticOrderParam.setUnloadName(unloadAddress.getName());
            addLogisticOrderParam.setUnloadCityCode(unloadAddress.getCityCode());
            addLogisticOrderParam.setUnloadCityName(unloadAddress.getCityName());
            addLogisticOrderParam.setUnLoadDetailAddress(unloadAddress.getDetailAddress());
            addLogisticOrderParam.setUnloadContacts(unloadAddress.getContacts());
            addLogisticOrderParam.setUnloadPhone(unloadAddress.getPhone());
            addLogisticOrderParam.setUnloadLng(unloadAddress.getLng());
            addLogisticOrderParam.setUnloadLat(unloadAddress.getLat());
        }
        addLogisticOrderParam.setEntId(LoginUserHolder.getEntId());
        addLogisticOrderParam.setUserId(LoginUserHolder.getUserId());
        addLogisticOrderParam.setMeasurementWay(tradeContractResDto.getMeasurementWay());
        log.info("创建物流订单：{}", JSONObject.toJSONString(addLogisticOrderParam));
        Integer result = transportRemoteService.addLogisticOrder(addLogisticOrderParam);
        //自动派单运力不足
        if (result == Global.YES) {
            kwoTradeOrder.setAddVehicles(Global.YES);
        }
        //更新贸易订单状态
        kwoTradeOrder.setStatus(Objects.equals(tradeOrderAuditParam.getStatus(), 2) ? TradeOrderStatusEnum.BACK.getCode() : TradeOrderStatusEnum.ING.getCode());
        kwoTradeOrderMapper.updateById(kwoTradeOrder);
        return buildAuditServiceFeeBalanceResp(kwoTradeOrder, unitMap, null);
    }

    /**
     * 构建审核结果，返回采购方服务费余额
     */
    private TradeOrderAuditResp buildAuditServiceFeeBalanceResp(KwoTradeOrder order,
                                                                Map<String, KwoTradeOrderUnit> unitMap,
                                                                BigDecimal serviceFeeBalance) {
        TradeOrderAuditResp resp = new TradeOrderAuditResp();
        if (!Objects.equals(order.getApplyChargeStrategy(), Global.YES)) {
            return resp;
        }
        if (serviceFeeBalance != null) {
            resp.setServiceFeeBalance(serviceFeeBalance);
            return resp;
        }
        Long proEntId = unitMap.get(String.valueOf(1)).getEntId();
        Long supEntId = 551429255406292993L;
        resp.setServiceFeeBalance(resolveParkingWalletFeeFeignResult(
                parkingWalletFeeFeignService.queryServiceFeeBalance(proEntId, supEntId), "服务费余额查询"));
        return resp;
    }

    /**
     * 统一解析服务费 Feign 调用结果，避免调用点遗漏空响应、失败码和空数据判断。
     *
     * @param result        Feign 返回结果
     * @param operationName 业务操作名称
     * @param <T>           返回数据类型
     * @return Feign 响应数据
     */
    static <T> T resolveParkingWalletFeeFeignResult(BaseResult<T> result, String operationName) {
        if (result == null) {
            log.error("{}失败，服务费Feign响应为空", operationName);
            throw new BusinessException(operationName + "失败，服务费响应为空");
        }
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            log.error("{}失败，服务费Feign返回失败，code:{}，message:{}",
                    operationName, result.getCode(), result.getMessage());
            throw new BusinessException(operationName + "失败：" + result.getMessage());
        }
        if (result.getData() == null) {
            log.error("{}失败，服务费Feign返回数据为空，code:{}，message:{}",
                    operationName, result.getCode(), result.getMessage());
            throw new BusinessException(operationName + "失败，服务费返回数据为空");
        }
        return result.getData();
    }

    @NotNull
    private List<LogisticsEntDtoVO> checkAutoContractLogOrder(Map<String, KwoTradeOrderUnit> unitMap, KwoTradeOrderGoods byOrderId, TradeContractResDto tradeContractResDto) {
        KwoTradeOrderUnit tradeOrderUnit = unitMap.get(String.valueOf(Global.NUMERICAL_TWO));
        //查询满足自动派单的物流合同
        List<LogisticsEntDtoVO> contractLogisticsList = remoteContractService.queryAutoContractLogOrder(tradeOrderUnit.getEntId(), Lists.newArrayList(byOrderId.getId()));
        if (CollectionUtils.isEmpty(contractLogisticsList)) {
            throw new BusinessException("未找到该商品有效的自动派车物流合同，请先签订自动派车物流合同");
        }
        //填充运输单价
        for (LogisticsEntDtoVO vo : contractLogisticsList) {
            LogisticsGoodsDto dto = remoteContractService.queryLogGoodsByContractId(vo.getContractId(), byOrderId.getGoodsId());
            if (dto.getPrice() == null || dto.getPrice().compareTo(BigDecimal.ZERO) == 0) {
                vo.setTransportPrice(vo.getCommonPrice());
            } else {
                vo.setTransportPrice(dto.getPrice());
            }
        }
        return contractLogisticsList;
    }

    /**
     * 实际派车数
     *
     * @param tradeOrder
     * @param addressList
     * @return
     */
    public Integer getActualDisPatch(KwoTradeOrder tradeOrder, Map<String, KwoTradeOrderUnit> unitMap, List<KwoTradeOrderAddress> addressList) {
        //获取供应企业id
        KwoTradeOrderUnit tradeOrderUnit = unitMap.get(String.valueOf(Global.NUMERICAL_TWO));
        TruckDispatchCoefficientVO truckDispatchVO = remoteFleetService.findAutoTruckDispatchByEntId(tradeOrderUnit.getEntId());
        if (truckDispatchVO == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "未找到自动派车系数！");
        }
        ActualDisPatchDto dto = new ActualDisPatchDto();
        dto.setTradeOrderId(tradeOrder.getId());
        dto.setEntId(tradeOrderUnit.getEntId());
        dto.setStartTime(tradeOrder.getStartTime());
        dto.setEndTime(tradeOrder.getEndTime());
        dto.setAmount(tradeOrder.getAmount());
        //司机行为规则
        dto.setVehicleAvgLoad(truckDispatchVO.getVehicleAvgLoad());
        dto.setBufferCoefficient(truckDispatchVO.getBufferCoefficient());
        dto.setVehicleWorkHours(truckDispatchVO.getVehicleWorkHours());
        dto.setVehicleLoadingHours(truckDispatchVO.getVehicleLoadingHours());
        dto.setVehicleUnloadingHours(truckDispatchVO.getVehicleUnloadingHours());
        dto.setVehicleAvgSpeed(truckDispatchVO.getVehicleAvgSpeed());

        //查询贸易订单装卸货地址
        Map<Integer, KwoTradeOrderAddress> addressMap = addressList.stream().collect(Collectors.toMap(address -> StringUtils.isBlank(address.getAddressType()) ? 0 : Integer.valueOf(address.getAddressType()), Function.identity(), (x, y) -> x));
        KwoTradeOrderAddress shipmentAddress = addressMap.getOrDefault(AddressTypeEnum.SHIPMENT.getCode(), new KwoTradeOrderAddress());
        KwoTradeOrderAddress takeAddress = addressMap.getOrDefault(AddressTypeEnum.TAKE.getCode(), new KwoTradeOrderAddress());
        dto.setLon1(shipmentAddress.getLng());
        dto.setLat1(shipmentAddress.getLat());
        dto.setLon2(takeAddress.getLng());
        dto.setLat2(takeAddress.getLat());

        //查询实际派车数
        Integer actualDisPatch = remoteSystemService.getActualDisPatch(dto);
        if (actualDisPatch == null || actualDisPatch <= 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "实际派车数量需大于0！");
        }
        return actualDisPatch;
    }

    /**
     * 手动完结订单
     *
     * @param tradeOrderSettleParam
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Object settleOrder(TradeOrderSettleParam tradeOrderSettleParam) {
        log.info("手动完结订单开始：{}", tradeOrderSettleParam);
        KwoTradeOrder kwoTradeOrder = new KwoTradeOrder();
        KwoTradeOrder kwoTradeOrderDB = kwoTradeOrderMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrder>().eq(KwoTradeOrder::getId, tradeOrderSettleParam.getId()).eq(KwoTradeOrder::getDelFlag, 0));
        List<KwtLogisticsOrderVO> logisticOrderList = transportRemoteService.getLogisticOrderList(new OrderFinishParam(tradeOrderSettleParam.getId()));
        if (CollUtil.isNotEmpty(logisticOrderList)) {
            if (logisticOrderList.stream().allMatch(d -> Objects.equals(d.getStatus(), LogisticsOrderV1Enum.COMPLETED.getCode()))) {
                log.info("手动完结订单，所有运单已完成，订单ID:{}, 订单号:{}", kwoTradeOrderDB.getId(), kwoTradeOrderDB.getTOrderNo());
                kwoTradeOrder.setStatus(TradeOrderStatusEnum.SUCCESS.getCode());
                // 预付钱包完结：解冻 + 按实际装/卸货量消费
                calculatePrepaidBalance(kwoTradeOrderDB);
            } else {
                log.info("手动完结订单，部分运单未完成，订单ID:{}, 订单号:{}", kwoTradeOrderDB.getId(), kwoTradeOrderDB.getTOrderNo());
                kwoTradeOrder.setStatus(TradeOrderStatusEnum.DEAL.getCode());
            }
        } else {
            log.info("手动完结订单，未找到运单，订单ID:{}, 订单号:{}", kwoTradeOrderDB.getId(), kwoTradeOrderDB.getTOrderNo());
            kwoTradeOrder.setStatus(TradeOrderStatusEnum.DEAL.getCode());
        }
        kwoTradeOrder.setId(tradeOrderSettleParam.getId());
        kwoTradeOrder.setUpdateBy(LoginUserHolder.getUserId());
        kwoTradeOrder.setUpdateTime(new Date());
        //通知下游，贸易订单已完结，或处于完结中。
        try {
            transportRemoteService.logisticOrderFinish(new OrderFinishParam(tradeOrderSettleParam.getId()));
        } catch (BusinessException e) {
            if (StrUtil.equals(e.getMsg(), "未找到该物流订单信息")) {
                kwoTradeOrder.setUnloadAmount(new BigDecimal("0"));
                kwoTradeOrder.setLoadAmount(new BigDecimal("0"));
            }
        }
        try {
            settleChargeStrategyAfterLogisticOrderFinish(tradeOrderSettleParam.getId());
        } catch (Exception e) {
            log.error("贸易订单完结后服务费结算失败，订单ID:{}, 订单号:{}, 异常信息:{}",kwoTradeOrder.getId(), kwoTradeOrder.getTOrderNo(), e.getMessage(), e);
        }
        kwoTradeOrderMapper.updateById(kwoTradeOrder);
        return true;
    }

    /**
     * 物流订单完结后统一处理服务费结算。
     * <p>
     * 所有调用 TransportRemoteService.logisticOrderFinish 的场景，均应调用此方法。
     * 方法内部重新查询订单和运单状态，确保仅在所有运单完成且订单应用收费策略时，
     * 执行服务费解冻、扣减并记录钱包变动明细。
     *
     * @param tradeOrderId 贸易订单ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void settleChargeStrategyAfterLogisticOrderFinish(Long tradeOrderId) {
        log.info("物流订单完结后服务费结算开始，订单ID:{}", tradeOrderId);
        if (tradeOrderId == null) {
            log.warn("物流订单完结后服务费结算跳过，订单ID为空");
            return;
        }
        KwoTradeOrder order = kwoTradeOrderMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrder>()
                .eq(KwoTradeOrder::getId, tradeOrderId)
                .eq(KwoTradeOrder::getDelFlag, Global.UN_DELETED));
        if (order == null) {
            log.warn("物流订单完结后服务费结算跳过，未找到贸易订单，订单ID:{}", tradeOrderId);
            return;
        }
        List<KwtLogisticsOrderVO> logisticOrderList;
        try {
            logisticOrderList = transportRemoteService.getLogisticOrderList(new OrderFinishParam(tradeOrderId));
        } catch (Exception e) {
            log.error("物流订单完结后查询运单列表失败，订单ID:{}, 订单号:{}",
                    order.getId(), order.getTOrderNo(), e);
            throw new BusinessException("物流订单完结后查询运单列表失败");
        }
        if (!hasAllLogisticsOrdersCompleted(logisticOrderList)) {
            log.info("物流订单尚未全部完成，服务费结算跳过，订单ID:{}, 订单号:{}, 运单数量:{}",
                    order.getId(), order.getTOrderNo(), CollUtil.size(logisticOrderList));
            return;
        }
        settleChargeStrategyIfApplied(order, logisticOrderList);
    }

    /**
     * 判断贸易订单下是否存在运单且所有运单均已完成。
     *
     * @param logisticOrderList 物流订单列表
     * @return true-所有运单完成；false-无运单或存在未完成运单
     */
    static boolean hasAllLogisticsOrdersCompleted(List<KwtLogisticsOrderVO> logisticOrderList) {
        return CollUtil.isNotEmpty(logisticOrderList)
                && logisticOrderList.stream()
                .allMatch(order -> order != null
                        && Objects.equals(order.getStatus(), LogisticsOrderV1Enum.COMPLETED.getCode()));
    }

    /**
     * 贸易订单完结时，处理收费策略关联的服务费结算
     * <p>
     * 触发条件：所有运单完成且订单 applyChargeStrategy=1（下单时已冻结服务费）。
     * 运输净重量：汇总已完成运单子任务的装/卸货净重（与看板运单完成量统计口径一致）。
     * 扣减逻辑：运输净重量 × 订单下单时快照的收费策略单价（无快照时回退当前策略）
     *
     * @param order             贸易订单
     * @param logisticOrderList 关联物流单列表（用于日志，净重量以运单统计为准）
     */
    private void settleChargeStrategyIfApplied(KwoTradeOrder order, List<KwtLogisticsOrderVO> logisticOrderList) {
        if (!Objects.equals(order.getApplyChargeStrategy(), Global.YES)) {
            log.info("贸易订单未应用收费策略，跳过服务费结算，订单ID:{}, 订单号:{}, 是否应用收费策略:{}",
                    order.getId(), order.getTOrderNo(), order.getApplyChargeStrategy());
            return;
        }
        log.info("贸易订单已应用收费策略，开始准备服务费结算，订单ID:{}, 订单号:{}, 收费策略ID:{}, 计费方式:{}",
                order.getId(), order.getTOrderNo(), order.getChargeStrategyId(), order.getChargeType());

        List<KwoTradeOrderUnit> orderUnits = kwoTradeOrderUnitService.getByOrderId(order.getId());
        if (CollUtil.isEmpty(orderUnits)) {
            log.error("贸易订单企业信息不存在，无法结算服务费，订单ID:{}, 订单号:{}", order.getId(), order.getTOrderNo());
            throw new BusinessException("贸易订单企业信息不存在");
        }
        Map<String, KwoTradeOrderUnit> unitMap = orderUnits.stream()
                .collect(Collectors.toMap(KwoTradeOrderUnit::getUnitType, e -> e, (a, b) -> a));
        if (unitMap.size() < 2) {
            log.error("贸易订单企业信息缺失，无法结算服务费，订单ID:{}, 订单号:{}, 企业数量:{}",
                    order.getId(), order.getTOrderNo(), unitMap.size());
            throw new BusinessException("贸易订单企业信息缺失");
        }

        // 运输净重量：汇总已完成运单的装/卸货净重（chargeType=1装货净重，=2卸货净重）
        BigDecimal transportNetWeight = queryTransportNetWeight(order);
        log.info("运输净重量汇总完成，订单号:{}, 计费方式:{}, 运输净重量:{}, 物流订单数量:{}",
                order.getTOrderNo(), order.getChargeType(), transportNetWeight, logisticOrderList.size());

        Long proEntId = unitMap.get(String.valueOf(1)).getEntId();
        Long supEntId = unitMap.get(String.valueOf(2)).getEntId();
        ParkingWalletFeeFreezeParam settleParam = new ParkingWalletFeeFreezeParam();
        settleParam.setOrderNo(order.getTOrderNo());
        settleParam.setProEntId(proEntId);
        settleParam.setSupEntId(551429255406292993L);
        settleParam.setActualQuantity(transportNetWeight);
        settleParam.setChargeStrategyId(order.getChargeStrategyId());
        settleParam.setChargeStrategyAmount(order.getChargeStrategyAmount());
        settleParam.setOperatorId(LoginUserHolder.getUserId());
        log.info("调用服务费完结结算，订单号:{}, 采购方企业ID:{}, 供应商企业ID:{}, 运输净重量:{}, 收费策略ID:{}, 快照单价:{}, 操作人ID:{}",
                order.getTOrderNo(), proEntId, supEntId, transportNetWeight, order.getChargeStrategyId(),
                order.getChargeStrategyAmount(), settleParam.getOperatorId());

        ParkingWalletFeeFreezeResult settleResult = resolveParkingWalletFeeFeignResult(
                parkingWalletFeeFeignService.settleChargeStrategy(settleParam), "服务费完结结算");
        log.info("服务费完结结算完成，订单号:{}, 扣减金额:{}, 收费策略ID:{}, 收费策略描述:{}, 扣减后服务费余额:{}",
                order.getTOrderNo(), settleResult.getFreezeAmount(), settleResult.getChargeStrategyId(),
                settleResult.getChargeStrategyDesc(), settleResult.getServiceFeeBalance());
    }

    /**
     * 查询贸易订单运输净重量（已完成运单装/卸货净重之和）
     */
    private BigDecimal queryTransportNetWeight(KwoTradeOrder order) {
        try {
            return Optional.ofNullable(transportRemoteStatisticsService.sumCompletedWaybillVolumeByTimeRange(order.getId(), order.getChargeType()))
                    .orElse(BigDecimal.ZERO);
        } catch (Exception e) {
            log.error("查询贸易订单运输净重量失败，订单ID:{}, 订单号:{}, 计费方式:{}",
                    order.getId(), order.getTOrderNo(), order.getChargeType(), e);
            throw new BusinessException("查询贸易订单运输净重量失败");
        }
    }

    private void calculatePrepaidBalance(KwoTradeOrder kwoTradeOrder) {
        //贸易订单已完结，计算预付余额
        if (Objects.equals(kwoTradeOrder.getSettlement(), 1)) {
            //todo 普通结算

        } else if (Objects.equals(kwoTradeOrder.getSettlement(), 2)) {
            //预付制模式
            //1解冻运费
            List<KwoTradeOrderUnit> orderUnits = kwoTradeOrderUnitService.getByOrderId(kwoTradeOrder.getId());
            if (CollUtil.isEmpty(orderUnits)) {
                throw new BusinessException("贸易订单企业信息不存在");
            }
            Map<String, KwoTradeOrderUnit> unitMap = orderUnits.stream().collect(Collectors.toMap(KwoTradeOrderUnit::getUnitType, e -> e, (a, b) -> a));
            if (unitMap.keySet().size() < 2) {
                throw new BusinessException("贸易订单企业信息缺失");
            }
            //钱包退回金额
            WalletPrepaidDto unFreezePrepaidDto = new WalletPrepaidDto();
            unFreezePrepaidDto.setOrderNo(kwoTradeOrder.getTOrderNo());
            unFreezePrepaidDto.setProEntId(unitMap.get(String.valueOf(1)).getEntId());
            unFreezePrepaidDto.setSupEntId(unitMap.get(String.valueOf(2)).getEntId());
            unFreezePrepaidDto.setOrderType(4);
            unFreezePrepaidDto.setTradeType(5);
            unFreezePrepaidDto.setRemark("贸易订单：" + unFreezePrepaidDto.getOrderNo() + ",");
            log.info("贸易订单号：{}，订单完结调用钱包服务解冻预付余额，参数：{}", unFreezePrepaidDto.getOrderNo(), JSON.toJSONString(unFreezePrepaidDto));
            BaseResult<Object> unFreezeResult = new BaseResult<>();
            try {
                unFreezeResult = paymentFeignService.updatePrepaidBalance(unFreezePrepaidDto);
            } catch (Exception e) {
                log.error("订单完结调用钱包服务解冻预付余额异常 {}", e.getMessage());
            }
            if (unFreezeResult.getCode() != HttpStatus.SUCCESS_CODE) {
                log.error("贸易订单号：{}，订单完结解冻失败,异常信息为：{}", unFreezePrepaidDto.getOrderNo(), unFreezeResult.getMessage());
                throw new BusinessException("贸易订单号：" + unFreezePrepaidDto.getOrderNo() + "，订单完结解冻失败");
            }
            KwoTradeOrderGoods kwoTradeOrderGoods = kwoTradeOrderGoodsMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrderGoods>()
                    .eq(KwoTradeOrderGoods::getDelFlag, 0)
                    .eq(KwoTradeOrderGoods::getTOrderId, kwoTradeOrder.getId())
                    .last("limit 1")
            );
            //2计算订单金额
            WalletPrepaidDto consumePrepaidDto = new WalletPrepaidDto();
            consumePrepaidDto.setOrderNo(kwoTradeOrder.getTOrderNo());
            consumePrepaidDto.setProEntId(unitMap.get(String.valueOf(1)).getEntId());
            consumePrepaidDto.setSupEntId(unitMap.get(String.valueOf(2)).getEntId());
            consumePrepaidDto.setOrderType(4);
            consumePrepaidDto.setTradeType(6);
            if (Objects.equals(kwoTradeOrder.getChargeType(), 1)) {
                consumePrepaidDto.setTradeAmount(NumberUtil.mul(kwoTradeOrder.getLoadAmount(), kwoTradeOrderGoods.getUnitPrice()));
            } else {
                consumePrepaidDto.setTradeAmount(NumberUtil.mul(kwoTradeOrder.getUnloadAmount(), kwoTradeOrderGoods.getUnitPrice()));
            }
            consumePrepaidDto.setRemark("贸易订单号：" + consumePrepaidDto.getOrderNo() + "，订单完结消费");
            log.info("贸易订单号：{}，订单完结调用钱包服务消费预付余额，参数：{}", consumePrepaidDto.getOrderNo(), JSON.toJSONString(consumePrepaidDto));
            BaseResult<Object> consumeResult = new BaseResult<>();
            try {
                consumeResult = paymentFeignService.updatePrepaidBalance(consumePrepaidDto);
            } catch (Exception e) {
                log.error("订单完结调用钱包服务消费预付余额异常 {}", e.getMessage());
            }
            if (consumeResult.getCode() != HttpStatus.SUCCESS_CODE) {
                log.error("贸易订单号：{}，订单完结消费失败,异常信息为：{}", consumePrepaidDto.getOrderNo(), consumeResult.getMessage());
                throw new BusinessException("贸易订单号：" + consumePrepaidDto.getOrderNo() + "，订单完结消费失败");
            }
        }

    }

    public void updateOrderAmount(TradeOrderSettlePara tradeOrderSettlePara) {
        if (Objects.isNull(tradeOrderSettlePara.getTOrderId())) {
            throw new BusinessException("订单id不能为空");
        }
        KwoTradeOrder kwoTradeOrder = kwoTradeOrderMapper.selectById(tradeOrderSettlePara.getTOrderId());
        KwoTradeOrder kwoTradeOrder1 = new KwoTradeOrder();
        kwoTradeOrder1.setId(kwoTradeOrder.getId());
        if (Objects.nonNull(tradeOrderSettlePara.getLoadAmount())) {
            kwoTradeOrder1.setLoadAmount(NumberUtil.add(tradeOrderSettlePara.getLoadAmount(), kwoTradeOrder.getLoadAmount()));
        }
        if (Objects.nonNull(tradeOrderSettlePara.getUnloadAmount())) {
            kwoTradeOrder1.setUnloadAmount(NumberUtil.add(tradeOrderSettlePara.getUnloadAmount(), kwoTradeOrder.getUnloadAmount()));
        }

        kwoTradeOrderMapper.updateById(kwoTradeOrder1);
    }

    public List<TradeOrderVo> queryOrder(TradeOrderPara tradeOrderPara) {
        UserResDto userResDto = remoteSystemService.queryUserById(tradeOrderPara.getUserId());
        if (Objects.nonNull(userResDto)) {
            Integer systemType = userResDto.getSystemType();
            tradeOrderPara.setType(userResDto.getType());
            if (!Objects.equals(systemType, SystemTypeEnum.MANAGE.getCode())) {
                tradeOrderPara.setEntId(remoteUserService.findChildEntList(userResDto.getEntId()));
            }
        }
        List<TradeOrderVo> tradeOrderVos = kwoTradeOrderMapper.selectData(tradeOrderPara);
        if (CollUtil.isNotEmpty(tradeOrderVos)) {
            Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.UNIT_TYPE.getType(), DictTypeEnum.CHARGING_TYPE.getType(), DictTypeEnum.TORDER_STATUS.getType()));
            Map<String, String> statusMap, productNameMap, unitMap, chargeTypeMap;
            if (CollUtil.isNotEmpty(dict)) {
                statusMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_STATUS.getType())) ? dict.get(DictTypeEnum.TORDER_STATUS.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
                productNameMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType())) ? dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
                unitMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.UNIT_TYPE.getType())) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
                chargeTypeMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.CHARGING_TYPE.getType())) ? dict.get(DictTypeEnum.CHARGING_TYPE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
            } else {
                statusMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
                productNameMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
                unitMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
                chargeTypeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            }
            tradeOrderVos.forEach(d -> {
                d.setMoreUrl("/#/orderManagement/tradeOrder/list");
                d.setTOrderNoUrl(new OrderUrl(d.getTOrderNo(), "/#/orderManagement/tradeOrder/detail/" + d.getTOrderId()));
                d.setStatusLabel(statusMap.get(String.valueOf(d.getStatus())));
                d.setGoodsTypeLabel(productNameMap.get(d.getGoodsType()));
                d.setChargeTypeLabel(chargeTypeMap.get(String.valueOf(d.getChargeType())));
                d.setUnitLabel(unitMap.get(String.valueOf(d.getUnit())));
            });
            return tradeOrderVos;
        }
        return new ArrayList<>();
    }


    /**
     * 获取贸易订单及原矿物流订单的执行展示列表。
     * 主要用于公共BI大屏展示，包含特定企业的贸易订单执行进度和原矿物流订单执行情况。
     *
     * @return 订单执行展示数据列表
     */
    public List<OrderExecutionDisplayVo> listOrderExecutionDisplay() {
        log.info("开始查询订单执行展示数据");

        // 1. 查询原矿物流订单执行数据
//        List<OrderExecutionDisplayVo> rawOreRows = buildRawOreOrderExecutionDisplayRows(ORDER_EXECUTION_DISPLAY_LIMIT);
//        log.debug("查询到原矿物流订单执行数据条数: {}", rawOreRows.size());

        // 2. 查询指定报表企业范围内的贸易订单ID
        List<Long> reportTradeOrderIds = queryReportTradeOrderIds();
        if (CollectionUtils.isEmpty(reportTradeOrderIds)) {
            log.info("未找到指定报表企业的贸易订单ID");
            return List.of();
        }
        log.info("找到指定报表企业的贸易订单ID数量: {}", reportTradeOrderIds.size());

        // 3. 查询符合条件的贸易订单列表
        // 条件：未删除、在指定ID范围内、状态为待审核/进行中/结算中、按更新时间倒序、限制数量
        List<KwoTradeOrder> orders = kwoTradeOrderMapper.selectList(
                Wrappers.<KwoTradeOrder>lambdaQuery()
                        .eq(KwoTradeOrder::getDelFlag, Global.NO)
                        .in(CollectionUtils.isNotEmpty(reportTradeOrderIds), KwoTradeOrder::getId, reportTradeOrderIds)
                        .in(KwoTradeOrder::getStatus, Arrays.asList(
                                TradeOrderStatusEnum.AUDIT.getCode(),
                                TradeOrderStatusEnum.ING.getCode(),
                                TradeOrderStatusEnum.DEAL.getCode()))
                        .orderByDesc(KwoTradeOrder::getUpdateTime)
                        .last("LIMIT " + ORDER_EXECUTION_DISPLAY_LIMIT));

        if (CollectionUtils.isEmpty(orders)) {
            log.info("未查询到符合条件的贸易订单，仅返回原矿物流订单数据");
            return List.of();
        }
        log.info("查询到符合条件的贸易订单数量: {}", orders.size());

        // 4. 批量查询贸易订单关联的运单统计信息（已完成运单的趟次、净重等）
        List<Long> orderIds = orders.stream().map(KwoTradeOrder::getId).toList();
        log.debug("开始批量查询贸易订单运单统计信息，订单ID数量: {}", orderIds.size());
        List<TradeOrderWaybillAggDto> aggs = transportRemoteService.aggregateCompletedWaybillStatsByTradeOrderIds(orderIds);
        log.debug("查询到贸易订单运单统计信息数量: {}", aggs != null ? aggs.size() : 0);

        // 5. 将运单统计信息转换为Map，以便通过订单ID快速查找
        Map<Long, TradeOrderWaybillAggDto> aggMap = aggs != null ? aggs.stream()
                .collect(Collectors.toMap(TradeOrderWaybillAggDto::getTOrderId, Function.identity(), (a, b) -> a))
                : Collections.emptyMap();

        // 6. 组装贸易订单执行展示数据
        List<OrderExecutionDisplayVo> rows = new ArrayList<>(orders.size());
        for (KwoTradeOrder order : orders) {
            TradeOrderWaybillAggDto agg = aggMap.get(order.getId());

            // 获取运输趟次，若无数据则默认为0
            int trips = (agg != null && agg.getTripCount() != null) ? agg.getTripCount() : 0;

            // 获取已装载净重总和，若无数据则默认为0
            BigDecimal loadedWeight = (agg != null && agg.getNetWeightSum() != null) ? agg.getNetWeightSum() : BigDecimal.ZERO;

            // 获取订单计划总量，若无数据则默认为0
            BigDecimal plannedAmount = (order.getAmount() != null) ? order.getAmount() : BigDecimal.ZERO;

            // 计算计划吨数（取整，至少为0）
            int plannedTons = Math.max(0, plannedAmount.setScale(0, RoundingMode.HALF_UP).intValue());

            // 计算已装载吨数（保留两位小数）
            BigDecimal loadedTons = loadedWeight.setScale(2, RoundingMode.HALF_UP);

            // 计算完成率百分比
            BigDecimal completionRate;
            if (plannedAmount.compareTo(BigDecimal.ZERO) <= 0) {
                // 如果计划量为0或负数，防止除以零错误，完成率设为0
                completionRate = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
            } else {
                // 完成率 = (已装载量 / 计划量) * 100，中间计算保留10位精度，最终结果保留2位小数
                completionRate = loadedWeight.divide(plannedAmount, 10, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .setScale(2, RoundingMode.HALF_UP);
            }

            // 构建返回对象
            OrderExecutionDisplayVo vo = new OrderExecutionDisplayVo();
            vo.setOrderNo(order.getTOrderNo());
            vo.setPlannedTons(plannedTons);
            vo.setLoadedTons(loadedTons);
            vo.setTripCount(trips);
            vo.setCompletionRatePercent(completionRate);
            rows.add(vo);
        }

        // 7. 将原矿物流订单数据追加到列表末尾(原矿的数据已经取消)
        log.info("订单执行展示数据组装完成，贸易订单数: {}, 总数: {}",
                orders.size(), rows.size());
        return rows;
    }
    /**
     * 查询属于公共BI大屏固定企业范围的贸易订单ID列表。
     * <p>
     * 该方法通过查询 {@link KwoTradeOrderUnitRepository} 获取指定企业ID列表（{@link #REPORT_ENT_IDS}）
     * 关联的贸易订单单位信息，并提取出唯一的贸易订单ID集合。
     * </p>
     *
     * @return 贸易订单ID列表，若无匹配数据则返回空列表
     */
    private List<Long> queryReportTradeOrderIds() {
        log.debug("开始查询公共BI大屏固定企业范围的贸易订单ID，目标企业IDs: {}", REPORT_ENT_IDS);
        
        // 1. 根据固定企业ID列表查询关联的贸易订单单位信息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitRepository.queryByReportEntIds(REPORT_ENT_IDS);
        
        // 2. 若未查询到任何单位信息，直接返回空列表
        if (CollectionUtils.isEmpty(units)) {
            log.debug("未查询到固定企业范围内的贸易订单单位信息");
            return Collections.emptyList();
        }
        
        log.debug("查询到贸易订单单位信息数量: {}", units.size());

        // 3. 流式处理：过滤空对象 -> 提取订单ID -> 过滤空ID -> 去重 -> 转换为List
        List<Long> orderIds = units.stream()
                .filter(Objects::nonNull)
                .map(KwoTradeOrderUnit::getTOrderId)
                .filter(Objects::nonNull)
                .distinct()
                .toList();
        
        log.debug("最终获取到的唯一贸易订单ID数量: {}", orderIds.size());
        return orderIds;
    }

    /**
     * 构建原矿物流订单执行展示数据列表。
     * <p>
     * 该方法调用远程运输服务，获取指定企业范围（{@link #REPORT_ENT_IDS}）内的原矿物流订单执行数据，
     * 并将其转换为前端展示所需的 {@link OrderExecutionDisplayVo} 对象列表。
     * </p>
     *
     * @param limit 查询数量限制，用于控制返回的数据条数
     * @return 原矿物流订单执行展示数据列表；若查询失败或无数据，则返回空列表
     */
    private List<OrderExecutionDisplayVo> buildRawOreOrderExecutionDisplayRows(int limit) {
        log.info("开始构建原矿物流订单执行展示数据，限制数量: {}", limit);
        try {
            // 1. 调用远程服务查询原矿物流订单执行数据
            log.debug("调用远程运输服务查询原矿物流订单，企业IDs: {}, 限制数量: {}", REPORT_ENT_IDS, limit);
            List<RawOreOrderExecutionDto> rawOreRows = transportRemoteService.listRawOreOrderExecutionDisplay(REPORT_ENT_IDS, limit);

            // 2. 判空处理：若无数据，直接返回空列表
            if (CollectionUtils.isEmpty(rawOreRows)) {
                log.info("未查询到原矿物流订单执行数据");
                return Collections.emptyList();
            }
            log.debug("查询到原矿物流订单原始数据条数: {}", rawOreRows.size());

            // 3. 数据转换：将 DTO 转换为 VO
            List<OrderExecutionDisplayVo> result = rawOreRows.stream()
                    .map(this::buildRawOreOrderExecutionDisplayVo)
                    .toList();
            
            log.info("原矿物流订单执行展示数据构建完成，最终返回条数: {}", result.size());
            return result;
        } catch (Exception e) {
            // 4. 异常处理：记录错误日志并返回空列表，避免影响主流程（如贸易订单数据的展示）
            log.error("构建原矿物流订单执行展示数据失败", e);
            return Collections.emptyList();
        }
    }

    /**
     * 构建原矿物流订单执行展示视图对象。
     * <p>
     * 该方法将远程服务返回的原矿物流订单执行数据 DTO 转换为前端展示所需的 VO 对象。
     * 主要包含以下逻辑：
     * 1. 处理空值：将计划量和已装载量中的 null 值转换为 BigDecimal.ZERO。
     * 2. 计算完成率：避免除以零错误，保留两位小数。
     * 3. 数据格式化：计划吨数取整，已装载吨数保留两位小数，趟次处理 null 值。
     * </p>
     *
     * @param row 原矿物流订单执行数据 DTO
     * @return 原矿物流订单执行展示视图对象
     */
    private OrderExecutionDisplayVo buildRawOreOrderExecutionDisplayVo(RawOreOrderExecutionDto row) {
        log.debug("开始构建原矿物流订单执行展示VO，物流单号: {}", row != null ? row.getLogisticsOrderNo() : "null");

        // 1. 获取并处理计划量，防止空指针
        BigDecimal plannedRaw = row.getPlannedAmount() != null ? row.getPlannedAmount() : BigDecimal.ZERO;
        // 2. 获取并处理已装载净重总和，防止空指针
        BigDecimal loadedRaw = row.getNetWeightSum() != null ? row.getNetWeightSum() : BigDecimal.ZERO;

        // 3. 计算完成率百分比
        BigDecimal rate;
        if (plannedRaw.compareTo(BigDecimal.ZERO) <= 0) {
            // 如果计划量为0或负数，防止除以零，完成率设为0
            rate = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
            log.debug("物流单号: {} 计划量为0或负数，完成率设为0", row.getLogisticsOrderNo());
        } else {
            // 正常计算：(已装载量 / 计划量) * 100
            // 中间计算保留10位精度以确保准确性，最终结果保留2位小数
            rate = loadedRaw.divide(plannedRaw, 10, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP);
        }

        // 4. 组装返回对象
        OrderExecutionDisplayVo vo = new OrderExecutionDisplayVo();
        // 设置物流订单号
        vo.setOrderNo(row.getLogisticsOrderNo());
        // 设置计划吨数：四舍五入取整，且最小为0
        vo.setPlannedTons(Math.max(0, plannedRaw.setScale(0, RoundingMode.HALF_UP).intValue()));
        // 设置已装载吨数：保留两位小数
        vo.setLoadedTons(loadedRaw.setScale(2, RoundingMode.HALF_UP));
        // 设置运输趟次：若为null则默认为0
        vo.setTripCount(row.getTripCount() == null ? 0 : row.getTripCount());
        // 设置完成率百分比
        vo.setCompletionRatePercent(rate);

        log.debug("原矿物流订单执行展示VO构建完成，单号: {}, 计划吨: {}, 已装吨: {}, 趟次: {}, 完成率: {}%",
                vo.getOrderNo(), vo.getPlannedTons(), vo.getLoadedTons(), vo.getTripCount(), vo.getCompletionRatePercent());

        return vo;
    }

    public List<ContractLogisticsVO> queryAddContractList(ContractLogisticsQueryParam param) {
        KwoTradeOrder kwoTradeOrder = kwoTradeOrderMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrder>().eq(KwoTradeOrder::getId, param.getTradeOrderId()).eq(KwoTradeOrder::getDelFlag, 0));
        if (Objects.isNull(kwoTradeOrder)) {
            throw new BusinessException("贸易订单不存在");
        }
        if (!Objects.equals(TradeOrderStatusEnum.ING.getCode(), kwoTradeOrder.getStatus())) {
            throw new BusinessException("只有进行中的贸易订单可以增补运力");
        }
        //查询满足手动派单的物流合同
        List<LogisticsEntDtoVO> contractLogisticsList = remoteContractService.queryContractLogOrder(param.getSupEntId(), param.getGoodsId());
        if (CollectionUtils.isEmpty(contractLogisticsList)) {
            throw new BusinessException("未找到该商品有效的手动派车物流合同");
        }
        //查询贸易订单已经存在的物流合同
        List<LogisticContractVo> logisticContractVos = transportRemoteService.queryLogOrderCirculateByLogOrderId(param.getTradeOrderId());
        Set<Long> existingContractIds = logisticContractVos.stream().map(LogisticContractVo::getLogContractId).collect(Collectors.toSet());

        // 过滤掉contractLogisticsList中包含已存在合同ID的数据
        List<LogisticsEntDtoVO> filteredContractList = contractLogisticsList.stream()
                .filter(contract -> !existingContractIds.contains(contract.getContractId()))
                .collect(Collectors.toList());

        //填充运输单价
        for (LogisticsEntDtoVO vo : filteredContractList) {
            LogisticsGoodsDto dto = remoteContractService.queryLogGoodsByContractId(vo.getContractId(), param.getGoodsId());
            if (dto.getPrice() == null || dto.getPrice().compareTo(BigDecimal.ZERO) == 0) {
                vo.setTransportPrice(vo.getCommonPrice());
            } else {
                vo.setTransportPrice(dto.getPrice());
            }
        }
        List<ContractLogisticsVO> contractLogisticsVOS = new ArrayList<>();
        for (LogisticsEntDtoVO vo : filteredContractList) {
            ContractLogisticsVO logisticsVO = new ContractLogisticsVO();
            logisticsVO.setContractId(vo.getContractId());
            logisticsVO.setContractNo(vo.getContractNo());
            logisticsVO.setStartTime(vo.getStartTime());
            logisticsVO.setEndTime(vo.getEndTime());
            logisticsVO.setEntId(vo.getEntId());
            logisticsVO.setEntName(vo.getEntName());
            logisticsVO.setCommonPrice(vo.getCommonPrice());
            logisticsVO.setContactsId(vo.getContactsId());
            logisticsVO.setContacts(vo.getContacts());
            logisticsVO.setPhone(vo.getPhone());
            logisticsVO.setTransportPrice(vo.getTransportPrice());
            contractLogisticsVOS.add(logisticsVO);
        }
        return contractLogisticsVOS;
    }


    /**
     * 查询增补运力物流合同（手动派车物流合同）
     *
     * @param param
     * @return
     */
    public void addContractList(ContractLogisticsAddParam param) {
        KwoTradeOrder kwoTradeOrder = kwoTradeOrderMapper.selectOne(new LambdaQueryWrapper<KwoTradeOrder>().eq(KwoTradeOrder::getId, param.getTradeOrderId()).eq(KwoTradeOrder::getDelFlag, 0));
        if (Objects.isNull(kwoTradeOrder)) {
            throw new BusinessException("贸易订单不存在");
        }
        if (!Objects.equals(TradeOrderStatusEnum.ING.getCode(), kwoTradeOrder.getStatus())) {
            throw new BusinessException("只有进行中的贸易订单可以增补运力");
        }

        KwoTradeOrderGoods byOrderId = kwoTradeOrderGoodsService.getByOrderId(kwoTradeOrder.getId());
        if (Objects.isNull(byOrderId)) {
            throw new BusinessException("贸易订单关联商品信息不存在");
        }
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderId(kwoTradeOrder.getId());
        if (CollUtil.isEmpty(addressList)) {
            throw new BusinessException("贸易订单运输地址信息不存在");
        }
        Map<String, List<KwoTradeOrderAddress>> addressMap = addressList.stream().collect(Collectors.groupingBy(KwoTradeOrderAddress::getAddressType));
        if (CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.SHIPMENT.getCode()))) && CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.BOTH.getCode())))) {
            throw new BusinessException("装货地址信息不存在");
        }
        if (CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.TAKE.getCode()))) && CollUtil.isEmpty(addressMap.get(String.valueOf(AddressTypeEnum.BOTH.getCode())))) {
            throw new BusinessException("卸货地址信息不存在");
        }
        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(param.getTradeContractId(), param.getGoodsId());
        if (Objects.isNull(tradeContractResDto)) {
            throw new BusinessException("贸易合同不存在");
        }
        List<KwoTradeOrderUnit> orderUnits = kwoTradeOrderUnitService.getByOrderId(kwoTradeOrder.getId());
        if (CollUtil.isEmpty(orderUnits)) {
            throw new BusinessException("贸易订单企业信息不存在");
        }
        Map<String, KwoTradeOrderUnit> unitMap = orderUnits.stream().collect(Collectors.toMap(KwoTradeOrderUnit::getUnitType, e -> e, (a, b) -> a));
        if (unitMap.keySet().size() < 2) {
            throw new BusinessException("贸易订单企业信息缺失");
        }
        if (Objects.equals(tradeContractResDto.getConsignment(), 2)) {
            throw new BusinessException("增补运力必须为卖方托运");
        }
        List<LogisticsEntDto> logisticsContractList = param.getLogisticsContractList();
        if (CollUtil.isEmpty(logisticsContractList)) {
            throw new BusinessException("物流合同不能为空");
        }

        //创建贸易订单和物流合同关联关系
        for (LogisticsEntDto logisticsEntDto : logisticsContractList) {
            KwoTradeOrderTransport kwoTradeOrderTransport = new KwoTradeOrderTransport();
            kwoTradeOrderTransport.setId(new IdWorker(1).nextId());
            kwoTradeOrderTransport.setTOrderId(kwoTradeOrder.getId());
            kwoTradeOrderTransport.setTOrderNo(kwoTradeOrder.getTOrderNo());
            kwoTradeOrderTransport.setEntId(logisticsEntDto.getEntId());
            kwoTradeOrderTransport.setFirmName(logisticsEntDto.getEntName());
            kwoTradeOrderTransport.setContractId(logisticsEntDto.getContractId());
            kwoTradeOrderTransport.setContractNo(logisticsEntDto.getContractNo());
            kwoTradeOrderTransport.setTransportPrice(logisticsEntDto.getTransportPrice());
            kwoTradeOrderTransport.setContactsId(logisticsEntDto.getContactsId());
            kwoTradeOrderTransport.setContacts(logisticsEntDto.getContacts());
            kwoTradeOrderTransport.setPhone(logisticsEntDto.getPhone());
            kwoTradeOrderTransport.setRemark("");
            kwoTradeOrderTransport.setStatus(0);
            kwoTradeOrderTransport.setCreateBy(LoginUserHolder.getUserId());
            kwoTradeOrderTransport.setCreateTime(LocalDateTime.now());
            kwoTradeOrderTransportService.insert(kwoTradeOrderTransport);
        }

        //组装下游生成物流订单数据
        AddLogisticOrderParam addLogisticOrderParam = new AddLogisticOrderParam();
        List<LogisticInfo> collect = logisticsContractList.stream().map(d -> {
            LogisticInfo logisticInfo = new LogisticInfo();
            logisticInfo.setContractId(d.getContractId());
            logisticInfo.setContractNo(d.getContractNo());
            logisticInfo.setContractName("");
            logisticInfo.setAcceptCompanyId(d.getEntId());
            logisticInfo.setAcceptContactPhone("");
            logisticInfo.setAcceptContacts(d.getContacts());
            logisticInfo.setAcceptContactsId(d.getContactsId());
            logisticInfo.setAcceptCompany("");
            logisticInfo.setPrice(d.getTransportPrice());
            logisticInfo.setPriceType(0L);
            logisticInfo.setAmount(new BigDecimal("0"));
            logisticInfo.setAmountUnit("");
            logisticInfo.setLoss(new BigDecimal("0"));
            logisticInfo.setPayment(0L);
            logisticInfo.setSigningWay(0);
            logisticInfo.setLossUnit("");
            logisticInfo.setRemark("");
            logisticInfo.setType(0);

            return logisticInfo;
        }).collect(Collectors.toList());
        addLogisticOrderParam.setLogisticInfo(collect);
        addLogisticOrderParam.setTradeOrderId(kwoTradeOrder.getId());
        addLogisticOrderParam.setTradeOrderNo(kwoTradeOrder.getTOrderNo());
        addLogisticOrderParam.setBillingMode(String.valueOf(kwoTradeOrder.getChargeType()));
        addLogisticOrderParam.setStartTime(DateUtils.dateToLocalDate(kwoTradeOrder.getStartTime()));
        addLogisticOrderParam.setEndTime(DateUtils.dateToLocalDate(kwoTradeOrder.getEndTime()));

        KwoTradeOrderUnit kwoTradeOrderUnit = unitMap.get("2");//卖方
        if (Objects.nonNull(kwoTradeOrderUnit)) {
            addLogisticOrderParam.setConsignCompany(kwoTradeOrderUnit.getFirmName());
            addLogisticOrderParam.setConsignCompanyId(kwoTradeOrderUnit.getEntId());
            addLogisticOrderParam.setConsignContactPhone(kwoTradeOrderUnit.getPhone());
            addLogisticOrderParam.setConsignContacts(kwoTradeOrderUnit.getContacts());
            addLogisticOrderParam.setConsignContactsId(kwoTradeOrderUnit.getContactsId());
        }
        KwoTradeOrderUnit kwoTradeOrderUnit2 = unitMap.get("1");//买方
        if (Objects.nonNull(kwoTradeOrderUnit2)) {
            addLogisticOrderParam.setNonConsignCompany(kwoTradeOrderUnit2.getFirmName());
            addLogisticOrderParam.setNonConsignCompanyId(kwoTradeOrderUnit2.getEntId());
            addLogisticOrderParam.setNonConsignContactPhone(kwoTradeOrderUnit2.getPhone());
            addLogisticOrderParam.setNonConsignContacts(kwoTradeOrderUnit2.getContacts());
            addLogisticOrderParam.setNonConsignContactsId(kwoTradeOrderUnit2.getContactsId());
        }

        addLogisticOrderParam.setGoodsId(byOrderId.getGoodsId());
        addLogisticOrderParam.setGoodsName(byOrderId.getGoodsName());
        addLogisticOrderParam.setGoodsType(byOrderId.getGoodsType());
        addLogisticOrderParam.setGoodsPrice(byOrderId.getUnitPrice());
        addLogisticOrderParam.setGoodsPriceUnit(byOrderId.getUnit());
        List<KwoTradeOrderAddress> kwoTradeOrderAddresses = addressMap.get(String.valueOf(AddressTypeEnum.SHIPMENT.getCode()));
        KwoTradeOrderAddress kwoTradeOrderAddress = kwoTradeOrderAddresses.get(0);
        if (Objects.nonNull(kwoTradeOrderAddress)) {
            addLogisticOrderParam.setLoadName(kwoTradeOrderAddress.getName());
            addLogisticOrderParam.setLoadCityCode(kwoTradeOrderAddress.getCityCode());
            addLogisticOrderParam.setLoadCityName(kwoTradeOrderAddress.getCityName());
            addLogisticOrderParam.setLoadContacts(kwoTradeOrderAddress.getContacts());
            addLogisticOrderParam.setLoadPhone(kwoTradeOrderAddress.getPhone());
            addLogisticOrderParam.setLoadDetailAddress(kwoTradeOrderAddress.getDetailAddress());
            addLogisticOrderParam.setLoadLat(kwoTradeOrderAddress.getLat());
            addLogisticOrderParam.setLoadLng(kwoTradeOrderAddress.getLng());
        }

        List<KwoTradeOrderAddress> kwoTradeOrderAddresses2 = addressMap.get(String.valueOf(AddressTypeEnum.TAKE.getCode()));
        KwoTradeOrderAddress unloadAddress = kwoTradeOrderAddresses2.get(0);
        if (Objects.nonNull(unloadAddress)) {
            addLogisticOrderParam.setUnloadId(unloadAddress.getId());
            addLogisticOrderParam.setUnloadName(unloadAddress.getName());
            addLogisticOrderParam.setUnloadCityCode(unloadAddress.getCityCode());
            addLogisticOrderParam.setUnloadCityName(unloadAddress.getCityName());
            addLogisticOrderParam.setUnLoadDetailAddress(unloadAddress.getDetailAddress());
            addLogisticOrderParam.setUnloadContacts(unloadAddress.getContacts());
            addLogisticOrderParam.setUnloadPhone(unloadAddress.getPhone());
            addLogisticOrderParam.setUnloadLng(unloadAddress.getLng());
            addLogisticOrderParam.setUnloadLat(unloadAddress.getLat());
        }
        addLogisticOrderParam.setEntId(LoginUserHolder.getEntId());
        addLogisticOrderParam.setUserId(LoginUserHolder.getUserId());
        addLogisticOrderParam.setDispatchWay(DispatchWayEnums.MANUAL_DISPATCH.getCode());
        log.info("创建物流订单：{}", JSONObject.toJSONString(addLogisticOrderParam));
        transportRemoteService.addLogisticOrder(addLogisticOrderParam);

        //修改贸易订单增派运力是否满足
        kwoTradeOrder.setAddVehicles(Global.NO);
        kwoTradeOrderMapper.updateById(kwoTradeOrder);

    }

    public List<SaleTopVo> saleTop() {
        return kwoTradeOrderMapper.saleTop();
    }

    public BigDecimal saleSum() {
        return kwoTradeOrderMapper.saleSum();
    }

    public List<KwoTradeOrderArchiveVo> saleSummary() {
        return kwoTradeOrderArchiveMapper.summary();
    }
}
