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 com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
import com.sckw.contract.api.model.vo.GoodsInfoDto;
import com.sckw.contract.api.model.vo.TradeContractResDto;
import com.sckw.contract.api.model.vo.TradeContractUnitDto;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.exception.BusinessException;
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.HttpResult;
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.OrderSaleVo;
import com.sckw.order.api.model.TradeOrderCountStatisticsDTO;
import com.sckw.order.api.model.TradeOrderSettlePara;
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.req.*;
import com.sckw.order.model.vo.res.*;
import com.sckw.payment.api.dubbo.PayCenterDubboService;
import com.sckw.payment.api.dubbo.PaymentDubboService;
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.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.model.dto.res.*;
import com.sckw.transport.api.dubbo.TransportRemoteService;
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.vo.KwtLogisticsOrderVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
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.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 {

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

    @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;

    private final KwoTradeOrderMapper kwoTradeOrderMapper;
    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;

    @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);
        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));
                }
            }
            process.setStatusLabel(OrderStatusEnum.getMsg(process.getStatus()));
            orderProcesses.add(process);
        });
        detail.setOrderProcess(orderProcesses);
        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()));
        Map<String, String> tradeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        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> orderUnitMap, orderAddressMap, addressMap;
        if (CollUtil.isNotEmpty(dict)) {
            tradeMap = dict.get(DictTypeEnum.TRADE_TYPE.getType());
            pickupMap = dict.get(DictTypeEnum.PICKUP_TYPE.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());
        } 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());
        detail.setFirmName(Objects.isNull(ent) ? null : ent.getFirmName())
                .setCreateByName(Objects.isNull(createUser) ? null : createUser.getName())
                .setTradingLabel(CollUtil.isNotEmpty(tradeMap) ? tradeMap.get(detail.getTrading()) : null)
                .setPickupTypeLabel(CollUtil.isNotEmpty(pickupMap) ? pickupMap.get(detail.getPickupType()) : null)
                .setDeliveryTypeLabel(CollUtil.isNotEmpty(deleveryMap) ? deleveryMap.get(detail.getDeliveryType()) : null)
                .setSourceLabel(CollUtil.isNotEmpty(sourceMap) ? sourceMap.get(detail.getSource()) : null)
                .setStatusLabel(CollUtil.isNotEmpty(statusMap) ? statusMap.get(String.valueOf(detail.getStatus())) : null)
                .setChargeTypeLabel(CollUtil.isNotEmpty(chargeTypeMap) ? chargeTypeMap.get(String.valueOf(detail.getChargeType())) : null)
                .setConsignmentWayLabel(CollUtil.isNotEmpty(consignmentWayMap) ? consignmentWayMap.get(String.valueOf(detail.getConsignmentWay())) : null)
        ;
        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());
                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<GoodsUnitDetailRes> assistUnit = kwoTradeOrderGoodsUnitService.findGoodsUnitDetail(id);
