package com.sckw.transport.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
import com.sckw.core.model.enums.CarWaybillEnum;
import com.sckw.core.model.enums.LogisticsOrderEnum;
import com.sckw.core.model.page.PageRes;
import com.sckw.core.model.page.PageResult;
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.LineFreightAddressRes;
import com.sckw.mongo.enums.BusinessTypeEnum;
import com.sckw.mongo.model.SckwLogisticsOrder;
import com.sckw.order.api.dubbo.RemoteTradeOrderAmountService;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.*;
import com.sckw.redis.config.RedisLockUtil;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.SckwBusSum;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.model.vo.LogisticsOrderVO;
import com.sckw.transport.common.config.MessageUrlConfig;
import com.sckw.transport.dao.*;
import com.sckw.transport.model.*;
import com.sckw.transport.model.dto.*;
import com.sckw.transport.model.param.ContractParam;
import com.sckw.transport.model.param.LogisticsOrderParam;
import com.sckw.transport.model.vo.LogisticsOrderUnitResp;
import com.sckw.transport.model.vo.*;
import com.sckw.transport.repository.KwtLogisticsOrderRepository;
import com.sckw.transport.repository.KwtLogisticsOrderUnitRepository;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lfdc
 * @desc 运输服务公共service接口
 * @date 2023-06-29 15:06:45
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class KwtTransportCommonService {

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

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 10000)
    TradeOrderInfoService tradeOrderInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 10000)
    RemoteTradeOrderAmountService tradeOrderAmountService;

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

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

    @Autowired
    MessageUrlConfig messageUrlConfig;

    @Autowired
    RedisLockUtil redisLockUtil;


    @Autowired
    public KwtLogisticsOrderGoodsService logisticsOrderGoodsService;

    @Autowired
    public KwtWaybillOrderService waybillOrderService;

    @Autowired
    public KwtCommonService commonService;

    @Autowired
    public KwtLogisticsOrderContractMapper logisticsOrderContractMapper;

    @Autowired
    public KwtLogisticsOrderLineFreightRateMapper lineFreightRateMapper;

    @Autowired
    public KwtLogisticsOrderAddressMapper logisticsOrderAddressMapper;

    @Autowired
    public KwtLogisticsOrderAmountMapper logisticsOrderAmountMapper;

    @Autowired
    public KwtWaybillOrderSubtaskMapper waybillOrderSubtaskMapper;

    @Autowired
    public KwtLogisticsOrderTrackMapper logisticsOrderTrackMapper;

    @Autowired
    public KwtLogisticsOrderGoodsMapper logisticsOrderGoodsMapper;

    @Autowired
    public KwtLogisticsOrderUnitMapper logisticsOrderUnitMapper;

    @Autowired
    public KwtLogisticsOrderMapper logisticsOrderMapper;

    @Autowired
    private KwtWaybillOrderV1Mapper kwtWaybillOrderV1Mapper;

    @Resource
    private StreamBridge streamBridge;

    @Autowired
    private KwtLogisticsOrderLineFreightRateMapper kwtLogisticsOrderLineFreightRateMapper;

    private final KwtLogisticsOrderUnitRepository logisticsOrderUnitRepository;
    private final KwtLogisticsOrderRepository logisticsOrderRepository;
    /**
     * 查看订单详情
     *
     * @param dto
     * @return
     */
    public HttpResult getOrderDetail(DocumentParamDTO dto) {
        HttpResult httpResult = new HttpResult();
        httpResult.setCode(HttpStatus.SUCCESS_CODE);
        if (String.valueOf(NumberConstant.THREE).equals(dto.getDocumentType())) {
            //托运订单
            OrderDetailVO orderDetailVO = getOrderData(dto);
            httpResult.setData(orderDetailVO);
        } else if (String.valueOf(NumberConstant.TWO).equals(dto.getDocumentType())) {
            //承运订单
            OrderDetailVO orderDetailVO = getOrderData(dto);
            httpResult.setData(orderDetailVO);
        } else if (String.valueOf(NumberConstant.ZERO).equals(dto.getDocumentType())) {
            //销售订单
            OrderDetailVO orderDetailVO = getOrderData(dto);
            httpResult.setData(orderDetailVO);
        } else if (String.valueOf(NumberConstant.ONE).equals(dto.getDocumentType())) {
            //采购订单
            OrderDetailVO orderDetailVO = getOrderData(dto);
            httpResult.setData(orderDetailVO);
        } else {
            httpResult.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
            httpResult.setMsg("单据类型错误");
        }
        return httpResult;
    }

    /**
     * 获取订单详情
     *
     * @param dto
     * @return
     */
    private OrderDetailVO getOrderData(DocumentParamDTO dto) {
        KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(dto.getId());
        if (logisticsOrder == null) {
            log.info("查无单据:{}", JSONObject.toJSONString(dto));
            throw new RuntimeException("查无单据");
        }
        KwtLogisticsOrderContract contract = logisticsOrderContractMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderContract>()
                .eq(StringUtils.isNotBlank(dto.getId()), KwtLogisticsOrderContract::getLOrderId, dto.getId()));
        KwtLogisticsOrderUnit unitOne = logisticsOrderUnitMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                .eq(StringUtils.isNotBlank(dto.getId()), KwtLogisticsOrderUnit::getLOrderId, dto.getId())
                .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.ONE));
        KwtLogisticsOrderUnit unitTwo = logisticsOrderUnitMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                .eq(StringUtils.isNotBlank(dto.getId()), KwtLogisticsOrderUnit::getLOrderId, dto.getId())
                .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.TWO));
        List<KwtLogisticsOrderAddress> loadOrderAddress = logisticsOrderAddressMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
                .eq(StringUtils.isNotBlank(dto.getId()), KwtLogisticsOrderAddress::getLOrderId, dto.getId())
                .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.ONE));
        List<KwtLogisticsOrderAddress> unloadOrderAddress = logisticsOrderAddressMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
                .eq(StringUtils.isNotBlank(dto.getId()), KwtLogisticsOrderAddress::getLOrderId, dto.getId())
                .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.TWO));
        KwtLogisticsOrderGoods orderGoods = logisticsOrderGoodsMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderGoods>()
                .eq(StringUtils.isNotBlank(logisticsOrder.getId()), KwtLogisticsOrderGoods::getLOrderId, logisticsOrder.getId()));
        OrderDetailVO orderDetailVO = new OrderDetailVO();
        orderDetailVO.setId(String.valueOf(logisticsOrder.getId()));
        if (contract != null) {
            orderDetailVO.setContractId(contract.getContractId() == null ? null : String.valueOf(contract.getContractId()));
            //todo 接口调用合同服务查询合同信息
            List<Long> list = new ArrayList<>(NumberConstant.SIXTEEN);
            list.add(contract.getContractId());
            Map<Long, ContractCommonInfoResDto> contractBaseInfo = remoteContractService.queryContractBaseInfo(list);
            if (CollectionUtils.isNotEmpty(contractBaseInfo) && !ObjectUtils.isEmpty(contractBaseInfo.get(contract.getContractId()))) {
                orderDetailVO.setContractName(contractBaseInfo.get(contract.getContractId()).getContactName());
                orderDetailVO.setContractNo(contractBaseInfo.get(contract.getContractId()).getContractCode());
                orderDetailVO.setSigningWay(contractBaseInfo.get(contract.getContractId()).getSigningWay());
            }
        }
        if (unitOne != null) {
            orderDetailVO.setConsignCompanyId(unitOne.getEntId());
            orderDetailVO.setConsignCompany(unitOne.getFirmName());
            orderDetailVO.setConsignContacts(unitOne.getContacts());
            orderDetailVO.setConsignPhone(unitOne.getPhone());
            orderDetailVO.setCollectionCompany(unitOne.getFirmName());
        }
        if (unitTwo != null) {
            orderDetailVO.setCarrierCompanyId(unitTwo.getEntId());
            orderDetailVO.setCarrierCompany(unitTwo.getFirmName());
            orderDetailVO.setCarrierContacts(unitTwo.getContacts());
            orderDetailVO.setCarrierPhone(unitTwo.getPhone());
        }
        orderDetailVO.setTaxRate(logisticsOrder.getTaxRate());
        orderDetailVO.setTaxRateLabel(logisticsOrder.getTaxRate() + "%");
        orderDetailVO.setStatus(logisticsOrder.getStatus());
        orderDetailVO.setStatusLabel(LogisticsOrderEnum.getName(logisticsOrder.getStatus()));
        orderDetailVO.setGoodsId(String.valueOf(orderGoods == null ? null : orderGoods.getGoodsId()));
        orderDetailVO.setGoodsName(orderGoods == null ? null : orderGoods.getGoodsName());
        orderDetailVO.setNumber(logisticsOrder.getAmount() == null ? null : logisticsOrder.getAmount());
        orderDetailVO.setPrice(logisticsOrder.getPrice() == null ? null : logisticsOrder.getPrice());
        orderDetailVO.setLoss(logisticsOrder.getLoss() == null ? null : logisticsOrder.getLoss());
        orderDetailVO.setDeduct(logisticsOrder.getGoodsPrice() == null ? null : logisticsOrder.getGoodsPrice());
//        orderDetailVO.setLoadName(loadOrderAddress.getName());
//        orderDetailVO.setLoadAddress(loadOrderAddress.getCityName());
//        orderDetailVO.setLoadContacts(loadOrderAddress.getContacts());
//        orderDetailVO.setLoadPhone(loadOrderAddress.getPhone());
//        orderDetailVO.setLoadAddressDetail(loadOrderAddress.getDetailAddress());
//        orderDetailVO.setUnloadName(unloadOrderAddress.getName());
//        orderDetailVO.setUnloadAddress(unloadOrderAddress.getCityName());
//        orderDetailVO.setUnloadContacts(unloadOrderAddress.getContacts());
//        orderDetailVO.setUnloadPhone(unloadOrderAddress.getPhone());
//        orderDetailVO.setUnloadAddressDetail(unloadOrderAddress.getDetailAddress());
        List<LoadAddressVo> loadAddressList = new ArrayList<>();
        loadOrderAddress.forEach(loadAddress -> {
            LoadAddressVo vo = new LoadAddressVo();
            vo.setLoadName(loadAddress.getName());
            vo.setLoadAddress(loadAddress.getCityName());
            vo.setLoadContacts(loadAddress.getContacts());
            vo.setLoadPhone(loadAddress.getPhone());
            vo.setLoadAddressDetail(loadAddress.getDetailAddress());
            KwtLogisticsOrderAmount orderAmount = logisticsOrderAmountMapper.selectOne(
                    new LambdaQueryWrapper<KwtLogisticsOrderAmount>()
                            .eq(KwtLogisticsOrderAmount::getLOrderId, loadAddress.getLOrderId())
                            .eq(KwtLogisticsOrderAmount::getLAddressId, loadAddress.getId())
                            .eq(KwtLogisticsOrderAmount::getDelFlag, 0)
            );
            vo.setLoadAmount(orderAmount != null ? orderAmount.getAmount() : new BigDecimal("0.00"));
            vo.setAddressId(loadAddress.getId());
            loadAddressList.add(vo);

        });
        orderDetailVO.setLoadAddressList(loadAddressList);

        List<UnLoadAddressVo> unloadAddressList = new ArrayList<>();
        unloadOrderAddress.forEach(unloadAddress -> {
            UnLoadAddressVo vo = new UnLoadAddressVo();
            vo.setUnloadName(unloadAddress.getName());
            vo.setUnloadAddress(unloadAddress.getCityName());
            vo.setUnloadContacts(unloadAddress.getContacts());
            vo.setUnloadPhone(unloadAddress.getPhone());
            vo.setUnloadAddressDetail(unloadAddress.getDetailAddress());
            KwtLogisticsOrderAmount orderAmount = logisticsOrderAmountMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderAmount>()
                    .eq(KwtLogisticsOrderAmount::getLOrderId, unloadAddress.getLOrderId())
                    .eq(KwtLogisticsOrderAmount::getLAddressId, unloadAddress.getId())
                    .eq(KwtLogisticsOrderAmount::getDelFlag, 0)
            );
            vo.setUnloadAmount(orderAmount != null ? orderAmount.getAmount() : new BigDecimal("0.00"));
            vo.setAddressId(unloadAddress.getId());
            unloadAddressList.add(vo);

        });
        orderDetailVO.setUnloadAddressList(unloadAddressList);

        orderDetailVO.setSettlementCycle(logisticsOrder.getSettlementCycle() == null ? null : String.valueOf(logisticsOrder.getSettlementCycle()));
        if (logisticsOrder.getSettlementCycle() != null) {
            Map<String, SysDictResDto> dtoMap = remoteSystemService.queryDictMapByType(DictTypeEnum.SETTLEMENT_CYCLE.getType());
            orderDetailVO.setSettlementCycleLabel(dtoMap.isEmpty() ? null :
                    (dtoMap.get(String.valueOf(logisticsOrder.getSettlementCycle())) == null ? null : dtoMap.get(String.valueOf(logisticsOrder.getSettlementCycle())).getLabel()));
        }
        orderDetailVO.setBillingMode(logisticsOrder.getBillingMode());
        if (logisticsOrder.getBillingMode() != null) {
            Map<String, SysDictResDto> dictResDtoMap = remoteSystemService.queryDictMapByType(DictTypeEnum.CHARGING_TYPE.getType());
            orderDetailVO.setBillingModeLabel(dictResDtoMap.isEmpty() ? null :
                    (dictResDtoMap.get(logisticsOrder.getBillingMode()) == null ? null : dictResDtoMap.get(logisticsOrder.getBillingMode()).getLabel()));
        }
        orderDetailVO.setScheduleStartTime(logisticsOrder.getStartTime() == null ? null : logisticsOrder.getStartTime());
        orderDetailVO.setScheduleEndTime(logisticsOrder.getEndTime() == null ? null : logisticsOrder.getEndTime());
        /**2023-12-23 新增车次按照卸货量计费*/
        if (logisticsOrder.getBillingMode().equals(String.valueOf(NumberConstant.ONE))) {
            orderDetailVO.setPerformanceAmount(logisticsOrder.getTotalLoadAmount() == null ? null : logisticsOrder.getTotalLoadAmount());
        } else if (logisticsOrder.getBillingMode().equals(String.valueOf(NumberConstant.TWO))) {
            orderDetailVO.setPerformanceAmount(logisticsOrder.getTotalUnloadAmount() == null ? null : logisticsOrder.getTotalUnloadAmount());
        } else {
            orderDetailVO.setPerformanceAmount(logisticsOrder.getTotalUnloadAmount() == null ? null : logisticsOrder.getTotalUnloadAmount());
        }
//        orderDetailVO.setPerformanceAmount(logisticsOrder.getLoadAmount() == null ? null : logisticsOrder.getLoadAmount());
        orderDetailVO.setTotalLoadAmount(logisticsOrder.getTotalLoadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getTotalLoadAmount());
        orderDetailVO.setTotalUnloadAmount(logisticsOrder.getTotalUnloadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getTotalUnloadAmount());
        orderDetailVO.setCreateTime(logisticsOrder.getCreateTime());
        orderDetailVO.setPayment(logisticsOrder.getPayment());
        if (logisticsOrder.getPayment() != null) {
            Map<String, SysDictResDto> dictResDtoMap = remoteSystemService.queryDictMapByType(DictTypeEnum.TRADE_TYPE.getType());
            if (dictResDtoMap.isEmpty()) {
                orderDetailVO.setPaymentLabel(null);
            } else {
                if (dictResDtoMap.get(logisticsOrder.getPayment().toString()) != null) {
                    orderDetailVO.setPaymentLabel(dictResDtoMap.get(logisticsOrder.getPayment().toString()).getLabel());
                }
            }
        }
        if (orderDetailVO.getSigningWay() != null) {
            Map<String, SysDictResDto> dictResDtoMap = remoteSystemService.queryDictMapByType(DictTypeEnum.SIGNING_TYPE.getType());
            if (dictResDtoMap.isEmpty()) {
                orderDetailVO.setPaymentLabel(null);
            } else {
                if (dictResDtoMap.get(String.valueOf(orderDetailVO.getSigningWay())) != null) {
                    orderDetailVO.setSigningWayLabel(dictResDtoMap.get(orderDetailVO.getSigningWay().toString()).getLabel());
                }
            }
        }
        if (logisticsOrder.getGoodsPriceUnit() != null) {
            SysDictResDto sysDictResDto = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), logisticsOrder.getGoodsPriceUnit());
            orderDetailVO.setDeductLabel(sysDictResDto == null ? null : sysDictResDto.getLabel());
        }
        if (logisticsOrder.getLossUnit() != null) {
            SysDictResDto sysDictResDto = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.TAX_RATE_TYPE.getType(), logisticsOrder.getLossUnit());
            orderDetailVO.setLossLabel(sysDictResDto == null ? null : sysDictResDto.getLabel());
        }
        if (logisticsOrder.getUnit() != null) {
            SysDictResDto sysDictResDto = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.UNIT_TYPE.getType(), logisticsOrder.getUnit());
            orderDetailVO.setNumberLabel(sysDictResDto == null ? null : sysDictResDto.getLabel());
        }
        if (logisticsOrder.getPriceType() != null) {
            SysDictResDto sysDictResDto = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), String.valueOf(logisticsOrder.getPriceType()));
            orderDetailVO.setPriceLabel(sysDictResDto == null ? null : sysDictResDto.getLabel());
        }
        orderDetailVO.setRemark(logisticsOrder.getRemark());
        orderDetailVO.setWaitDistributionAmount(logisticsOrder.getAmount()
                .subtract(logisticsOrder.getSubcontractAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getSubcontractAmount())
                .subtract(logisticsOrder.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getEntrustAmount()));
        /**亏吨量/吨->装货量-卸货量
         * 合理损耗值=装货量*合理损耗
         扣亏量/吨->亏吨量-合理损耗值
         罚款值 扣亏量/吨*扣亏货值
         总运价:
         按照装货量 运输运价*装货量
         按照卸货量 卸货量*运输单价-罚款值
         按照趟次=运输运价
         */
        //合理损耗
        BigDecimal loss = logisticsOrder.getLoss() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getLoss();

        Integer status = logisticsOrder.getStatus();
        List<Integer> orderStatusFinish = new ArrayList<>();
        orderStatusFinish.add(LogisticsOrderEnum.HAVE_FINISHED.getCode());
        orderStatusFinish.add(LogisticsOrderEnum.HAVE_RECONCILED.getCode());
        orderStatusFinish.add(LogisticsOrderEnum.HAVE_ALREADY_SETTLED.getCode());
        /**根据当前单据状态进行订单金额计算*/
        if (orderStatusFinish.contains(status)) {
            /**亏吨量/吨->装货量-卸货量
             扣亏量/吨->亏吨量-合理损耗值
             扣亏量/吨->亏吨量-合理损耗值(装货量*合理损耗)*/
            BigDecimal loadAmount = logisticsOrder.getTotalLoadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getTotalLoadAmount();
            BigDecimal unloadAmount = logisticsOrder.getTotalUnloadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getTotalUnloadAmount();
            //运价
            BigDecimal price = logisticsOrder.getPrice() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getPrice();
            //亏吨量
            BigDecimal defectiveWeighNumber = loadAmount.subtract(unloadAmount);
            //合理损耗值
            BigDecimal lossAmount = loadAmount.multiply(loss);
            //扣亏量/吨
            BigDecimal deductWeighNumber = defectiveWeighNumber.subtract(lossAmount);
            if (deductWeighNumber.compareTo(new BigDecimal("0")) < 0) {
                deductWeighNumber = NumberConstant.ZERO_TWO;
            }
            //罚款值
            BigDecimal fineValue = (logisticsOrder.getGoodsPrice() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getGoodsPrice()).multiply(deductWeighNumber);
            if (DictEnum.CHARGING_TYPE_1.getValue().equals(logisticsOrder.getBillingMode())) {
                orderDetailVO.setOrderAmount(price.multiply(loadAmount));
            } else if (DictEnum.CHARGING_TYPE_2.getValue().equals(logisticsOrder.getBillingMode())) {
                orderDetailVO.setOrderAmount(unloadAmount.multiply(price).subtract(fineValue));
            } else if (DictEnum.CHARGING_TYPE_3.getValue().equals(logisticsOrder.getBillingMode())) {
                /*// 物流订单运单趟次数量
                Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN) {{
                    put("upperlOrderId", logisticsOrder.getId());
                    put("passStatus", Global.NUMERICAL_ONE);
                }};
                WaybillCountVo waybillOrderCount = kwtWaybillOrderV1Mapper.findWaybillOrderCount(map);
                int count = waybillOrderCount == null ? NumberConstant.ZERO : waybillOrderCount.getTotalComplete();*/
                BigDecimal totalComplete = BigDecimal.valueOf(logisticsOrder.getTotalTake());
                orderDetailVO.setOrderAmount(totalComplete.multiply(price).subtract(fineValue));
            }
        } else {
            orderDetailVO.setOrderAmount(NumberUtils.parseBigDecimal(logisticsOrder.getAmount()).multiply(NumberUtils.parseBigDecimal(logisticsOrder.getPrice())));
        }


        List<LineFreightRateVo> lineFreightRateVos = kwtLogisticsOrderLineFreightRateMapper.selectListByOrderId(Long.parseLong(dto.getId()));
        orderDetailVO.setLineFreightRate(lineFreightRateVos);
        orderDetailVO.setTotalTake(logisticsOrder.getTotalTake());
        return orderDetailVO;
    }

    /**
     * 撤销托运
     *
     * @param orderDto 请求参数
     * @return 处理结果
     */
    @GlobalTransactional
    public HttpResult cancelConsign(CancelOrderDTO orderDto) {
        log.info("订单-撤销托运请求参数:{}", JSONObject.toJSONString(orderDto));
        HttpResult result = new HttpResult();
        String key = String.format(RedisConstant.LOGISTICS_ORDER_CANCEL_KEY, orderDto.getId());
        if (redisLockUtil.tryLock(key)) {
            try {
                KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrder>()
                        .eq(KwtLogisticsOrder::getId, orderDto.getId())
                );
                if (logisticsOrder == null) {
                    result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
                    result.setMsg("单据不存在");
                    return result;
                }
                if (!LogisticsOrderEnum.PENDING_ORDER.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))) {
                    result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
                    result.setMsg("待接单才允许撤销托运");
                    return result;
                }
                /**以此字段判别是否存在分包操作*/
                if (ObjectUtils.isEmpty(logisticsOrder.getPid()) && "1".equals(logisticsOrder.getType())) {
                    /**并不存在分包，撤销数据回归到贸易订单，[待接单状态]下才能撤销托运*/
                    /**调用dubbo 修改数值*/
                    List<GoodsLoadingParam> goodsLoading = logisticsOrderGoodsService.goodsLoadingParams(logisticsOrder, false);
//                    HttpResult httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(logisticsOrder.getTOrderId(), goodsLoading);
                    HttpResult httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(LoginUserHolder.getUserId(), LoginUserHolder.getUserName(), logisticsOrder.getTOrderId(), goodsLoading);
                    if (HttpStatus.SUCCESS_CODE != httpResult.getCode()) {
                        log.info("撤销托运错误:请求参数:{}{},响应信息:{}", logisticsOrder.getTOrderId(), JSONObject.toJSONString(goodsLoading), JSONObject.toJSONString(httpResult));
                        throw new BusinessException("撤销托运错误:" + httpResult.getMsg());
                    }
                    Long id = logisticsOrder.getId();
                    List<LogisticsOrderCancelAmountVo> logisticsOrderCancelAmountVos = logisticsOrderAmountMapper.cancelOrderToAmountByOrderId(id, NumberConstant.ONE);
                    if (CollectionUtils.isNotEmpty(logisticsOrderCancelAmountVos)) {
                        logisticsOrderCancelAmountVos.forEach(cancelAmountVos -> {
                            Long tOrderId = cancelAmountVos.getTOrderId();
                            Long tOrderAddressId = cancelAmountVos.getTOrderAddressId();
                            UpdateAddressEntrustAmountParam param = new UpdateAddressEntrustAmountParam();
                            param.setTOrderId(tOrderId);
                            param.setTAddressId(tOrderAddressId);
                            param.setEntrustAmount(cancelAmountVos.getAmount().negate());
                            param.setUpdateBy(LoginUserHolder.getUserId());
                            param.setUpdateByName(LoginUserHolder.getUserName());
                            HttpResult httpResult1 = tradeOrderAmountService.updateAddressEntrustAmount(param);
                            if (HttpStatus.SUCCESS_CODE != httpResult1.getCode()) {
                                log.info("撤销托运还原地址的分配量错误:,请求参数:{},{},响应信息:{}",
                                        logisticsOrder.getTOrderId(), JSONObject.toJSONString(param), JSONObject.toJSONString(httpResult1));
                                throw new BusinessException("撤销托运还原地址的分配量错误:" + httpResult1.getMsg());
                            }
                        });
                    }
                    logisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                            .eq(KwtLogisticsOrder::getId, logisticsOrder.getId())
                            .set(KwtLogisticsOrder::getStatus, LogisticsOrderEnum.CANCEL_ORDER.getCode())
                            .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                            .set(KwtLogisticsOrder::getUpdateTime, new Date()));
                    updateOrderTrack(logisticsOrder.getId(), orderDto.getRemark(), LogisticsOrderEnum.CANCEL_ORDER);
                    //mongodb更新
                    SckwLogisticsOrder order = new SckwLogisticsOrder();
                    order.set_id(logisticsOrder.getId());
                    order.setLOrderId(logisticsOrder.getId());
                    order.setStatus(LogisticsOrderEnum.CANCEL_ORDER.getStatus());
                    order.setUpdateTime(new Date());
                    order.setUpdateByName(LoginUserHolder.getUserName());
                    order.setUpdateBy(LoginUserHolder.getUserId());
                    SckwBusSum busSum = new SckwBusSum();
                    //业务汇总类型
                    busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
                    //操作对象（1新增/2修改）
                    busSum.setMethod(NumberConstant.TWO);
                    //业务汇总数据对象
                    busSum.setObject(order);
                    streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
                } else {
                    /**即代表存在分包,当次是属于被分包.需要将数据回归到上游数据。*/
                    Long pid = logisticsOrder.getPid();
                    /**指的是上游单据进行回归*/
                    KwtLogisticsOrder order = logisticsOrderMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrder>()
                            .eq(KwtLogisticsOrder::getId, pid));
                    //上游分配量
                    BigDecimal amount = logisticsOrder.getAmount();
                    //已经完成的量
                    BigDecimal loadAmount = logisticsOrder.getLoadAmount();
                    //未完成的量
                    BigDecimal subtract = amount.subtract(loadAmount);
                    //.setScale(2,BigDecimal.ROUND_HALF_DOWN)
                    BigDecimal add = order.getSubcontractAmount().subtract(amount);
                    logisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                            .eq(KwtLogisticsOrder::getId, order.getId())
                            .set(KwtLogisticsOrder::getDelFlag, NumberConstant.ZERO)
                            .set(KwtLogisticsOrder::getSubcontractAmount, add)
                            .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                            .set(KwtLogisticsOrder::getUpdateTime, new Date()));
                    //            updateOrderTrack(logisticsOrder.getId(),orderDto.getRemark(),LogisticsOrderEnum.CANCEL_ORDER);
                    /**修改上游地址id的分包量*/
                    updateOrderAmount(logisticsOrder, order);
                    /**下游订单进行状态改变*/
                    logisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                            .eq(KwtLogisticsOrder::getId, logisticsOrder.getId())
                            .set(KwtLogisticsOrder::getStatus, LogisticsOrderEnum.CANCEL_ORDER.getCode())
                            .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                            .set(KwtLogisticsOrder::getUpdateTime, new Date()));
                    updateOrderTrack(logisticsOrder.getId(), orderDto.getRemark(), LogisticsOrderEnum.CANCEL_ORDER);
                    /**mongodb更新*/
                    //父级
                    SckwLogisticsOrder sckwLogisticsOrder = new SckwLogisticsOrder();
                    sckwLogisticsOrder.set_id(order.getId());
                    sckwLogisticsOrder.setLOrderId(order.getId());
                    sckwLogisticsOrder.setSubcontractAmount(add);
                    sckwLogisticsOrder.setUpdateTime(new Date());
                    sckwLogisticsOrder.setUpdateByName(LoginUserHolder.getUserName());
                    sckwLogisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
                    SckwBusSum busSum = new SckwBusSum();
                    //业务汇总类型
                    busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
                    //操作对象（1新增/2修改）
                    busSum.setMethod(NumberConstant.TWO);
                    //业务汇总数据对象
                    busSum.setObject(sckwLogisticsOrder);
                    //当前级
                    streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
                    SckwLogisticsOrder logisticsOrder1 = new SckwLogisticsOrder();
                    logisticsOrder1.set_id(logisticsOrder.getId());
                    logisticsOrder1.setLOrderId(logisticsOrder.getId());
                    logisticsOrder1.setStatus(LogisticsOrderEnum.CANCEL_ORDER.getStatus());
                    logisticsOrder1.setUpdateTime(new Date());
                    logisticsOrder1.setUpdateByName(LoginUserHolder.getUserName());
                    logisticsOrder1.setUpdateBy(LoginUserHolder.getUserId());
                    SckwBusSum busSum1 = new SckwBusSum();
                    //业务汇总类型
                    busSum1.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
                    //操作对象（1新增/2修改）
                    busSum1.setMethod(NumberConstant.TWO);
                    //业务汇总数据对象
                    busSum1.setObject(logisticsOrder1);
                    streamBridge.send("sckw-busSum", JSON.toJSONString(busSum1));
                }