//                if (CollUtil.isNotEmpty(assistUnit)) {
//                    Map<String, String> finalUnitMap = unitMap;
//                    assistUnit.forEach(e -> {
//                        e.setFromUnitName(CollUtil.isNotEmpty(finalUnitMap) ? finalUnitMap.get(e.getFromUnit()) : null);
//                        e.setToUnitName(CollUtil.isNotEmpty(finalUnitMap) ? finalUnitMap.get(e.getToUnit()) : null);
//                    });
//                }
//                detail.setAssistUnit(assistUnit);
            }
        }

        //单位信息
        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());
            }
            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());
                        }
                );
                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);

        }

        //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);
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<OrderListResDTO> list = kwoTradeOrderMapper.tradeOrderSelect(dto, dto.getGoodIds(), LoginUserHolder.getAuthUserIdList(), null);
        return buildResult(list, params.getPageSize());

    }

    /**
     * @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.TRADE_TYPE.getType(), DictTypeEnum.DELIVERY_TYPE.getType(),
                DictTypeEnum.PICKUP_TYPE.getType(), DictTypeEnum.TORDER_SOURCE.getType()));
        Map<String, SysDictResDto> unitType = remoteSystemService.queryDictMapByType(DictTypeEnum.UNIT_TYPE.getType());
        Map<String, String> statusMap, tradeMap, deliveryMap, pickupMap, sourceMap;
        if (CollUtil.isNotEmpty(dict)) {
            statusMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_STATUS.getType())) ?
                    dict.get(DictTypeEnum.TORDER_STATUS.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);
            deliveryMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.DELIVERY_TYPE.getType())) ?
                    dict.get(DictTypeEnum.DELIVERY_TYPE.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);
            sourceMap = CollUtil.isNotEmpty(dict.get(DictTypeEnum.TORDER_SOURCE.getType())) ?
                    dict.get(DictTypeEnum.TORDER_SOURCE.getType()) : new HashMap<>(Global.NUMERICAL_SIXTEEN);
        } else {
            statusMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            tradeMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            deliveryMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            pickupMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            sourceMap = 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());
            //装货地点名称
            List<String> loadName = loadAddresses.stream().map(KwoTradeOrderAddress::getName).toList();
            //装货地点
            List<String> loadAddress = loadAddresses.stream().map(item -> item.getCityName() + " " + item.getDetailAddress()).toList();
            //卸货地点点名称
            List<String> unloadName = unloadAddresses.stream().map(KwoTradeOrderAddress::getName).toList();
            //卸货地点
            List<String> unloadAddress = unloadAddresses.stream().map(item -> item.getCityName() + " " + item.getDetailAddress()).toList();

            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(statusMap.get(String.valueOf(e.getStatus())))
                    .setTradingLabel(tradeMap.get(e.getTrading()))
                    .setTrading(tradeMap.get(e.getTrading()))
                    .setDeliveryTypeLabel(deliveryMap.get(e.getDeliveryType()))
                    .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())
                    .setGoodsSpec(Objects.isNull(goods) ? null : goods.getSpec())
                    .setGoodsTaxRate(Objects.isNull(goods) ? null : goods.getTaxRate())
                    .setGoodsThumb(Objects.isNull(goods) ? null : goods.getThumb())
                    .setWaitEntrustAmount(setScale(getWaitEntrustAmount(e.getAmount(), e.getEntrustAmount())))
                    .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())
                    .setLoadName(loadName)
                    .setLoadAddress(loadAddress)
                    .setUnloadName(unloadName)
                    .setUnloadAddress(unloadAddress);
            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);
        dto.setEntId(LoginUserHolder.getEntId())
                .setUserId(LoginUserHolder.getUserId())
                .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(TradeOrderListStatisticParam params) {
        TableStatisticRes res = new TableStatisticRes();
        TradeOrderListSelectDTO dto = buildSelectParam(params);
        dto.setStatus(null);
        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 (OrderStatusEnum e : OrderStatusEnum.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;
    }

    /**
     * @desc: 贸易订单列表导出
     * @author: yzc
     * @date: 2023-07-17 18:05
     * @Param params:
     * @return: java.util.List<com.sckw.report.service.param.TradeOrderListExport>
     */
    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 Collections.emptyList();
        }
        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<Long> querySignGoods(Long entId) {
        return kwoTradeOrderMapper.selectGoodsId(entId);
    }

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

    /**
     * 新增贸易订单
     *
     * @param tradeOrderParam
     */
    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);
        //商品地址信息
        AddressInfoDetail goodsAddress = goodsInfoService.getGoodsAddress(tradeOrderParam.getGoodsId());
        if (Objects.isNull(goodsAddress)) {
            throw new BusinessException("商品发货地址信息不存在");
        }
        kwoTradeOrderMapper.insert(order);//贸易订单

        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(goodsInfoDto.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.getTradeContractName());
        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());
                kwoTradeOrderTransportService.insert(kwoTradeOrderTransport);
            }
        }
        List<TradeContractUnitDto> unitList = tradeContractResDto.getUnitList();

        List<KwoTradeOrderUnit> list = new ArrayList<>();
        unitList.forEach(e -> {
            KwoTradeOrderUnit unit = BeanUtil.copyProperties(e, KwoTradeOrderUnit.class);
            unit.setId(new IdWorker(1).nextId());
            unit.setTOrderId(order.getId())
                    .setUnitType(e.getUnitType())
                    .setTOrderNo(order.getTOrderNo())
                    .setTopEntId(e.getEntId());
            list.add(unit);
        });
        kwoTradeOrderUnitService.insertBatch(list);

        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(tradeOrderParam.getGoodsId(), tradeOrderParam.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
    }

    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("当前贸易订单不存在交易商品");
        }
        order.setUnit(goodsInfoDto.getUnit());
        order.setPrice(goodsInfoDto.getPrice());
        order.setTrading(String.valueOf(tradeContractResDto.getTrading()));
        order.setPickupType(String.valueOf(tradeContractResDto.getConsignment()));//来源于合同约束的托运方式
        order.setDeliveryType("");
        order.setActualAmount(new BigDecimal("0"));
        order.setAssociateStatement(0);
        order.setChargeType(tradeContractResDto.getUnloadWay());
        order.setConsignmentWay(tradeContractResDto.getConsignment());
        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
     */
    public Object 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("贸易订单企业信息缺失");
        }
        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(tradeOrderAuditParam.getTradeContractId(), tradeOrderAuditParam.getGoodsId());

        List<LogisticsEntDto> logisticsContractId = tradeOrderAuditParam.getLogisticsContractList();
        if (Objects.equals(tradeContractResDto.getConsignment(), 2) && CollUtil.isEmpty(logisticsContractId)) {
            throw new BusinessException("卖方托运时，物流合同不能为空");
        }
        //更新贸易订单状态
        kwoTradeOrder.setStatus(Objects.equals(tradeOrderAuditParam.getStatus(), 2) ? TradeOrderStatusEnum.BACK.getCode() : TradeOrderStatusEnum.ING.getCode());
        kwoTradeOrderMapper.updateById(kwoTradeOrder);
        if (Objects.equals(tradeOrderAuditParam.getStatus(), 2)) {
            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);
            return true;
        }
        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);
        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 (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.setEndTime(LocalDate.now());
                logisticInfo.setStartTime(LocalDate.now());
                logisticInfo.setUnloadContacts("");
                logisticInfo.setUnloadPhone("");
                logisticInfo.setUnloadDetailAddress("");
                logisticInfo.setAmount(new BigDecimal("0"));
                logisticInfo.setAmountUnit("");
                logisticInfo.setLoss(new BigDecimal("0"));
                logisticInfo.setPayment(0L);
                logisticInfo.setSigningWay(0);
                logisticInfo.setLossUnit("");
                logisticInfo.setBillingMode("");
                logisticInfo.setRemark("");
                logisticInfo.setType(0);

                return logisticInfo;
            }).collect(Collectors.toList());
            addLogisticOrderParam.setLogisticInfo(collect);
        } 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.setEndTime(LocalDate.now());
                            logisticInfo.setStartTime(LocalDate.now());
                            logisticInfo.setUnloadContacts("");
                            logisticInfo.setUnloadPhone("");
                            logisticInfo.setUnloadDetailAddress("");
                            logisticInfo.setAmount(new BigDecimal("0"));
                            logisticInfo.setAmountUnit("");
                            logisticInfo.setLoss(new BigDecimal("0"));
                            logisticInfo.setPayment(0L);
                            logisticInfo.setSigningWay(0);
                            logisticInfo.setLossUnit("");
                            logisticInfo.setBillingMode("");
                            logisticInfo.setRemark("");
                            logisticInfo.setType(0);

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

        }
        addLogisticOrderParam.setTradeOrderId(kwoTradeOrder.getId());
        addLogisticOrderParam.setTradeOrderNo(kwoTradeOrder.getTOrderNo());
        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());
            }

        } 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());
            }
        }

        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());
        }

        List<KwoTradeOrderAddress> kwoTradeOrderAddresses2 = addressMap.get(String.valueOf(AddressTypeEnum.SHIPMENT.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());
        }

        log.info("创建物流订单：{}", JSONObject.toJSONString(addLogisticOrderParam));
        transportRemoteService.addLogisticOrder(addLogisticOrderParam);
        return true;
    }

    /**
     * 手动完结订单
     *
     * @param tradeOrderSettleParam
     * @return
     */
    public Object settleOrder(TradeOrderSettleParam tradeOrderSettleParam) {
        KwoTradeOrder kwoTradeOrder = new KwoTradeOrder();
        List<KwtLogisticsOrderVO> logisticOrderList = transportRemoteService.getLogisticOrderList(new OrderFinishParam(tradeOrderSettleParam.getId()));
        if (CollUtil.isNotEmpty(logisticOrderList)) {
            if (logisticOrderList.stream().allMatch(d -> Objects.equals(d.getStatus(), LogisticsOrderV1Enum.HAVE_FINISHED.getCode()))) {
                kwoTradeOrder.setStatus(TradeOrderStatusEnum.SUCCESS.getCode());
            } else {
                kwoTradeOrder.setStatus(TradeOrderStatusEnum.DEAL.getCode());
            }
        } else {
            kwoTradeOrder.setStatus(TradeOrderStatusEnum.DEAL.getCode());
        }
        kwoTradeOrder.setId(tradeOrderSettleParam.getId());
        kwoTradeOrder.setUpdateBy(LoginUserHolder.getUserId());
        kwoTradeOrder.setUpdateTime(new Date());
        kwoTradeOrderMapper.updateById(kwoTradeOrder);
        //通知下游，贸易订单已完结，或处于完结中。
        transportRemoteService.logisticOrderFinish(new OrderFinishParam(tradeOrderSettleParam.getId()));
        return true;
    }

    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);
    }
}