//        String type = orderDto.getType();
//        if ("1".equals(type)) {
//            commonService.cancelLogisticsConsignment(logisticsOrder.getLOrderNo(), logisticsOrder.getCreateBy(), logisticsOrder.getEntId(), MessageEnum.CANCELLATION_LOGISTICS,newLogisticsOrderUrl);
//        } else if ("2".equals(type)) {
//            commonService.cancelLogisticsConsignment(logisticsOrder.getLOrderNo(), logisticsOrder.getCreateBy(), logisticsOrder.getEntId(), MessageEnum.CARRIAGE_CANCELLATION_LOGISTICS,newLogisticsOrderUrl);
//        }

                Long id = logisticsOrder.getId();
                //托运
                KwtLogisticsOrderUnit consignUnit = logisticsOrderUnitMapper.selectOne(
                        new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                                .eq(KwtLogisticsOrderUnit::getLOrderId, id)
                                .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.ONE));
                //承运
                KwtLogisticsOrderUnit carriageUnit = logisticsOrderUnitMapper.selectOne(
                        new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                                .eq(KwtLogisticsOrderUnit::getLOrderId, id)
                                .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.TWO));
//        commonService.cancelLogisticsConsignment(consignUnit, carriageUnit, logisticsOrder.getLOrderNo(), logisticsOrder.getCreateBy(),
//                logisticsOrder.getEntId(), MessageEnum.CANCELLATION_LOGISTICS, MessageEnum.CARRIAGE_CANCELLATION_LOGISTICS);
                commonService.newSendLogisticsOrderToMessage(consignUnit, carriageUnit, logisticsOrder.getLOrderNo(), logisticsOrder.getCreateBy(),
                        logisticsOrder.getEntId(),
                        messageUrlConfig.getPc().getConsignLogisticsAddOrderUrl(), messageUrlConfig.getApp().getConsignLogisticsAddOrderUrl(),
                        messageUrlConfig.getPc().getCarriageLogisticsAddOrderUrl(), messageUrlConfig.getApp().getCarriageLogisticsAddOrderUrl(),
                        MessageEnum.CANCELLATION_LOGISTICS, MessageEnum.CARRIAGE_CANCELLATION_LOGISTICS,
                        "1");
            } finally {
                redisLockUtil.unlock(key);
            }
        } else {
            return HttpResult.error("当前数据不可重复提交");
        }
        return result;
    }

    /**
     * 修改订单地址的量
     *
     * @param currentLogisticsOrder 当前订单
     * @param pidLogisticsOrder     父级订单
     */
    private void updateOrderAmount(KwtLogisticsOrder currentLogisticsOrder, KwtLogisticsOrder pidLogisticsOrder) {
        List<LogisticsOrderCancelAmountVo> currentOrder = logisticsOrderAmountMapper.cancelOrderToAmountByOrderId(currentLogisticsOrder.getId(), NumberConstant.ONE);
        List<LogisticsOrderCancelAmountVo> pidOrder = logisticsOrderAmountMapper.cancelOrderToAmountByOrderId(pidLogisticsOrder.getId(), NumberConstant.ONE);
        Map<String, BigDecimal> currentOrderMap = new HashMap<>();
        if (currentOrder.size() > 0) {
            for (LogisticsOrderCancelAmountVo logisticsOrderCancelAmountVo : currentOrder) {
                String key = String.valueOf(logisticsOrderCancelAmountVo.getLOrderId()) + "-" + String.valueOf(logisticsOrderCancelAmountVo.getTOrderAddressId());
                BigDecimal amount = logisticsOrderCancelAmountVo.getAmount();
                currentOrderMap.put(key, amount);
            }
        }
        if (pidOrder.size() > 0) {
            for (LogisticsOrderCancelAmountVo logisticsOrderCancelAmountVo : pidOrder) {
                Long lOrderId = logisticsOrderCancelAmountVo.getLOrderId();
                Long tOrderAddressId = logisticsOrderCancelAmountVo.getTOrderAddressId();
                String key = String.valueOf(lOrderId) + "-" + String.valueOf(tOrderAddressId);
                if (currentOrderMap.get(key) != null) {
                    logisticsOrderCancelAmountVo.setAmount(logisticsOrderCancelAmountVo.getAmount().subtract(currentOrderMap.get(key)));
                    logisticsOrderAmountMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrderAmount>()
                            .set(KwtLogisticsOrderAmount::getEntrustAmount, logisticsOrderCancelAmountVo.getAmount())
                            .eq(KwtLogisticsOrderAmount::getId, logisticsOrderCancelAmountVo.getAmountId())
                    );
                }
            }
        }
    }

    /**
     * 根据物流订单修改物流状态表
     *
     * @param id                 物流订单ID
     * @param remark             备注
     * @param logisticsOrderEnum 物流订单昨天枚举
     */
    private void updateOrderTrack(Long id, String remark, LogisticsOrderEnum logisticsOrderEnum) {
        KwtLogisticsOrderTrack orderTrack = logisticsOrderTrackMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderTrack>()
                .eq(KwtLogisticsOrderTrack::getLOrderId, id)
                .eq(KwtLogisticsOrderTrack::getStatus, logisticsOrderEnum.getCode())
        );
        if (orderTrack == null) {
            KwtLogisticsOrderTrack track = new KwtLogisticsOrderTrack();
            track.setId(new IdWorker(NumberConstant.ONE).nextId());
            track.setLOrderId(id);
            track.setRemark(remark);
            track.setStatus(LogisticsOrderEnum.CANCEL_ORDER.getCode());
            track.setCreateBy(LoginUserHolder.getUserId());
            track.setCreateTime(new Date());
            track.setUpdateBy(LoginUserHolder.getUserId());
            track.setUpdateTime(new Date());
            logisticsOrderTrackMapper.insert(track);
        } else {
            orderTrack.setRemark(remark);
            orderTrack.setStatus(LogisticsOrderEnum.CANCEL_ORDER.getCode());
            orderTrack.setUpdateBy(LoginUserHolder.getUserId());
            orderTrack.setUpdateTime(new Date());
            logisticsOrderTrackMapper.updateById(orderTrack);
        }
    }

    /**
     * 对账管理-运费收款对账界面查询接口
     *
     * @param logisticsOrderParam
     * @return
     */
    public HttpResult getAcceptCarriageOrder(LogisticsOrderParam logisticsOrderParam) {
        SysDictResDto sysDictResDto = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.TRADE_TYPE.getType(), logisticsOrderParam.getPayment());
        String dictValue = sysDictResDto == null ? null : sysDictResDto.getValue();
        if (StringUtils.isNotBlank(logisticsOrderParam.getStartTime())) {
            logisticsOrderParam.setStartTime(StringTimeUtil.fillStart(logisticsOrderParam.getStartTime()));
        }
        if (StringUtils.isNotBlank(logisticsOrderParam.getEndTime())) {
            logisticsOrderParam.setEndTime(StringTimeUtil.fillEnd(logisticsOrderParam.getEndTime()));
        }
        Integer page = logisticsOrderParam.getPage();
        Long entId = LoginUserHolder.getEntId();
        List<Long> ids = new ArrayList<>();
        ids.add(entId);
        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(entId);
        if (entCacheResDto != null) {
            ids.add(entCacheResDto.getId());
        }
        List<Integer> orderStatusList = new ArrayList<>();
        orderStatusList.add(LogisticsOrderEnum.HAVE_FINISHED.getCode());
        ids = ids.stream().distinct().collect(Collectors.toList());
        logisticsOrderParam.setPage((logisticsOrderParam.getPage() - 1) * logisticsOrderParam.getPageSize());
        List<LogisticsOrderVO> list = logisticsOrderMapper.selectLogisticOrderData(logisticsOrderParam, dictValue, LoginUserHolder.getEntId(), ids, orderStatusList);
        Long count = logisticsOrderMapper.selectLogisticOrderCount(logisticsOrderParam, dictValue, LoginUserHolder.getEntId(), ids, orderStatusList);
        /**计量单位*/
        Map<String, String> unitTypeDictData = getDictData(DictTypeEnum.UNIT_TYPE.getType());
        /**运价方式*/
        Map<String, String> priceDictData = getDictData(DictTypeEnum.PRICE_TYPE.getType());
//        /**签约方式*/
//        Map<String, String> singDictData = getDictData(DictTypeEnum.SIGNING_TYPE.getType());
        /**计费方式*/
        Map<String, String> chargingDictData = getDictData(DictTypeEnum.CHARGING_TYPE.getType());
        /**结算周期*/
        Map<String, String> settlementDictData = getDictData(DictTypeEnum.SETTLEMENT_CYCLE.getType());
        /**合理损耗*/
        Map<String, String> taxRateTypeDictData = getDictData(DictTypeEnum.TAX_RATE_TYPE.getType());
        if (CollectionUtils.isNotEmpty(list)) {

            List<LogisticsOrderVO> collect = list.stream().filter(item -> item.getBillingMode().equals(DictEnum.CHARGING_TYPE_4.getValue())).collect(Collectors.toList());
            Map<Long, List<KwtLogisticsOrderLineFreightRate>> collect1 = new HashMap<>();
            if (CollectionUtils.isNotEmpty(collect)) {
                List<KwtLogisticsOrderLineFreightRate> kwtLogisticsOrderLineFreightRates = lineFreightRateMapper.selectListByOrderIdList(collect.stream().map(LogisticsOrderVO::getLOrderId).map(Long::parseLong).toList());
                if (CollectionUtils.isNotEmpty(kwtLogisticsOrderLineFreightRates)) {
                    collect1 = kwtLogisticsOrderLineFreightRates.stream().collect(Collectors.groupingBy(KwtLogisticsOrderLineFreightRate::getLOrderId));
                }
            }

            for (LogisticsOrderVO logisticsOrderDTO : list) {
                List<KwtLogisticsOrderLineFreightRate> kwtLogisticsOrderLineFreightRates = collect1.get(Long.parseLong(logisticsOrderDTO.getLOrderId()));
                if (CollectionUtils.isNotEmpty(kwtLogisticsOrderLineFreightRates)) {
                    logisticsOrderDTO.setPrices(kwtLogisticsOrderLineFreightRates.stream().map(item -> item.getName() + " " + item.getTransportPrice()).toList());
                }
                String tOrderId = logisticsOrderDTO.getTOrderId();
                if (StringUtils.isNotBlank(tOrderId)) {
                    try {
                        OrderDetailRes orderDetailById = tradeOrderInfoService.getOrderDetailById(Long.parseLong(tOrderId));
                        if (orderDetailById != null) {
                            List<UnitInfoDetailRes> unitInfo = orderDetailById.getUnitInfo();
                            if (CollectionUtils.isNotEmpty(unitInfo)) {
                                for (UnitInfoDetailRes detailRes : unitInfo) {
                                    if ("1".equals(detailRes.getUnitType())) {
                                        logisticsOrderDTO.setConsignee(detailRes.getFirmName());
                                    }
                                    if ("2".equals(detailRes.getUnitType())) {
                                        logisticsOrderDTO.setForwardingUnit(detailRes.getFirmName());
                                    }
                                }
                            }
                        }
                    } catch (NumberFormatException e) {
                        System.out.println("查询不到贸易订单数据,id" + tOrderId);
                    }
                }

                KwtLogisticsOrderUnit consignOrderUnit = logisticsOrderUnitMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                        .eq(KwtLogisticsOrderUnit::getLOrderId, logisticsOrderDTO.getLOrderId())
                        .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.ONE));
                KwtLogisticsOrderUnit carrierOrderUnit = logisticsOrderUnitMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderUnit>()
                        .eq(KwtLogisticsOrderUnit::getLOrderId, logisticsOrderDTO.getLOrderId())
                        .eq(KwtLogisticsOrderUnit::getUnitType, NumberConstant.TWO));
//                KwtLogisticsOrderAddress loadOrderAddress = logisticsOrderAddressMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
//                        .eq(KwtLogisticsOrderAddress::getLOrderId, logisticsOrderDTO.getLOrderId())
//                        .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.ONE)
//                );
//                KwtLogisticsOrderAddress unloadOrderAddress = logisticsOrderAddressMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
//                        .eq(KwtLogisticsOrderAddress::getLOrderId, logisticsOrderDTO.getLOrderId())
//                        .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.TWO)
//                );
                KwtLogisticsOrderContract contract = logisticsOrderContractMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderContract>()
                        .eq(KwtLogisticsOrderContract::getLOrderId, logisticsOrderDTO.getLOrderId())
                );

                KwtLogisticsOrderGoods orderGoods = logisticsOrderGoodsMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderGoods>()
                        .eq(KwtLogisticsOrderGoods::getLOrderId, logisticsOrderDTO.getLOrderId())
                );
                logisticsOrderDTO.setGoodsName(orderGoods == null ? null : orderGoods.getGoodsName());

                String billingMode = logisticsOrderDTO.getBillingMode();

                /**
                 * 一、罚款值计算：
                 * 1、合理损耗值=实装量*合理损耗（‰）
                 *  1.1 亏吨量= 实装量-实卸量
                 * 2、扣亏量=亏吨量-合理损耗值【要求大于0，如果小于0则扣亏货量取0】
                 * 3、罚款值=扣亏量 * 扣亏货值
                 *
                 * 二、运价计算：
                 * 1、按装货量：总运价=实装量*运价-罚款值
                 * 2、按卸货量：总运价=实卸量*运价-罚款值
                 * 3、按趟次：总运价=运价*趟次【后期加】
                 */
                //运价
                BigDecimal price = logisticsOrderDTO.getPrice() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getPrice();


                /**亏吨量/吨->装货量-卸货量
                 扣亏量/吨->亏吨量-合理损耗值
                 扣亏量/吨->亏吨量-合理损耗值(装货量*合理损耗)*/
                BigDecimal loadAmount = logisticsOrderDTO.getTotalLoadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalLoadAmount();
                BigDecimal unloadAmount = logisticsOrderDTO.getTotalUnloadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalUnloadAmount();
                BigDecimal loss = logisticsOrderDTO.getLoss() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getLoss();
                //亏吨量
                BigDecimal defectiveWeighNumber = loadAmount.subtract(unloadAmount);
                //合理损耗值
//                BigDecimal lossAmount = loadAmount.multiply(logisticsOrderDTO.getLoss() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getLoss());
                //扣亏量
//                BigDecimal deductWeighNumber = defectiveWeighNumber.subtract(lossAmount);
//                if (deductWeighNumber.compareTo(new BigDecimal("0")) < 0) {
//                    deductWeighNumber = NumberConstant.ZERO_TWO;
//                }
                BigDecimal deductWeighNumber = commonService.deficitLossAmount(loadAmount, defectiveWeighNumber, loss, logisticsOrderDTO.getLossUnit());
                //罚款值
                BigDecimal fineValue = (logisticsOrderDTO.getGoodsPrice() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getGoodsPrice()).multiply(deductWeighNumber);
                /**
                 *
                 * 二、运价计算：
                 * 1、按装货量：总运价=实装量*运价-罚款值
                 * 2、按卸货量：总运价=实卸量*运价-罚款值
                 * 3、按趟次：总运价=运价*趟次【后期加】
                 */
                //todo 2023-10-10 含税金额不减去罚款值 另指定罚款值进行返回数据
                BigDecimal actualAmount = NumberConstant.ZERO_TWO;
                if (DictEnum.CHARGING_TYPE_1.getValue().equals(billingMode)) {
//                    actualAmount = (logisticsOrderDTO.getTotalLoadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalLoadAmount()).multiply(price).subtract(fineValue);
                    actualAmount = (logisticsOrderDTO.getTotalLoadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalLoadAmount()).multiply(price);
                } else if (DictEnum.CHARGING_TYPE_2.getValue().equals(billingMode)) {
//                    actualAmount = (logisticsOrderDTO.getTotalUnloadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalUnloadAmount()).multiply(price).subtract(fineValue);
                    actualAmount = (logisticsOrderDTO.getTotalUnloadAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderDTO.getTotalUnloadAmount()).multiply(price);
                } else if (DictEnum.CHARGING_TYPE_3.getValue().equals(billingMode)) {
                    // 物流订单运单趟次数量
//                    Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN) {{
//                        put("upperlOrderId", logisticsOrderDTO.getLOrderId());
//                        put("passStatus", Global.NUMERICAL_ONE);
//                    }};

                   /* WaybillCountVo waybillOrderCount = kwtWaybillOrderV1Mapper.findCountByLOrderId(Long.parseLong(logisticsOrderDTO.getLOrderId()));
                    BigDecimal totalComplete = waybillOrderCount == null ? NumberConstant.ZERO_TWO : new BigDecimal(waybillOrderCount.getTotalComplete());*/
                    BigDecimal totalComplete = BigDecimal.valueOf(logisticsOrderDTO.getTotalTake());
                    actualAmount = totalComplete.multiply(price);
                } else if (DictEnum.CHARGING_TYPE_4.getValue().equals(billingMode)) {
                    String lOrderId = logisticsOrderDTO.getLOrderId();
                    List<KwtLogisticsOrderLineFreightRate> lineFreightRates = lineFreightRateMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrderLineFreightRate>()
                            .eq(KwtLogisticsOrderLineFreightRate::getLOrderId, lOrderId)
                            .eq(KwtLogisticsOrderLineFreightRate::getDelFlag, 0)
                    );
                    if (CollectionUtils.isNotEmpty(lineFreightRates)) {
                        Map<Long, BigDecimal> amountMap = lineFreightRates.stream().collect(Collectors.toMap(KwtLogisticsOrderLineFreightRate::getLineFreightRateId, KwtLogisticsOrderLineFreightRate::getSettlementAmount));
                        List<Long> lineFreightRateIds = lineFreightRates.stream().map(KwtLogisticsOrderLineFreightRate::getLineFreightRateId).collect(Collectors.toList());
                        Map<Long, LineFreightAddressRes> lineFreightAddress = manageService.findLineFreightAddress(lineFreightRateIds);
                        if (lineFreightAddress != null) {
                            for (LineFreightAddressRes address : lineFreightAddress.values()) {
//                                BigDecimal decimal = amountMap.get(address.getId());
//                                if (decimal != null) {
//                                    BigDecimal sum = address.getTransportPrice().multiply(decimal).setScale(2, RoundingMode.HALF_UP);
//                                    actualAmount = actualAmount.add(address.getTransportAmount());
//                                }
                                actualAmount = actualAmount.add(address.getTransportAmount());
                            }
                        }
                    }
                }
                logisticsOrderDTO.setDeductPrice(fineValue);
                logisticsOrderDTO.setTaxMoney(actualAmount);
//                logisticsOrderDTO.setContractId();
                logisticsOrderDTO.setContractName(contract.getContractName());
                logisticsOrderDTO.setContractNo(contract.getContractNo());
                logisticsOrderDTO.setGoodsPriceLabel(priceDictData.get(logisticsOrderDTO.getPriceType()));
                logisticsOrderDTO.setCreateByName(remoteSystemService.queryUserCacheById(logisticsOrderDTO.getCreateBy()) == null ? null : remoteSystemService.queryUserCacheById(logisticsOrderDTO.getCreateBy()).getName());
//                logisticsOrderDTO.setLoadAddress(loadOrderAddress.getDetailAddress());
//                logisticsOrderDTO.setLoadName(loadOrderAddress.getName());
//                logisticsOrderDTO.setLoadContacts(loadOrderAddress.getContacts());
//                logisticsOrderDTO.setLoadPhone(loadOrderAddress.getPhone());
//                logisticsOrderDTO.setUnloadAddress(unloadOrderAddress.getDetailAddress());
//                logisticsOrderDTO.setUnloadName(unloadOrderAddress.getName());
//                logisticsOrderDTO.setUnloadContacts(unloadOrderAddress.getContacts());
//                logisticsOrderDTO.setUnloadPhone(unloadOrderAddress.getPhone());
                logisticsOrderDTO.setCarrierCompany(carrierOrderUnit == null ? null : carrierOrderUnit.getFirmName());
                logisticsOrderDTO.setCarrierPhone(carrierOrderUnit == null ? null : carrierOrderUnit.getPhone());
                logisticsOrderDTO.setCarrierContacts(carrierOrderUnit == null ? null : carrierOrderUnit.getContacts());
                logisticsOrderDTO.setConsignCompany(consignOrderUnit == null ? null : consignOrderUnit.getFirmName());
                logisticsOrderDTO.setConsignPhone(consignOrderUnit == null ? null : consignOrderUnit.getPhone());
                logisticsOrderDTO.setConsignContacts(consignOrderUnit == null ? null : consignOrderUnit.getContacts());
                logisticsOrderDTO.setSettlementCycleLabel(logisticsOrderDTO.getSettlementCycle() == null ? null : settlementDictData.get(logisticsOrderDTO.getSettlementCycle().toString()));
                logisticsOrderDTO.setBillingModeLabel(chargingDictData.get(logisticsOrderDTO.getBillingMode()));
                logisticsOrderDTO.setPriceLabel(priceDictData.get(logisticsOrderDTO.getPriceType()));
                logisticsOrderDTO.setLossUnitLabel(taxRateTypeDictData.get(logisticsOrderDTO.getLossUnit()));
                logisticsOrderDTO.setAmountLabel(unitTypeDictData.get(logisticsOrderDTO.getUnit()));
                logisticsOrderDTO.setIgnoreAmountLabel(unitTypeDictData.get(logisticsOrderDTO.getUnit()));
                logisticsOrderDTO.setLoadAmount(logisticsOrderDTO.getTotalLoadAmount());
                logisticsOrderDTO.setUnloadAmount(logisticsOrderDTO.getTotalUnloadAmount());
                if (logisticsOrderDTO.getTOrderId() != null) {
                    try {
                        OrderDetailRes orderDetailRes = tradeOrderInfoService.getOrderDetailById(Long.valueOf(logisticsOrderDTO.getTOrderId()));
                        if (orderDetailRes != null) {
                            List<UnitInfoDetailRes> unitInfo = orderDetailRes.getUnitInfo();
                            if (CollectionUtils.isNotEmpty(unitInfo)) {
                                for (UnitInfoDetailRes unitInfoDetailRes : unitInfo) {
                                    if (String.valueOf(NumberConstant.TWO).equals(unitInfoDetailRes.getUnitType())) {
                                        logisticsOrderDTO.setShipmentsUnitId(String.valueOf(unitInfoDetailRes.getEntId()));
                                        logisticsOrderDTO.setShipmentsUnit(unitInfoDetailRes.getFirmName());
                                    } else if (String.valueOf(NumberConstant.ONE).equals(unitInfoDetailRes.getUnitType())) {
                                        logisticsOrderDTO.setReceiveGoodsUnitId(String.valueOf(unitInfoDetailRes.getEntId()));
                                        logisticsOrderDTO.setReceiveGoodsUnit(unitInfoDetailRes.getFirmName());
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("tradeOrderInfoService.getOrderDetailById error id:{},errorMessage:{}", logisticsOrderDTO.getTOrderId(), e.getMessage(), e);
                    }
                }
//                logisticsOrderDTO.setCount(waybillOrderMapper.selectCount(new LambdaQueryWrapper<KwtWaybillOrder>().eq(KwtWaybillOrder::getLOrderId, logisticsOrderDTO.getLOrderId())));
            }
        }
        PageResult build = PageResult.build(page, logisticsOrderParam.getPageSize(), count, list);
        return HttpResult.ok(build);
    }

    /**
     * 获取数据字典
     *
     * @param type 字典类型
     * @return 数据
     */
    public Map<String, String> getDictData(String type) {
        Map<String, String> maps = new HashMap<>(NumberConstant.SIXTEEN);
        List<SysDictResDto> list = remoteSystemService.queryDictByType(type);
        if (CollectionUtils.isNotEmpty(list)) {
            maps = list.stream().collect(Collectors.toMap(SysDictResDto::getValue, SysDictResDto::getLabel, (key1, key2) -> key2));
        }
        return maps;
    }

    /**
     * 承运合同/托运合同-根据合同id获取托运订单列表
     *
     * @param contractParam 参数
     * @return 合同信息
     */
    public HttpResult getLogisticsOrderByContractId(ContractParam contractParam) {
        PageHelper.startPage(contractParam.getPage(), contractParam.getPageSize());
        List<Long> contractIds = StringUtils.splitStrToList(contractParam.getContractIds(), Long.class);
        Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(Collections.singletonList(LoginUserHolder.getEntId()));
        List<SckwLogisticsOrderVO> list = logisticsOrderMapper.selectOrderListByContractId(contractParam.getContractType(), entMap.get(LoginUserHolder.getEntId()).getId(), contractIds);
        List<SckwLogisticsOrderVO> returnList = new ArrayList<>();
        PageInfo<SckwLogisticsOrderVO> pageInfo = new PageInfo<>(list);
        if (CollectionUtils.isEmpty(list)) {
            return HttpResult.ok(PageRes.build(pageInfo, list));
        }
        /**计量单位*/
        Map<String, String> dictResDtoMap = getDictData(DictTypeEnum.UNIT_TYPE.getType());
        /**支付方式*/
        Map<String, String> tradeTypeDictData = getDictData(DictTypeEnum.TRADE_TYPE.getType());
        /**运价方式*/
//        Map<String, String> priceDictData = getDictData(DictTypeEnum.PRICE_TYPE.getType());
        /**计费方式*/
        Map<String, String> chargingDictData = getDictData(DictTypeEnum.CHARGING_TYPE.getType());
        /**结算周期*/
        Map<String, String> settlementDictData = getDictData(DictTypeEnum.SETTLEMENT_CYCLE.getType());
        /**签约方式*/
//        Map<String, String> signingWay = getDictData(DictTypeEnum.SIGNING_TYPE.getType());
        /**合理损耗*/
        Map<String, String> taxRateTypeDictData = getDictData(DictTypeEnum.TAX_RATE_TYPE.getType());
        if (CollectionUtils.isNotEmpty(list)) {
            for (SckwLogisticsOrderVO vo : list) {
                vo.setBillingModeLabel(chargingDictData == null ? null : chargingDictData.get(vo.getBillingMode()));
                vo.setPaymentLabel(vo.getPayment() == null ? null : tradeTypeDictData.get(vo.getPayment().toString()));
                vo.setStatusLabel(LogisticsOrderEnum.getDestination(vo.getStatus()));
                vo.setLossUnitLabel(vo.getLossUnit() == null ? null : taxRateTypeDictData.get(vo.getLossUnit()));
                vo.setUnitLabel(vo.getUnit() == null ? null : dictResDtoMap.get(vo.getUnit()));
                vo.setGoodsPriceUnitLabel(vo.getGoodsPriceUnit() == null ? null : dictResDtoMap.get(vo.getGoodsPriceUnit()));
                vo.setSettlementCycleLabel(vo.getSettlementCycle() == null ? null : settlementDictData.get(vo.getSettlementCycle().toString()));
                UserCacheResDto userCacheResDto = remoteSystemService.queryUserCacheById(vo.getCreateBy());
                vo.setCreateByName(userCacheResDto == null ? null : userCacheResDto.getName());
                //todo 2024-03-08 11:18沟通  去掉展示订单地址信息
//                Long lOrderId = vo.getLOrderId();
//                List<String> loadName = new ArrayList<String>();
//                List<String> loadAddressList = new ArrayList<String>();
//                List<KwtLogisticsOrderAddress> loadAddress = logisticsOrderAddressMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
//                        .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.ONE)
//                        .eq(KwtLogisticsOrderAddress::getDelFlag, NumberConstant.ZERO)
//                        .eq(KwtLogisticsOrderAddress::getLOrderId, lOrderId)
//                );
//                loadAddress.forEach(address -> {
//                    loadName.add(address.getName());
//                    loadAddressList.add(address.getDetailAddress());
//                });
//
//                List<String> unloadName = new ArrayList<String>();
//                List<String> unloadAddressList = new ArrayList<String>();
//                List<KwtLogisticsOrderAddress> unloadAddress = logisticsOrderAddressMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
//                        .eq(KwtLogisticsOrderAddress::getAddressType, NumberConstant.TWO)
//                        .eq(KwtLogisticsOrderAddress::getDelFlag, NumberConstant.ZERO)
//                        .eq(KwtLogisticsOrderAddress::getLOrderId, lOrderId)
//                );
//                unloadAddress.forEach(address -> {
//                    unloadName.add(address.getName());
//                    unloadAddressList.add(address.getDetailAddress());
//                });
//                vo.setLoadNames(loadName);
//                vo.setLoadAddresses(loadAddressList);
//                vo.setUnloadNames(unloadName);
//                vo.setUnloadAddresses(unloadAddressList);
//                List<LoadAddressVo> loadAddressAmount = logisticsOrderAddressMapper.findByAddressAndLoadAmount(lOrderId, NumberConstant.ONE);
//                vo.setLoading(loadAddressAmount);
//                List<UnLoadAddressVo> unloadAddressAmount = logisticsOrderAddressMapper.findByAddressAndUnLoadAmount(lOrderId, NumberConstant.TWO);
//                vo.setUnloading(unloadAddressAmount);
            }
//            returnList = list.stream().skip((contractParam.getPage() - 1) * contractParam.getPageSize()).limit(contractParam.getPageSize()).collect(Collectors.toList());
        }
//        PageResult build = PageResult.build(contractParam.getPage(), contractParam.getPageSize(), list.stream().count(), returnList);
        return HttpResult.ok(PageRes.build(pageInfo, list));
    }

    /**
     * 托运订单（自建、采购、贸易）/承运订单（自建、托运）-完结订单-数据查询展示
     *
     * @param orderId 物流订单id
     * @return 数据
     */
    public HttpResult orderFinishDetail(String orderId) {
        Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN) {{
            put("upperlOrderId", orderId);
            put("passStatus", Global.NUMERICAL_ONE);
        }};
        //WaybillCountVo waybillOrderCount = waybillOrderMapper.findWaybillOrderCount(map);
        OrderFinishVO orderFinishVO = new OrderFinishVO();
        List<OrderGoodsLoadingVo> assistUnit = new ArrayList<>();
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = dict != null ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : null;
        //物流订单
        KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(orderId);
        //物流订单辅助单位信息
        List<KwtLogisticsOrderGoodsUnit> goodsUnits = logisticsOrderGoodsService.findGoodsUnit(logisticsOrder.getId());
        if (CollectionUtils.isNotEmpty(goodsUnits)) {
            goodsUnits.forEach(e -> {
                assistUnit.add(new OrderGoodsLoadingVo(e.getUnit(), unitMap != null ? unitMap.get(e.getUnit()) : null, e.getTotalLoadAmount(), e.getTotalUnloadAmount()));
            });
        }
        List<Integer> orderStatus = new ArrayList<>() {{
            add(CarWaybillEnum.APPROVAL_PASS.getCode());
        }};
//        orderFinishVO.setNumber(waybillOrderCount == null ? NumberConstant.ZERO : waybillOrderCount.getTotalComplete());
        /*orderFinishVO.setNumber(waybillOrderSubtaskMapper.selectCount(
                new LambdaQueryWrapper<KwtWaybillOrderSubtask>()
                        .eq(KwtWaybillOrderSubtask::getLOrderId, Long.parseLong(orderId))
                        .eq(KwtWaybillOrderSubtask::getDelFlag, 0)
                        .in(KwtWaybillOrderSubtask::getStatus, orderStatus)).intValue());*/
        orderFinishVO.setNumber(logisticsOrder.getTotalTake());
        orderFinishVO.setUnit(logisticsOrder.getUnit());
        orderFinishVO.setUnitName(unitMap != null ? unitMap.get(logisticsOrder.getUnit()) : null);
        orderFinishVO.setAmount(logisticsOrder.getAmount());
        orderFinishVO.setLoadAmount(logisticsOrder.getTotalLoadAmount());
        orderFinishVO.setUnloadAmount(logisticsOrder.getTotalUnloadAmount());
        orderFinishVO.setAssistUnit(assistUnit);
        orderFinishVO.setLineFreightRate(lineFreightRateMapper.selectListByOrderId(Long.parseLong(orderId)));
        return HttpResult.ok(orderFinishVO);
    }

    /**
     * @param params 手动完结参数
     * @desc 完结物流订单-采购/销售/托运/承运
     * @author zk
     * @date 2023/12/8
     **/
//    @GlobalTransactional(/*name = "default_tx_group"*/)
    @Transactional
    public HttpResult orderFinish(OrderManualCompletionDto params) {
        /** 订单完结 物流运单状态为【待派车】、【运输中】可操作*/
        /**完结拦截 必须车辆运单无正在运输中的单据才能完结 状态有 待接单之后已核弹之前的状态 都不能完结*/
        /**完结订单-对应物流订单下子订单都要进行完结*/
        /**完结订单 不做页面填写数量与数据库数量进行计算验证-直接获取页面填写数据进行保存处理*/
        Long id = params.getId();
        String key = String.format(RedisConstant.LOGISTICS_ORDER_FINISH_KEY, params.getId());
        if (redisLockUtil.tryLock(key)) {
            try {
                KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(id);
                if (logisticsOrder == null) {
                    throw new BusinessException("采购订单-完结订单-物流单据不存在!");
                }
                /**订单状态验证*/
                if (!LogisticsOrderEnum.WAIT_DELIVERY.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))
                        && !LogisticsOrderEnum.IN_TRANSIT.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))) {
                    throw new BusinessException("当前订单并不属于【待派车】,【运输中】状态");
                }
                //验证当前物流订单是否还存在进行的车辆运单
                boolean flag = commonService.judgmentWaybillOrderIsFinish(String.valueOf(id));
                if (flag) {
                    throw new BusinessException("检测您现在有运单正在执行中，该订单目前不可完结，请先将运单执行完毕！");
                }

                //修改单据本身数据
                BigDecimal loadAmount = getLoading(params, logisticsOrder.getUnit(), NumberConstant.ONE);
                BigDecimal unloadAmount = getLoading(params, logisticsOrder.getUnit(), NumberConstant.TWO);
                BigDecimal ignoreAmount = logisticsOrder.getAmount().subtract(loadAmount == null ? NumberConstant.ZERO_TWO : logisticsOrder.getLoadAmount());
                logisticsOrder.setTotalLoadAmount(loadAmount);
                logisticsOrder.setTotalUnloadAmount(unloadAmount);
                logisticsOrder.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
                logisticsOrder.setUpdateTime(new Date());
                logisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
                logisticsOrder.setIgnoreAmount(ignoreAmount);
                logisticsOrderMapper.updateById(logisticsOrder);
                //物流订单状态记录
                updateLogisticOrderTrack(logisticsOrder.getId(), LogisticsOrderEnum.HAVE_FINISHED.getCode(), params.getRemark(), JSON.toJSONString(params));
                //修改mongodb的数据
                updateMongoDbByLogisticsOrder(logisticsOrder);
                //更新商品辅助单位信息
                logisticsOrderGoodsService.editLogisticsOrderGoodsTotalLoading(params);

                //获取物流订单下的子单
                /**完结订单-对应物流订单下子订单都要进行完结*/
                List<KwtLogisticsOrder> kwtLogisticsOrders = logisticsOrderMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrder>()
                        .eq(KwtLogisticsOrder::getDelFlag, NumberConstant.ZERO)
                        .apply(id != null, "FIND_IN_SET ('" + id + "', pids)").ne(KwtLogisticsOrder::getId, id));
                if (!CollectionUtils.isEmpty(kwtLogisticsOrders)) {
                    //修改单据剩余运输量
                    kwtLogisticsOrders.forEach(kwtLogisticsOrder -> {
                        BigDecimal subtract = kwtLogisticsOrder.getAmount().subtract(kwtLogisticsOrder.getTotalLoadAmount());
                        //更新忽略剩余量
                        updateLogisticOrderAndTrack(kwtLogisticsOrder);
                        //更新Mongodb
                        updateMongoDbByLogisticsOrder(kwtLogisticsOrder);
                    });
                }

                /**是否是一级订单,是->推送至贸易*/
                if (logisticsOrder.getPid() == null && "1".equals(logisticsOrder.getType())) {
                    List<GoodsLoadingV1Param> loadings = new ArrayList<>();
                    List<OrderGoodsLoadingDto> loading = params.getLoading();
                    loading.forEach(e -> {
                        loadings.add(new GoodsLoadingV1Param(e.getUnit(), e.getLoadAmount(), e.getUnloadAmount()));
                    });
                    //数据推送至贸易订单-更新总装卸货量
                    HttpResult httpResult = tradeOrderInfoService.completeLogisticsOrderV1(LoginUserHolder.getUserId(), LoginUserHolder.getUserName(), logisticsOrder.getTOrderId(), loadings);
                    if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                        log.info("贸易订单手动完结订单异常,传递信息:{}{},返回信息:{}", logisticsOrder.getTOrderId(), loadings, JSONObject.toJSONString(httpResult));
                        throw new BusinessException("单据完结出现错误！" + httpResult.getMsg());
                    }

                    //数据推送至贸易订单-更新时间装货量
                    List<GoodsLoadingParam> goodsLoading = logisticsOrderGoodsService.goodsLoadingParams(logisticsOrder, loading);
//                    httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(logisticsOrder.getTOrderId(), goodsLoading);
                    httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(LoginUserHolder.getUserId(), LoginUserHolder.getUserName(), logisticsOrder.getTOrderId(), goodsLoading);
                    if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                        log.info("托运订单手动完结订单-完结订单,传递信息:{},返回信息:{}",
                                "userId:" + LoginUserHolder.getUserId() +
                                        "userName:" + LoginUserHolder.getUserName() +
                                        "id:" + logisticsOrder.getTOrderId() +
                                        "orderNo" + logisticsOrder.getTOrderNo(),
                                JSONObject.toJSONString(httpResult))
                        ;
                        throw new BusinessException("{" + logisticsOrder.getTOrderNo() + "} 托运订单手动完结订单-完结订单!" + httpResult.getMsg());
                    }
                }

                //修改合同履约量
                commonService.updatePerformed(logisticsOrder, loadAmount, unloadAmount);

                //完结物流订单数据处理-上级物流订单分包量计算
                closeHandleByOrderFinish(logisticsOrder.getId());

                //关闭运单
                waybillOrderService.cancelSendCar(logisticsOrder.getId());
            } finally {
                redisLockUtil.unlock(key);
            }
        } else {
            HttpResult.error("当前数据正在处理，请稍后再试");
        }
        return HttpResult.ok("托运订单-完结订单成功");
    }

    /**
     * @param params 完结参数
     * @param unit   单位
     * @param type   装卸货类型
     * @desc 获取装卸货量
     * @author zk
     * @date 2023/9/18
     **/
    public BigDecimal getLoading(OrderManualCompletionDto params, String unit, int type) {
        List<OrderGoodsLoadingDto> loadings = params.getLoading();
        if (CollectionUtils.isNotEmpty(loadings)) {
            for (OrderGoodsLoadingDto loading : loadings) {
                if (loading.getUnit().equals(unit)) {
                    return type == NumberConstant.ONE ? loading.getLoadAmount() : loading.getUnloadAmount();
                }
            }
        }
        return BigDecimal.ZERO;
    }


    /**
     * @param params 完结参数
     * @param unit   单位
     * @param type   装卸货类型
     * @desc 获取装卸货量
     * @author zk
     * @date 2023/9/18
     **/
    public BigDecimal getLoadingV42(LogisticsOrderFinishDto params, String unit, int type) {
        List<OrderGoodsLoadingDto> loadings = params.getLoading();
        if (CollectionUtils.isNotEmpty(loadings)) {
            for (OrderGoodsLoadingDto loading : loadings) {
                if (loading.getUnit().equals(unit)) {
                    return type == NumberConstant.ONE ? loading.getLoadAmount() : loading.getUnloadAmount();
                }
            }
        }
        return BigDecimal.ZERO;
    }

    /**
     * 物流订单完结订单-修改物流表+新增物流状态记录
     *
     * @param params 物流订单
     */
    public void updateLogisticOrderAndTrack(KwtLogisticsOrder params) {
        Integer code = LogisticsOrderEnum.HAVE_FINISHED.getCode();
        logisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                .set(KwtLogisticsOrder::getStatus, code)
                .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                .set(KwtLogisticsOrder::getIgnoreAmount, params.getIgnoreAmount())
                .set(KwtLogisticsOrder::getUpdateTime, new Date())
                .eq(KwtLogisticsOrder::getId, params.getId())
        );

        KwtLogisticsOrderTrack track = logisticsOrderTrackMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderTrack>()
                .eq(KwtLogisticsOrderTrack::getLOrderId, params.getId()).eq(KwtLogisticsOrderTrack::getStatus, code)
        );
        if (track != null) {
            logisticsOrderTrackMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrderTrack>()
                    .set(KwtLogisticsOrderTrack::getUpdateBy, LoginUserHolder.getUserId())
                    .set(KwtLogisticsOrderTrack::getUpdateTime, new Date())
                    .set(KwtLogisticsOrderTrack::getRemark, "手动完结订单。")
                    .eq(KwtLogisticsOrderTrack::getId, track.getId())
            );
        } else {
            KwtLogisticsOrderTrack orderTrack = new KwtLogisticsOrderTrack();
            orderTrack.setId(new IdWorker(NumberConstant.ONE).nextId());
            orderTrack.setLOrderId(params.getId());
            orderTrack.setRemark("手动完结订单。");
            orderTrack.setStatus(code);
            orderTrack.setCreateBy(LoginUserHolder.getUserId());
            orderTrack.setCreateTime(new Date());
            orderTrack.setUpdateBy(LoginUserHolder.getUserId());
            orderTrack.setUpdateTime(new Date());
            orderTrack.setDelFlag(NumberConstant.ZERO);
            logisticsOrderTrackMapper.insert(orderTrack);
        }
    }

    /**
     * 修改物流表+新增物流状态记录
     *
     * @param lOrderId 物流订单
     * @param code     状态码
     * @param remark   备注
     */
    private void updateLogisticOrderTrack(Long lOrderId, int code, String remark, String reserved) {
        KwtLogisticsOrderTrack track = logisticsOrderTrackMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderTrack>()
                .eq(KwtLogisticsOrderTrack::getLOrderId, lOrderId).eq(KwtLogisticsOrderTrack::getStatus, code)
        );
        if (track != null) {
            logisticsOrderTrackMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrderTrack>()
                    .set(KwtLogisticsOrderTrack::getUpdateBy, LoginUserHolder.getUserId())
                    .set(KwtLogisticsOrderTrack::getUpdateTime, new Date())
                    .set(KwtLogisticsOrderTrack::getRemark, remark)
                    .eq(KwtLogisticsOrderTrack::getId, track.getId())
            );
        } else {
            KwtLogisticsOrderTrack orderTrack = new KwtLogisticsOrderTrack();
            orderTrack.setId(new IdWorker(NumberConstant.ONE).nextId());
            orderTrack.setLOrderId(lOrderId);
            orderTrack.setRemark(remark);
            orderTrack.setStatus(code);
            orderTrack.setCreateBy(LoginUserHolder.getUserId());
            orderTrack.setCreateTime(new Date());
            orderTrack.setUpdateBy(LoginUserHolder.getUserId());
            orderTrack.setUpdateTime(new Date());
            orderTrack.setDelFlag(NumberConstant.ZERO);
            orderTrack.setReserved(reserved);
            logisticsOrderTrackMapper.insert(orderTrack);
        }
    }

    /**
     * 根据物流订单修改mongodb数据
     *
     * @param logisticsOrder 物流订单
     */
    private void updateMongoDbByLogisticsOrder(KwtLogisticsOrder logisticsOrder) {
        //更新mongodb
        SckwLogisticsOrder lOrder = new SckwLogisticsOrder();
        lOrder.set_id(logisticsOrder.getId());
        lOrder.setLOrderId(logisticsOrder.getId());
        lOrder.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getStatus());
        lOrder.setUpdateTime(new Date());
        lOrder.setUpdateBy(LoginUserHolder.getUserId());
        lOrder.setUpdateByName(LoginUserHolder.getUserName());
        lOrder.setTotalLoadAmount(logisticsOrder.getTotalLoadAmount());
        lOrder.setTotalUnloadAmount(logisticsOrder.getTotalUnloadAmount());
        lOrder.setIgnoreAmount(logisticsOrder.getIgnoreAmount());

        //rabbitMq业务汇总数据发送/消费对象
        SckwBusSum busSum = new SckwBusSum();
        //业务汇总类型
        busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
        //操作对象（1新增/2修改/3替换数据）
        busSum.setMethod(2);
        //业务汇总数据对象
        busSum.setObject(lOrder);
        busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
        busSum.setMethod(NumberConstant.TWO);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }

    /**
     * @param lOrderId 承运订单ID
     * @desc 完结物流订单数据处理-上级物流订单分包量计算
     * @author zk
     * @date 2023/9/18
     **/
    public void closeHandleByOrderFinish(Long lOrderId) {
        /**1数据校验**/
        KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(lOrderId);
        if (logisticsOrder == null) {
            return;
        }

        /**2物流订单树形数据结构**/
        //所有管理物流订单
        List<KwtLogisticsOrder> orders = logisticsOrderMapper.findLogisticsOrder(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
            put("plOrderIds", lOrderId);
            put("currentlOrderId", logisticsOrder.getPids());
            put("allOrderId", Global.NUMERICAL_ONE);
        }});
        //数据copy
        List<KwtLogisticsOrderTreeVo> logisticsOrders = new ArrayList<>();
        for (KwtLogisticsOrder order : orders) {
            KwtLogisticsOrderTreeVo logisticsOrderVo = new KwtLogisticsOrderTreeVo();
            BeanUtils.copyProperties(order, logisticsOrderVo);
            logisticsOrders.add(logisticsOrderVo);
        }
        List<KwtLogisticsOrderTreeVo> treeData = findTree(logisticsOrders);
        //数据去除已完结订单下级
        orderTreeHandle(treeData);

        /**3链路数据组装*/
        List<List<KwtLogisticsOrderTreeVo>> orderLinks = new ArrayList<>();
        for (KwtLogisticsOrderTreeVo order : treeData) {
            Stack<KwtLogisticsOrderTreeVo> pathStack = new Stack<>();
            iteratorNode(order, pathStack, orderLinks);
        }
        //当前物流订单所在链路
        List<KwtLogisticsOrderTreeVo> orderLink = findLink(orderLinks, lOrderId);
        //倒序
        assert orderLink != null;
        Collections.reverse(orderLink);

        /**4数据处理**/
        for (KwtLogisticsOrderTreeVo order : orderLink) {
            //排除已完结订单
            if (Objects.equals(order.getStatus(), LogisticsOrderEnum.HAVE_FINISHED.getCode())) {
                //上级物流订单分包量技术-排除一级物流订单
                if (order.getPid() != null) {
                    //mysql数据更新
                    KwtLogisticsOrder currentOrder = logisticsOrderMapper.selectById(order.getPid());
                    //差值=上游委托量-实际总装货量
                    BigDecimal difference = order.getAmount().subtract(order.getTotalLoadAmount());
                    currentOrder.setSubcontractAmount(currentOrder.getSubcontractAmount().subtract(difference));

                    //装货统计(当前物流订单)
                    Map<String, Object> queryParams = new HashMap<>(NumberConstant.SIXTEEN);
                    queryParams.put("lOrderId", currentOrder.getId());
                    queryParams.put("unit", currentOrder.getUnit());
                    queryParams.put("type", NumberConstant.ONE);
                    queryParams.put("passStatus", Global.NUMERICAL_ONE);
                    WaybillCountVo loadCount = kwtWaybillOrderV1Mapper.findTicketCountByAddress(queryParams);
                    //卸货统计(当前物流订单)
                    queryParams.put("type", NumberConstant.TWO);
                    WaybillCountVo unloadCount = kwtWaybillOrderV1Mapper.findTicketCountByAddress(queryParams);

                    //下级物流订单统计
                    Map<String, Object> params = new HashMap<>(){{put("upperlOrderId", currentOrder.getId()); put("ownOrderId", currentOrder.getId());}};
                    List<KwtLogisticsOrder> upperlOrders = logisticsOrderMapper.findLogisticsOrder(params);

                    //运量
                    BigDecimal totalLoadAmount = upperlOrders.stream().map(KwtLogisticsOrder::getTotalLoadAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal totalUnloadAmount = upperlOrders.stream().map(KwtLogisticsOrder::getTotalUnloadAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    currentOrder.setTotalLoadAmount(loadCount.getAmount().add(totalLoadAmount));
                    currentOrder.setTotalUnloadAmount(unloadCount.getAmount().add(totalUnloadAmount));

                    //运单数量
                    int sum = upperlOrders.stream().mapToInt(KwtLogisticsOrder::getTotalTake).sum();
                    int totalTake = kwtWaybillOrderV1Mapper.findWaybillOrderCountByLOrderId(currentOrder.getId());
                    currentOrder.setTotalTake(totalTake + sum);
                    logisticsOrderMapper.updateById(currentOrder);

                    //辅助单位运量
                    logisticsOrderGoodsService.editLogisticsOrderGoodsTotalLoading(currentOrder.getId());

                    //Mongodb数据更新
                    SckwLogisticsOrder lOrder = new SckwLogisticsOrder();
                    lOrder.setSubcontractAmount(currentOrder.getSubcontractAmount());
                    lOrder.setTotalUnloadAmount(currentOrder.getTotalUnloadAmount());
                    lOrder.setTotalLoadAmount(currentOrder.getTotalLoadAmount());
                    waybillOrderService.editSckwLogisticsOrder(lOrder, currentOrder);
                }
            }
        }
    }

    /**
     * @param lOrderId 承运订单ID
     * @desc 完结物流订单数据处理
     * @author zk
     * @date 2023/9/18
     **/
    public void closeHandle(Long lOrderId) {
        /**1数据校验**/
        KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(lOrderId);
        if (logisticsOrder == null) {
            return;
        }

        /**2物流订单树形数据结构**/
        //所有管理物流订单
        List<KwtLogisticsOrder> orders = logisticsOrderMapper.findLogisticsOrder(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
            put("plOrderIds", lOrderId);
            put("currentlOrderId", logisticsOrder.getPids());
            put("allOrderId", Global.NUMERICAL_ONE);
        }});
        //数据copy
        List<KwtLogisticsOrderTreeVo> logisticsOrders = new ArrayList<>();
        for (KwtLogisticsOrder order : orders) {
            KwtLogisticsOrderTreeVo logisticsOrderVo = new KwtLogisticsOrderTreeVo();
            BeanUtils.copyProperties(order, logisticsOrderVo);
            logisticsOrders.add(logisticsOrderVo);
        }
        List<KwtLogisticsOrderTreeVo> treeData = findTree(logisticsOrders);
        //数据去除已完结订单下级
        orderTreeHandle(treeData);

        /**3链路数据组装*/
        List<List<KwtLogisticsOrderTreeVo>> orderLinks = new ArrayList<>();
        for (KwtLogisticsOrderTreeVo order : treeData) {
            Stack<KwtLogisticsOrderTreeVo> pathStack = new Stack<>();
            iteratorNode(order, pathStack, orderLinks);
        }
        //当前物流订单所在链路
        List<KwtLogisticsOrderTreeVo> orderLink = findLink(orderLinks, lOrderId);
        //倒序
        assert orderLink != null;
        Collections.reverse(orderLink);

        /**4数据处理**/
        for (KwtLogisticsOrderTreeVo order : orderLink) {
            //排除已完结订单
            if (Objects.equals(order.getStatus(), LogisticsOrderEnum.HAVE_FINISHED.getCode())) {
                //上级物流订单分包量技术-排除一级物流订单
                if (order.getPid() != null) {
                    //mysql数据更新
                    KwtLogisticsOrder currentOrder = logisticsOrderMapper.selectById(order.getPid());
                    //差值=上游委托量-实际总装货量
                    BigDecimal difference = order.getAmount().subtract(order.getTotalLoadAmount());
                    currentOrder.setSubcontractAmount(currentOrder.getSubcontractAmount().subtract(difference));
                    logisticsOrderMapper.updateById(currentOrder);

                    //Mongodb数据更新
                    SckwLogisticsOrder lOrder = new SckwLogisticsOrder();
                    lOrder.setSubcontractAmount(currentOrder.getSubcontractAmount());
                    waybillOrderService.editSckwLogisticsOrder(lOrder, currentOrder);
                }
                continue;
            }

            //车辆运单统计(运输中的物流订单+车辆运单审核通过)
            WaybillCountVo waybillCount = kwtWaybillOrderV1Mapper.findWaybillOrderCount(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                //put("ownOrderId", order.getId());
                put("upperlOrderId", order.getId());
                put("passStatus", Global.NUMERICAL_ONE);
                put("logisticsStatus", LogisticsOrderEnum.IN_TRANSIT.getCode());
            }});
            //物流订单统计(运输完成后的物流订单)
            LogisticsCountVo LogisticsCount = logisticsOrderMapper.findLogisticsOrderCount(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                put("upperlOrderId", order.getId());
                put("finishedStatus", Global.NUMERICAL_ONE);
            }});

            //mysql数据更新
            KwtLogisticsOrder currentOrder = logisticsOrderMapper.selectById(order.getId());
            currentOrder.setTotalLoadAmount(waybillCount.getLoadAmount().add(LogisticsCount.getTotalLoadAmount()));
            currentOrder.setTotalUnloadAmount(waybillCount.getUnloadAmount().add(LogisticsCount.getTotalUnloadAmount()));
            logisticsOrderMapper.updateById(currentOrder);

            //Mongodb数据更新
            SckwLogisticsOrder lOrder = new SckwLogisticsOrder();
            lOrder.setTotalLoadAmount(currentOrder.getTotalLoadAmount());
            lOrder.setTotalUnloadAmount(currentOrder.getTotalUnloadAmount());
            waybillOrderService.editSckwLogisticsOrder(lOrder, currentOrder);

            //一级物流订单向贸易订单推送数据
            if (order.getPid() == null && Integer.parseInt(order.getType()) == Global.NUMERICAL_ONE) {
                //物流订单统计(运输完成后的物流订单)
                LogisticsCountVo tradeCount = logisticsOrderMapper.findLogisticsOrderCount(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                    put("tOrderId", order.getTOrderId());
                    put("level", Global.NUMERICAL_ONE);
                }});
                UpdateActualAmountParam tradeOrder = new UpdateActualAmountParam();
                tradeOrder.setTOrderId(logisticsOrder.getTOrderId());
                tradeOrder.setActualLoadAmount(tradeCount.getTotalLoadAmount());
                tradeOrder.setActualUnloadAmount(tradeCount.getTotalUnloadAmount());
                tradeOrder.setUpdateBy(LoginUserHolder.getUserId());
                tradeOrder.setUpdateByName(LoginUserHolder.getUserName());
                log.info("托运订单手动完结请求参数:{}", JSONObject.toJSONString(tradeOrder));
                HttpResult httpResult = tradeOrderInfoService.updateActualAmount(tradeOrder);
                if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                    log.info("贸易订单手动完结订单异常,传递信息:{},返回信息:{}", JSONObject.toJSONString(tradeOrder), JSONObject.toJSONString(httpResult));
                    throw new BusinessException("单据完结出现错误！" + httpResult.getMsg());
                }
            }
        }
    }

    /**
     * @param treeData 物流订单树形数据
     * @desc 数据去除已完结订单下级
     * @author zk
     * @date 2023/9/18
     **/
    public static void orderTreeHandle(List<KwtLogisticsOrderTreeVo> treeData) {
        if (CollectionUtil.isEmpty(treeData)) {
            return;
        }

        for (KwtLogisticsOrderTreeVo order : treeData) {
            orderTreeHandle(order.getChildren());
            if (order.getStatus() == 4) {
                order.setChildren(null);
            }
        }
    }

    /**
     * @param orders 物流订单
     * @desc 树形数据处理
     * @author zk
     * @date 2023/9/18
     **/
    public static List<KwtLogisticsOrderTreeVo> findTree(List<KwtLogisticsOrderTreeVo> orders) {
        //跟节点
        List<KwtLogisticsOrderTreeVo> rootList = new ArrayList();

        //获取根节点数据
        if (CollectionUtil.isNotEmpty(orders)) {
            for (KwtLogisticsOrderTreeVo order : orders) {
                if (order.getPid() == null) {
                    rootList.add(order);
                }
            }
        }

        //遍历，找到二级节点（根节点的id和所有节点中的pid比较）
        for (KwtLogisticsOrderTreeVo order : rootList) {
            List<KwtLogisticsOrderTreeVo> child = getChild(order.getId(), orders);
            order.setChildren(child);
        }

        return rootList;
    }

    /**
     * @param pid    上级物流订单ID
     * @param orders 物流订单
     * @desc 树形数据处理-递归
     * @author zk
     * @date 2023/9/18
     **/
    public static List<KwtLogisticsOrderTreeVo> getChild(Long pid, List<KwtLogisticsOrderTreeVo> orders) {
        List<KwtLogisticsOrderTreeVo> childList = new ArrayList();
        for (KwtLogisticsOrderTreeVo order : orders) {
            if (pid.equals(order.getPid())) {
                //获取当前节点id的所有子列表
                childList.add(order);
            }
        }
        for (KwtLogisticsOrderTreeVo order : childList) {
            //将该id的子节点进行遍历，通过递归调用，获取每一个子节点的子节点数据
            List<KwtLogisticsOrderTreeVo> child = getChild(order.getId(), orders);
            order.setChildren(child);
        }
        if (childList.size() == 0) {
            //子节点的长度为0,返回null,null不会被阿里的FastJson包解析
            return null;
        }
        return childList;
    }

    /**
     * @param: order 当前节点
     * @param: pathstack 栈
     * @param: orderLinks 设备链路信息
     * @desc 链路组装
     * @author zk
     * @date 2023/8/8
     **/
    public static void iteratorNode(KwtLogisticsOrderTreeVo order, Stack<KwtLogisticsOrderTreeVo> pathstack, List orderLinks) {
        //入栈
        pathstack.push(order);
        List childlist = order.getChildren();
        //没有子节点 说明是叶子结点
        if (childlist == null) {
            List list = new ArrayList();
            Iterator stackIt = pathstack.iterator();
            while (stackIt.hasNext()) {
                list.add(stackIt.next());
            }
            List<KwtLogisticsOrderTreeVo> orders = print(list);
            orderLinks.add(orders);
        } else {
            Iterator iterator = childlist.iterator();
            while (iterator.hasNext()) {
                KwtLogisticsOrderTreeVo child = (KwtLogisticsOrderTreeVo) iterator.next();
                //深度优先 进入递归
                iteratorNode(child, pathstack, orderLinks);
                //回溯时候出栈
                pathstack.pop();
            }
        }
    }

    /**
     * @param list 树形数据
     * @desc 链路组装
     * @author zk
     * @date 2023/8/8
     **/
    private static List<KwtLogisticsOrderTreeVo> print(List list) {
        List<KwtLogisticsOrderTreeVo> orders = new ArrayList();
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            KwtLogisticsOrderTreeVo order = (KwtLogisticsOrderTreeVo) iterator.next();
            order.setChildren(null);
            orders.add(order);
        }
        return orders;
    }

    /**
     * @param orderLinks 物流订单链路信息
     * @param lOrderId   物流订单id
     * @desc 获取当前物流订单垂直链路
     * @author zk
     * @date 2023/9/18
     **/
    public static List<KwtLogisticsOrderTreeVo> findLink(List<List<KwtLogisticsOrderTreeVo>> orderLinks, Long lOrderId) {
        for (List<KwtLogisticsOrderTreeVo> logisticsOrders : orderLinks) {
            for (KwtLogisticsOrderTreeVo order : logisticsOrders) {
                if (Objects.equals(lOrderId, order.getId())) {
                    return logisticsOrders;
                }
            }
        }
        return null;
    }


    /**
     * @param params 手动完结参数
     * @desc 完结物流订单-采购/销售/托运/承运-v4.2
     * @author lfdc
     * @date 2024/03/08
     **/
    @GlobalTransactional
    public HttpResult logisticsOrderFinish(LogisticsOrderFinishDto params) {
        /** 订单完结 物流运单状态为【待派车】、【运输中】可操作*/
        /**完结拦截 必须车辆运单无正在运输中的单据才能完结 状态有 待接单之后已核弹之前的状态 都不能完结*/
        /**完结订单-对应物流订单下子订单都要进行完结*/
        /**完结订单 不做页面填写数量与数据库数量进行计算验证-直接获取页面填写数据进行保存处理*/
        Long id = params.getId();
        String key = String.format(RedisConstant.LOGISTICS_ORDER_FINISH_KEY, params.getId());
        if (redisLockUtil.tryLock(key)) {
            try {
                KwtLogisticsOrder logisticsOrder = logisticsOrderMapper.selectById(id);
                if (logisticsOrder == null) {
                    throw new BusinessException("完结订单-物流单据不存在!");
                }
                String billingMode = logisticsOrder.getBillingMode();
                if (DictEnum.CHARGING_TYPE_4.getValue().equals(billingMode)) {
                    List<LogisticsOrderLineFreightRateDto> lineFreightRate = params.getLineFreightRate();
                    if (CollectionUtils.isEmpty(lineFreightRate)) {
                        throw new BusinessException("按里程计费时,数量不能为空");
                    }
                }
                /**订单状态验证*/
                if (!LogisticsOrderEnum.WAIT_DELIVERY.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))
                        && !LogisticsOrderEnum.IN_TRANSIT.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))) {
                    throw new BusinessException("当前订单并不属于【待派车】,【运输中】状态");
                }
                //验证当前物流订单是否还存在进行的车辆运单
                boolean flag = commonService.judgmentWaybillOrderIsFinish(String.valueOf(id));
                if (flag) {
                    throw new BusinessException("检测您现在有运单正在执行中，该订单目前不可完结，请先将运单执行完毕！");
                }

                //修改单据本身数据
                BigDecimal loadAmount = getLoadingV42(params, logisticsOrder.getUnit(), NumberConstant.ONE);
                BigDecimal unloadAmount = getLoadingV42(params, logisticsOrder.getUnit(), NumberConstant.TWO);
                BigDecimal ignoreAmount = logisticsOrder.getAmount().subtract(loadAmount == null ? NumberConstant.ZERO_TWO : logisticsOrder.getLoadAmount());
                logisticsOrder.setTotalLoadAmount(loadAmount);
                logisticsOrder.setTotalUnloadAmount(unloadAmount);
                logisticsOrder.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
                logisticsOrder.setUpdateTime(new Date());
                logisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
                logisticsOrder.setIgnoreAmount(ignoreAmount);
                logisticsOrder.setTotalTake(params.getCount() != null ? params.getCount() : logisticsOrder.getTotalTake());
                if (DictEnum.CHARGING_TYPE_4.getValue().equals(logisticsOrder.getBillingMode())) {
                    updateLogisticsOrderLineFreightRate(logisticsOrder, params);
                }
                logisticsOrderMapper.updateById(logisticsOrder);
                //物流订单状态记录
                updateLogisticOrderTrack(logisticsOrder.getId(), LogisticsOrderEnum.HAVE_FINISHED.getCode(), params.getRemark(), JSON.toJSONString(params));
                //修改mongodb的数据
                updateMongoDbByLogisticsOrder(logisticsOrder);
                //更新商品辅助单位信息
                logisticsOrderGoodsService.editLogisticsOrderGoodsTotalLoadingV42(params);

                //获取物流订单下的子单
                /**完结订单-对应物流订单下子订单都要进行完结*/
                List<KwtLogisticsOrder> kwtLogisticsOrders = logisticsOrderMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrder>()
                        .eq(KwtLogisticsOrder::getDelFlag, NumberConstant.ZERO)
                        .apply(id != null, "FIND_IN_SET ('" + id + "', pids)").ne(KwtLogisticsOrder::getId, id));
                if (!CollectionUtils.isEmpty(kwtLogisticsOrders)) {
                    //修改单据剩余运输量
                    kwtLogisticsOrders.forEach(kwtLogisticsOrder -> {
                        BigDecimal subtract = kwtLogisticsOrder.getAmount().subtract(kwtLogisticsOrder.getTotalLoadAmount());
                        //更新忽略剩余量
                        updateLogisticOrderAndTrack(kwtLogisticsOrder);
                        //更新Mongodb
                        updateMongoDbByLogisticsOrder(kwtLogisticsOrder);
                    });
                }

                /**是否是一级订单,是->推送至贸易*/
                if (logisticsOrder.getPid() == null && "1".equals(logisticsOrder.getType())) {
                    //todo: 原来逻辑

                    List<GoodsLoadingV1Param> loadings = new ArrayList<>();
                    List<OrderGoodsLoadingDto> loading = params.getLoading();
                    loading.forEach(e -> {
                        loadings.add(new GoodsLoadingV1Param(e.getUnit(), e.getLoadAmount(), e.getUnloadAmount()));
                    });
                    //数据推送至贸易订单-更新总装卸货量
                    HttpResult httpResult = tradeOrderInfoService.completeLogisticsOrderV1(LoginUserHolder.getUserId(), LoginUserHolder.getUserName(), logisticsOrder.getTOrderId(), loadings);
                    if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                        log.info("贸易订单手动完结订单异常,传递信息:{}{},返回信息:{}", logisticsOrder.getTOrderId(), loadings, JSONObject.toJSONString(httpResult));
                        throw new BusinessException("单据完结出现错误！" + httpResult.getMsg());
                    }

                    //数据推送至贸易订单-更新时间装货量
                    List<GoodsLoadingParam> goodsLoading = logisticsOrderGoodsService.goodsLoadingParams(logisticsOrder, loading);
//                    httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(logisticsOrder.getTOrderId(), goodsLoading);
                    httpResult = tradeOrderInfoService.createOrCancelLogisticsOrderV1(LoginUserHolder.getUserId(), LoginUserHolder.getUserName(), logisticsOrder.getTOrderId(), goodsLoading);
                    if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                        log.info("手动完结订单-完结订单,传递信息:{},返回信息:{}",
                                "userId:" + LoginUserHolder.getUserId() +
                                        "userName:" + LoginUserHolder.getUserName() +
                                        "id:" + logisticsOrder.getTOrderId() +
                                        "orderNo" + logisticsOrder.getTOrderNo(),
                                JSONObject.toJSONString(httpResult))
                        ;
                        throw new BusinessException("{" + logisticsOrder.getTOrderNo() + "} 手动完结订单-完结订单!" + httpResult.getMsg());
                    }
                    //todo：新的逻辑 多装多卸
                    updateTradeOrderAddressAmount(logisticsOrder);
                }

                //修改合同履约量
                commonService.updatePerformed(logisticsOrder, loadAmount, unloadAmount);

                //完结物流订单数据处理-上级物流订单量计算
                closeHandleByOrderFinish(logisticsOrder.getId());

                //关闭运单
                waybillOrderService.cancelSendCar(logisticsOrder.getId());
            } finally {
                redisLockUtil.unlock(key);
            }
        } else {
            HttpResult.error("当前数据正在处理，请稍后再试");
        }
        return HttpResult.ok("托运订单-完结订单成功");
    }

    /**
     * 修改线路数据
     *
     * @param logisticsOrder
     * @param params
     */
    private void updateLogisticsOrderLineFreightRate(KwtLogisticsOrder logisticsOrder, LogisticsOrderFinishDto params) {
        Long orderId = logisticsOrder.getId();
        List<LogisticsOrderLineFreightRateDto> lineFreightRate = params.getLineFreightRate();
        lineFreightRate.forEach(dto -> {
            Long lineFreightRateId = dto.getLineFreightId();
            KwtLogisticsOrderLineFreightRate orderLineFreightRate = lineFreightRateMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrderLineFreightRate>()
                    .eq(KwtLogisticsOrderLineFreightRate::getLOrderId, orderId)
                    .eq(KwtLogisticsOrderLineFreightRate::getLineFreightRateId, lineFreightRateId)
            );
            if (orderLineFreightRate != null) {
                orderLineFreightRate.setSettlementAmount(dto.getAmount());
                lineFreightRateMapper.updateById(orderLineFreightRate);
            }
        });
    }

    private void updateTradeOrderAddressAmount(KwtLogisticsOrder logisticsOrder) {
        Long tOrderId = logisticsOrder.getTOrderId();
        if (!Objects.isNull(tOrderId)) {
            List<KwtLogisticsOrderAddress> logisticsOrderAddressList = logisticsOrderAddressMapper.selectList(
                    new LambdaQueryWrapper<KwtLogisticsOrderAddress>()
                            .eq(KwtLogisticsOrderAddress::getLOrderId, logisticsOrder.getId()));
            if (CollectionUtils.isNotEmpty(logisticsOrderAddressList)) {
                Map<Integer, List<KwtLogisticsOrderAddress>> map = logisticsOrderAddressList.stream()
                        .collect(Collectors.groupingBy(KwtLogisticsOrderAddress::getAddressType));

                List<KwtLogisticsOrderAddress> loadingLogisticsOrderAddresses = map.get(NumberConstant.ONE);
                List<Long> loadAddressIds = loadingLogisticsOrderAddresses.stream().map(KwtLogisticsOrderAddress::getId).collect(Collectors.toList());
                List<KwtLogisticsOrderAmount> kwtLogisticsOrderAmounts = logisticsOrderAmountMapper.selectList(
                        new LambdaQueryWrapper<KwtLogisticsOrderAmount>()
                                .eq(KwtLogisticsOrderAmount::getLOrderId, logisticsOrder.getId())
                                .eq(KwtLogisticsOrderAmount::getDelFlag, NumberConstant.ZERO)
                                .in(KwtLogisticsOrderAmount::getLAddressId, loadAddressIds)
                );
                //总装货量
                BigDecimal resultLoadAmount = new BigDecimal("0.00");
                if (CollectionUtils.isNotEmpty(kwtLogisticsOrderAmounts)) {
                    resultLoadAmount = kwtLogisticsOrderAmounts.stream()
                            .map(KwtLogisticsOrderAmount::getTotalLoadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                List<KwtLogisticsOrderAddress> unloadLogisticsOrderAddresses = map.get(NumberConstant.TWO);
                List<Long> unloadAddressIds = unloadLogisticsOrderAddresses.stream().map(KwtLogisticsOrderAddress::getId).collect(Collectors.toList());
                List<KwtLogisticsOrderAmount> unloadLogisticsOrderAmounts = logisticsOrderAmountMapper.selectList(
                        new LambdaQueryWrapper<KwtLogisticsOrderAmount>()
                                .eq(KwtLogisticsOrderAmount::getLOrderId, logisticsOrder.getId())
                                .eq(KwtLogisticsOrderAmount::getDelFlag, NumberConstant.ZERO)
                                .in(KwtLogisticsOrderAmount::getLAddressId, unloadAddressIds)
                );
                //总卸货量
                BigDecimal resultUnLoadAmount = new BigDecimal("0.00");
                if (CollectionUtils.isNotEmpty(unloadLogisticsOrderAmounts)) {
                    resultUnLoadAmount = kwtLogisticsOrderAmounts.stream()
                            .map(KwtLogisticsOrderAmount::getTotalLoadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                //对应地址id装货量+卸货量
                List<LogisticsOrderFinishAmountVo> loadAddressAmount = logisticsOrderAmountMapper.countAddressAmount(logisticsOrder.getId(), NumberConstant.ONE);
                List<LogisticsOrderFinishAmountVo> unloadAddressAmount = logisticsOrderAmountMapper.countAddressAmount(logisticsOrder.getId(), NumberConstant.TWO);
                List<AddressActualAmountParam> paramList = new ArrayList<>();
                loadAddressAmount.forEach(addressAmount -> {
                    Long tOrderAddressId = addressAmount.getTOrderAddressId();
                    BigDecimal countLoadAmount = addressAmount.getLoadAmount();
                    AddressActualAmountParam amountParam = new AddressActualAmountParam();
                    amountParam.setTAddressId(tOrderAddressId);
                    amountParam.setActualAmount(countLoadAmount);
                    paramList.add(amountParam);
                });
                unloadAddressAmount.forEach(addressAmount -> {
                    Long tOrderAddressId = addressAmount.getTOrderAddressId();
                    BigDecimal countUnloadAmount = addressAmount.getUnloadAmount();
                    AddressActualAmountParam amountParam = new AddressActualAmountParam();
                    amountParam.setTAddressId(tOrderAddressId);
                    amountParam.setActualAmount(countUnloadAmount);
                    paramList.add(amountParam);
                });
                if (paramList.size() > 0) {
                    UpdateAddressActualAmountParam param = new UpdateAddressActualAmountParam();
                    param.setTOrderId(tOrderId);
                    param.setUpdateBy(LoginUserHolder.getUserId());
                    param.setUpdateByName(LoginUserHolder.getUserName());
                    param.setAddressActualAmountParams(paramList);
                    tradeOrderAmountService.updateAddressActualAmount(param);
                } else {
                    log.info("完结订单--返回上游贸易订单地址数据异常---> lOrderId:{},tOrderId:{},tOrderNo:{}",
                            logisticsOrder.getId(), logisticsOrder.getTOrderId(), logisticsOrder.getTOrderNo());
                }
            }
        }

    }

    /**
     * 查询物流订单托运/承运企业
     */
    public List<LogisticsOrderUnitResp> queryOrderUnits() {
        log.info("查询物流订单托运/承运企业");
        Long entId = LoginUserHolder.getEntId();
        //根据企业查询物流订单
        List<KwtLogisticsOrderUnit> kwtLogisticsOrderUnits = logisticsOrderUnitRepository.queryByEntId(entId);
        if (CollectionUtils.isEmpty(kwtLogisticsOrderUnits)){
            return List.of();

        }
        List<Long> logIds = kwtLogisticsOrderUnits.stream()
                .map(KwtLogisticsOrderUnit::getLOrderId)
                .distinct()
                .collect(Collectors.toList());
        List<KwtLogisticsOrderUnit> units =logisticsOrderUnitRepository.queryByLOrderIds(logIds);
        if (CollectionUtils.isEmpty(units)){
            return List.of();
        }
        //

        return units.stream()
                .collect(Collectors.toMap(
                        unit -> unit.getEntId() + "_" + unit.getUnitType(),
                        unit -> unit,
                        (existing, replacement) -> existing,
                        LinkedHashMap::new))
                .values()
                .stream()
                .map(KwtTransportCommonService::getLogisticsOrderUnitResp)
                .collect(Collectors.toList());
    }

    @NotNull
    private static LogisticsOrderUnitResp getLogisticsOrderUnitResp(KwtLogisticsOrderUnit u) {
        LogisticsOrderUnitResp resp = new LogisticsOrderUnitResp();
        resp.setId(u.getId());
        resp.setLOrderId(u.getLOrderId());
        resp.setUnitType(u.getUnitType());
        resp.setTopEntId(u.getTopEntId());
        resp.setEntId(u.getEntId());
        resp.setFirmName(u.getFirmName());
        resp.setContactsId(u.getContactsId());
        resp.setContacts(u.getContacts());
        resp.setPhone(u.getPhone());
        resp.setRemark(u.getRemark());
        return resp;
    }
}
