package com.sckw.contract.service.operateService;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
import com.sckw.contract.dao.KwcContractLogisticsMapper;
import com.sckw.contract.model.dto.req.QueryListReqDto;
import com.sckw.contract.model.dto.res.QueryListResDto;
import com.sckw.contract.model.entity.KwcContractLogistics;
import com.sckw.contract.model.entity.KwcContractLogisticsGoods;
import com.sckw.contract.model.entity.KwcContractLogisticsUnit;
import com.sckw.contract.model.entity.KwcContractTrade;
import com.sckw.contract.model.enums.LogisticsTransportBizTypeEnum;
import com.sckw.contract.model.report.LogisticsListExport;
import com.sckw.contract.model.vo.req.*;
import com.sckw.contract.model.vo.res.*;
import com.sckw.contract.repository.KwcContractLogisticsGoodsRepository;
import com.sckw.contract.repository.KwcContractLogisticsRepository;
import com.sckw.contract.repository.KwcContractLogisticsUnitRepository;
import com.sckw.contract.repository.KwcContractTradeRepository;
import com.sckw.contract.service.*;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.DispatchingTypeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.SystemException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.*;
import com.sckw.core.model.page.PageHelperUtil;
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.BaseResult;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.excel.utils.ExcelUtil;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.TradeOrderContractVo;
import com.sckw.payment.api.feign.PaymentFeignService;
import com.sckw.payment.api.model.feign.WalletPayableDto;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.UserInfo;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.feign.DataPermissionFeignService;
import com.sckw.system.api.model.dto.req.DataPermissionFilterReqDto;
import com.sckw.system.api.model.dto.res.*;
import com.sckw.transport.api.dubbo.TransportRemoteService;
import com.sckw.transport.api.model.vo.KwtLogisticsOrderVO;
import com.sckw.transport.api.model.vo.RWaybillSubOrderVo;
import com.sckw.transport.api.model.vo.WayContaractbillOrderVo;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author PC
 * @description 针对表【kwc_contract_logistics(物流合同（承运合同/托运合同）)】的数据库操作Service实现
 * @createDate 2023-07-13 13:36:19
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class KwcContractLogisticsService {

    @Autowired
    private KwcContractLogisticsMapper kwcContractLogisticsMapper;

    @Autowired
    private KwcContractLogisticsGoodsService kwcContractLogisticsGoodsService;

    @Autowired
    private KwcContractLogisticsTrackService kwcContractLogisticsTrackService;

    @Autowired
    private KwcContractLogisticsUnitService kwcContractLogisticsUnitService;

    @Autowired
    private CommonBusinessService commonBusinessService;

    @Autowired
    private IKwcContractLogisticsScoreService logisticsScoreService;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private PaymentFeignService paymentFeignService;

    private final KwcContractLogisticsRepository kwcContractLogisticsRepository;
    private final KwcContractLogisticsUnitRepository kwcContractLogisticsUnitRepository;
    private final KwcContractLogisticsGoodsRepository kwcContractLogisticsGoodsRepository;
    private final KwcContractTradeRepository kwcContractTradeRepository;
    private final DataPermissionFeignService dataPermissionFeignService;

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

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

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

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

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

    //销售合同
    @Value(value = "${jumpUrl.saleSendContract}")
    private String saleSendContract;

    //采购合同
    @Value(value = "${jumpUrl.purchaseSendContract}")
    private String purchaseSendContract;

    //托运合同
    @Value(value = "${jumpUrl.consignmentSendContract}")
    private String consignmentSendContract;

    //承运合同
    @Value(value = "${jumpUrl.acceptanceSendContract}")
    private String acceptanceSendContract;

    //app销售合同
    @Value(value = "${jumpUrl.appSaleSendContract}")
    private String appSaleSendContract;

    //app采购合同
    @Value(value = "${jumpUrl.appPurchaseSendContract}")
    private String appPurchaseSendContract;

    //app托运合同
    @Value(value = "${jumpUrl.appConsignmentSendContract}")
    private String appConsignmentSendContract;

    //app承运合同
    @Value(value = "${jumpUrl.appAcceptanceSendContract}")
    private String appAcceptanceSendContract;

    /**
     * @param reqVo 新增入参
     * @desc: 新增托运合同
     * @author: czh
     * @date: 2023/7/13
     */
    @Transactional(rollbackFor = {})
    public Long addCheckedContract(ContractLogisticsReqVo reqVo) {
        LogisticsBaseInfoReqVo baseInfo = reqVo.getBaseInfo();
        List<LogisticsGoodsInfoReqVo> goodsInfo = reqVo.getGoodsInfo();
        //参数校验
        checkParam(baseInfo, goodsInfo);
        Long id = reqVo.getId();
        //不为空时是修改
        if (Objects.nonNull(id)) {
            update(reqVo);
            return id;
        }
        //合同编号+企业双方判定唯一
        String contractCode = baseInfo.getContractCode();
        String key = contractCode + baseInfo.getCarrierEntId() + baseInfo.getCheckedEntId();
        List<String> isSoleKey = kwcContractLogisticsMapper.checkContractIsSole(contractCode, baseInfo.getCarrierEntId(), baseInfo.getCheckedEntId());
        if (isSoleKey.size() > 0) {
            if (isSoleKey.contains(key)) {
                throw new BusinessException("新增合同时,合同编号一致时,双方已存在合同,不可重复创建!");
            }
        }
        //创建合同
        KwcContractLogistics kwcContractLogistics = getKwcContractLogistics(baseInfo, goodsInfo, reqVo.getRemark(), reqVo.getPid());
        long contactId = new IdWorker(1L).nextId();
        kwcContractLogistics.setId(contactId);
        kwcContractLogistics.setStatus(ContractStatusEnum.SAVE.getCode());
        String contractFile = reqVo.getContractFile();
        if (StringUtils.isNotBlank(contractFile)) {
            JSONArray jsonArray = JSONArray.parseArray(contractFile);
            for (int n = 0; n < jsonArray.size(); n++) {
                JSONObject jsonObject = jsonArray.getJSONObject(n);
                String url = jsonObject.getString("url");
                jsonObject.put("url", FileUtils.replaceAll(url));
            }
            kwcContractLogistics.setSigningUrl(JSON.toJSONString(jsonArray));
        }

        if (kwcContractLogisticsMapper.insert(kwcContractLogistics) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
        }

        //保存交易合同商品信息
        kwcContractLogisticsGoodsService.saveContractLogisticsGoods(kwcContractLogistics.getId(), goodsInfo);

        //存单位信息
        kwcContractLogisticsUnitService.saveContractLogisticsUnit(kwcContractLogistics.getId(), baseInfo);
        return contactId;
    }

    private void checkParam(LogisticsBaseInfoReqVo baseInfo, List<LogisticsGoodsInfoReqVo> goodsInfo) {
        if (Objects.nonNull(baseInfo)) {
//            if (StringUtils.isNotBlank(baseInfo.getContractCode()) && baseInfo.getContractCode().length() > 20) {
//                throw new SystemException("合同编号超长！");
//            }
//
//            if (StringUtils.isNotBlank(baseInfo.getContractName()) && baseInfo.getContractName().length() > 20) {
//                throw new SystemException("合同名称超长！");
//            }
        }

        if (CollectionUtils.isNotEmpty(goodsInfo)) {
            for (LogisticsGoodsInfoReqVo logisticsGoodsInfoReqVo : goodsInfo) {
                if (StringUtils.isNotBlank(logisticsGoodsInfoReqVo.getGoodsName()) && logisticsGoodsInfoReqVo.getGoodsName().length() > 50) {
                    throw new SystemException("商品名称超长！");
                }

                if (Objects.nonNull(logisticsGoodsInfoReqVo.getLoss()) && !RegularUtils.matchNumberWithFix(logisticsGoodsInfoReqVo.getLoss().toString(), 5, 2)) {
                    throw new SystemException("合理损耗超长！");
                }

                if (Objects.nonNull(logisticsGoodsInfoReqVo.getDeficitPrice()) && !RegularUtils.matchNumberWithFix(logisticsGoodsInfoReqVo.getDeficitPrice().toString(), 5, 2)) {
                    throw new SystemException("扣亏货值超长！");
                }
            }
        }
    }

    public KwcContractLogistics getKwcContractLogistics(LogisticsBaseInfoReqVo baseInfo, List<LogisticsGoodsInfoReqVo> goodsInfo, String remark, Long pid) {
        Date date = new Date();
        KwcContractLogistics kwcContractLogistics = new KwcContractLogistics();
        kwcContractLogistics.setEntId(LoginUserHolder.getEntId());
        kwcContractLogistics.setContractNo(baseInfo.getContractCode());
        kwcContractLogistics.setName(baseInfo.getContractName());
        kwcContractLogistics.setSigningWay(baseInfo.getSigningWay());
        kwcContractLogistics.setCharging(baseInfo.getCharging());
        kwcContractLogistics.setStartTime(baseInfo.getStartTime());
        if (Objects.nonNull(baseInfo.getEndTime())) {
            kwcContractLogistics.setEndTime(DateUtils.getEndOfDay(baseInfo.getEndTime()));
        }
        kwcContractLogistics.setPerformedAmount(new BigDecimal("0"));
        kwcContractLogistics.setContractPid(pid);
        kwcContractLogistics.setRemark(remark);
        kwcContractLogistics.setDelFlag(Global.NO);
        kwcContractLogistics.setCreateBy(LoginUserHolder.getUserId());
        kwcContractLogistics.setCreateTime(date);
        kwcContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
        kwcContractLogistics.setUpdateTime(date);
        BigDecimal amountTotal = new BigDecimal(Global.NUMERICAL_ZERO);
        if (CollectionUtils.isNotEmpty(goodsInfo)) {
            for (LogisticsGoodsInfoReqVo logisticsGoodsInfoReqVo : goodsInfo) {
                if (Objects.nonNull(logisticsGoodsInfoReqVo.getAmount())) {
                    amountTotal = amountTotal.add(logisticsGoodsInfoReqVo.getAmount());
                }
            }
        }
        kwcContractLogistics.setAmount(amountTotal);
        return kwcContractLogistics;
    }


    /**
     * @param reqVo 补充入参
     * @desc: 补充合同
     * @author: czh
     * @date: 2023/7/14
     */
    public void supplement(ContractLogisticsReqVo reqVo) {
        Long id = reqVo.getPid();
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(id);
        if (Objects.isNull(kwcContractLogistics)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.CONTRACT_NOT_EXISTS);
        }

        //补充合同直接
        submit(reqVo);
//        addCheckedContract(reqVo);
    }

    /**
     * @param id 主键
     * @return ContractLogisticsDetailResVo
     * @desc 合同详情
     * @author czh
     * @date 2023/7/16
     */
    public ContractLogisticsDetailResVo detail(Long id) {
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(id);
        if (Objects.isNull(kwcContractLogistics)) {
            return null;
        }

        return buildContractLogisticsDetailResVo(kwcContractLogistics);
    }


    private ContractLogisticsDetailResVo buildContractLogisticsDetailResVo(KwcContractLogistics kwcContractLogistics) {
        ContractLogisticsDetailResVo contractLogisticsDetailResVo = new ContractLogisticsDetailResVo();
        contractLogisticsDetailResVo.setId(kwcContractLogistics.getId());
        contractLogisticsDetailResVo.setRemark(kwcContractLogistics.getRemark());
        contractLogisticsDetailResVo.setStatus(kwcContractLogistics.getStatus());
        contractLogisticsDetailResVo.setStatusName(Objects.requireNonNull(ContractStatusEnum.getName(kwcContractLogistics.getStatus())).getName());
        //基础信息
        List<KwcContractLogisticsUnit> kwcContractLogisticsUnitList = kwcContractLogisticsUnitService.queryByContractId(kwcContractLogistics.getId());
        if (CollectionUtils.isNotEmpty(kwcContractLogisticsUnitList)) {
            LogisticsBaseInfoResVo logisticsBaseInfoResVo = new LogisticsBaseInfoResVo();
            for (KwcContractLogisticsUnit kwcContractLogisticsUnit : kwcContractLogisticsUnitList) {
                if (kwcContractLogisticsUnit.getUnitType().equals(CooperateTypeEnum.CONSIGN.getCode())) {
                    logisticsBaseInfoResVo.setCheckedEntName(kwcContractLogisticsUnit.getFirmName());
                    logisticsBaseInfoResVo.setCheckedPhone(kwcContractLogisticsUnit.getSignPhone());
                    logisticsBaseInfoResVo.setCheckedContacts(kwcContractLogisticsUnit.getContacts());
                    logisticsBaseInfoResVo.setCheckedEntId(kwcContractLogisticsUnit.getEntId());
                }

                if (kwcContractLogisticsUnit.getUnitType().equals(CooperateTypeEnum.CARRIAGE.getCode())) {
                    logisticsBaseInfoResVo.setCarrierEntName(kwcContractLogisticsUnit.getFirmName());
                    logisticsBaseInfoResVo.setCarrierPhone(kwcContractLogisticsUnit.getSignPhone());
                    logisticsBaseInfoResVo.setCarrierContacts(kwcContractLogisticsUnit.getContacts());
                    logisticsBaseInfoResVo.setCarrierEntId(kwcContractLogisticsUnit.getEntId());
                }
            }

            logisticsBaseInfoResVo.setChargingName(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), String.valueOf(kwcContractLogistics.getCharging())));
            logisticsBaseInfoResVo.setCharging(StringUtils.objectStr(kwcContractLogistics.getCharging()));
            logisticsBaseInfoResVo.setContractCode(kwcContractLogistics.getContractNo());
            logisticsBaseInfoResVo.setContractName(kwcContractLogistics.getName());
            logisticsBaseInfoResVo.setEndTime(Objects.isNull(kwcContractLogistics.getEndTime()) ? Global.EMPTY_STRING : DateUtils.format(kwcContractLogistics.getEndTime()));
            logisticsBaseInfoResVo.setSigningWayName(DictEnum.getLabel(DictTypeEnum.SIGNING_TYPE.getType(), String.valueOf(kwcContractLogistics.getSigningWay())));
            logisticsBaseInfoResVo.setSigningWay(StringUtils.objectStr(kwcContractLogistics.getSigningWay()));
            logisticsBaseInfoResVo.setStartTime(kwcContractLogistics.getStartTime());
            logisticsBaseInfoResVo.setAmount(kwcContractLogistics.getAmount());
            logisticsBaseInfoResVo.setPerformedAmount(kwcContractLogistics.getPerformedAmount());
            contractLogisticsDetailResVo.setBaseInfo(logisticsBaseInfoResVo);
        }

        //标的信息
        List<KwcContractLogisticsGoods> kwcContractLogisticsGoodsList = kwcContractLogisticsGoodsService.queryGoodsInfoByContractId(kwcContractLogistics.getId());
        if (CollectionUtils.isNotEmpty(kwcContractLogisticsGoodsList)) {
            StringBuilder keys = new StringBuilder();
            for (KwcContractLogisticsGoods item : kwcContractLogisticsGoodsList) {
                keys.append(DictTypeEnum.UNIT_TYPE.getType()).append(Global.POUND).append(item.getUnit()).append(Global.COMMA);
                keys.append(DictTypeEnum.PRICE_TYPE.getType()).append(Global.POUND).append(item.getPriceUnit()).append(Global.COMMA);
                keys.append(DictTypeEnum.WEIGHT_CAR.getType()).append(Global.POUND).append(item.getLossUnit()).append(Global.COMMA);
                keys.append(DictTypeEnum.WEIGHT_CAR.getType()).append(Global.POUND).append(item.getDeficitUnit()).append(Global.COMMA);
            }

            Map<String, SysDictResDto> stringSysDictResDtoMap = remoteSystemService.queryDictMapByTypeValues(keys.toString());

            List<LogisticsGoodsInfoResVo> goodsInfo = new ArrayList<>();
            for (KwcContractLogisticsGoods kwcContractLogisticsGoods : kwcContractLogisticsGoodsList) {
                LogisticsGoodsInfoResVo logisticsGoodsInfoResVo = new LogisticsGoodsInfoResVo();
                logisticsGoodsInfoResVo.setAmount(kwcContractLogisticsGoods.getAmount());
                logisticsGoodsInfoResVo.setUnit(kwcContractLogisticsGoods.getUnit());
                logisticsGoodsInfoResVo.setPrice(kwcContractLogisticsGoods.getPrice());
                logisticsGoodsInfoResVo.setPriceUnit(kwcContractLogisticsGoods.getPriceUnit());
                logisticsGoodsInfoResVo.setDeficitPrice(kwcContractLogisticsGoods.getDeficitPrice());
                logisticsGoodsInfoResVo.setDeficitUnit(kwcContractLogisticsGoods.getDeficitUnit());
                logisticsGoodsInfoResVo.setGoodsId(kwcContractLogisticsGoods.getGoodsId());
                logisticsGoodsInfoResVo.setId(kwcContractLogisticsGoods.getId());
                logisticsGoodsInfoResVo.setGoodsName(kwcContractLogisticsGoods.getGoodsName());
                logisticsGoodsInfoResVo.setLoss(kwcContractLogisticsGoods.getLoss());
                logisticsGoodsInfoResVo.setLossUnit(kwcContractLogisticsGoods.getLossUnit());


                SysDictResDto unitType = stringSysDictResDtoMap.get(DictTypeEnum.UNIT_TYPE.getType() + Global.POUND + kwcContractLogisticsGoods.getUnit());
                if (Objects.nonNull(unitType)) {
                    logisticsGoodsInfoResVo.setUnitName(unitType.getLabel());
                }

                SysDictResDto priceType = stringSysDictResDtoMap.get(DictTypeEnum.PRICE_TYPE.getType() + Global.POUND + kwcContractLogisticsGoods.getPriceUnit());
                if (Objects.nonNull(priceType)) {
                    logisticsGoodsInfoResVo.setPriceUnitName(priceType.getLabel());
                }

                SysDictResDto weightCar1 = stringSysDictResDtoMap.get(DictTypeEnum.WEIGHT_CAR.getType() + Global.POUND + kwcContractLogisticsGoods.getLossUnit());
                if (Objects.nonNull(weightCar1)) {
                    logisticsGoodsInfoResVo.setLossUnitName(weightCar1.getLabel());
                }

                SysDictResDto weightCar2 = stringSysDictResDtoMap.get(DictTypeEnum.WEIGHT_CAR.getType() + Global.POUND + kwcContractLogisticsGoods.getDeficitUnit());
                if (Objects.nonNull(weightCar2)) {
                    logisticsGoodsInfoResVo.setDeficitUnitName(weightCar2.getLabel());
                }

                goodsInfo.add(logisticsGoodsInfoResVo);
            }
            contractLogisticsDetailResVo.setGoodsInfo(goodsInfo);
        }

        //合同文件
        List<String> fileList = new ArrayList<>();
        String signedUrl = kwcContractLogistics.getSignedUrl();
        if (StringUtils.isNotBlank(signedUrl)) {
            JSONArray jsonArray = JSONArray.parseArray(signedUrl);
            for (int n = 0; n < jsonArray.size(); n++) {
                JSONObject jsonObject = jsonArray.getJSONObject(n);
                String url = jsonObject.getString("url");
                jsonObject.put("url", FileUtils.splice(url));
            }
            fileList.add(JSON.toJSONString(jsonArray));
        }

        String signingUrl = kwcContractLogistics.getSigningUrl();
        if (StringUtils.isNotBlank(signingUrl)) {
            JSONArray jsonArray = JSONArray.parseArray(signingUrl);
            for (int n = 0; n < jsonArray.size(); n++) {
                JSONObject jsonObject = jsonArray.getJSONObject(n);
                String url = jsonObject.getString("url");
                jsonObject.put("url", FileUtils.splice(url));
            }
            fileList.add(JSON.toJSONString(jsonArray));
        }
        contractLogisticsDetailResVo.setContractFile(fileList.stream().filter(StringUtils::isNotBlank).toList());

        //审批流程信息
        contractLogisticsDetailResVo.setTrackInfo(kwcContractLogisticsTrackService.queryContractTrackByContractId(kwcContractLogistics.getId()));

        //补充合同
        List<KwcContractLogistics> supplementList = getSupplementList(kwcContractLogistics);
        if (CollectionUtils.isNotEmpty(supplementList)) {
            List<ContractLogisticsDetailResVo> child = new ArrayList<>();
            for (KwcContractLogistics supplement : supplementList) {
                child.add(buildContractLogisticsDetailResVo(supplement));
            }
            contractLogisticsDetailResVo.setChild(child);
        }
        return contractLogisticsDetailResVo;
    }


    private List<KwcContractLogistics> getSupplementList(KwcContractLogistics kwcContractLogistics) {
        LambdaQueryWrapper<KwcContractLogistics> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwcContractLogistics::getContractPid, kwcContractLogistics.getId());
        wrapper.eq(KwcContractLogistics::getDelFlag, Global.NO);
//        wrapper.eq(KwcContractLogistics::getStatus, Global.NO);
        return kwcContractLogisticsMapper.selectList(wrapper);
    }


    /**
     * @desc: 发起签约
     * @param: reqVo 入参
     * @author: czh
     * @date 2023/7/17
     */
    @Transactional(rollbackFor = {})
    public Long submit(ContractLogisticsReqVo reqVo) {
        Long id = reqVo.getId();
        //直接签约先存草稿再修改状态
        if (Objects.isNull(id)) {
            id = addCheckedContract(reqVo);
            changeToSubmit(id);
            sign(reqVo, id);
            return id;
        }
        update(reqVo);
        changeToSubmit(id);
        sign(reqVo, id);
        return id;
    }

    /**
     * @param reqVo 入参 id合同id
     * @desc: 签约
     * @author: czh
     * @date: 2023/8/18
     */
    private void sign(ContractLogisticsReqVo reqVo, Long id) {
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(id);
        if (DictEnum.SIGNING_WAY_1.getValue().equals(String.valueOf(reqVo.getBaseInfo().getSigningWay()))) {
            commonBusinessService.postToEsign(reqVo.getBaseInfo().getCheckedPhone(),
                    reqVo.getBaseInfo().getCarrierPhone(),
                    reqVo.getBaseInfo().getCheckedEntId(),
                    reqVo.getBaseInfo().getCarrierEntId(),
                    reqVo.getContractFile(),
                    id,
                    reqVo.getBaseInfo().getContractName());
            //发送消息
            sendLogisticsMessage(kwcContractLogistics);
        }

        //线下签约直接通过
        if (DictEnum.SIGNING_WAY_2.getValue().equals(String.valueOf(reqVo.getBaseInfo().getSigningWay()))) {
            ESignCallBackReqVo eSignCallBackReqVo = new ESignCallBackReqVo();
            eSignCallBackReqVo.setContractId(id);
            eSignCallBackReqVo.setStatus(ContractStatusEnum.SIGNED.getCode());
            //发送消息
            sendLogisticsMessage(kwcContractLogistics);
            commonBusinessService.approval(eSignCallBackReqVo);
        }

    }


    private void sendLogisticsMessage(KwcContractLogistics kwcContractLogistics) {
        try {
            List<KwcContractLogisticsUnit> kwcContractLogisticsUnits = kwcContractLogisticsUnitService.queryByContractId(kwcContractLogistics.getId());
            Map<Integer, KwcContractLogisticsUnit> collect = kwcContractLogisticsUnits.stream().collect(Collectors.toMap(KwcContractLogisticsUnit::getUnitType, Function.identity()));
            KwcContractLogisticsUnit kwcContractLogisticsUnit = collect.get(CooperateTypeEnum.CARRIAGE.getCode());
            EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(kwcContractLogisticsUnit.getEntId());
            Map<String, Object> map = CollectionUtils.createHashMap();
            map.put("entName", entCacheResDto.getFirmName());
            map.put("contract_no", kwcContractLogistics.getContractNo());
            map.put("name", kwcContractLogistics.getName());
            MessageEnum messageEnum;
            if (Objects.nonNull(kwcContractLogistics.getContractPid())) {
                messageEnum = MessageEnum.SAELCONTRACT_SUBMIT_DATA;
            } else {
                messageEnum = MessageEnum.SAELCONTRACT_SEND_CONTRACT;
            }
            commonBusinessService.sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(kwcContractLogistics.getCreateBy()).setEntId(kwcContractLogistics.getEntId())),
                    messageEnum,
                    map,
                    consignmentSendContract,
                    appConsignmentSendContract);


            if (Objects.nonNull(kwcContractLogistics.getContractPid())) {
                messageEnum = MessageEnum.BUYCONTRACT_SUPPLYPROCESS_SEND;
            } else {
                messageEnum = MessageEnum.BUYCONTRACT_PROCESS_SEND;
            }

            EntCacheResDto entCacheResDto2 = remoteSystemService.queryEntTreeById(kwcContractLogisticsUnit.getEntId());
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntCacheById(kwcContractLogistics.getEntId());
            map.put("entName", entCacheResDto1.getFirmName());
            commonBusinessService.sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(entCacheResDto2.getContactsId()).setEntId(entCacheResDto2.getId())),
                    messageEnum,
                    map,
                    acceptanceSendContract,
                    appAcceptanceSendContract);
        } catch (Exception e) {
            log.error("合同签约流程已发起消息出错:", e);
        }
    }


    /**
     * @param id 合同id
     * @desc: 更新合同为发起
     * @author: czh
     * @date: 2023/7/20
     */
    private void changeToSubmit(Long id) {
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(id);
        kwcContractLogistics.setStatus(ContractStatusEnum.SUBMIT.getCode());
        if (kwcContractLogisticsMapper.updateById(kwcContractLogistics) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
        }
        kwcContractLogisticsTrackService.saveContractLogisticsTrack(id, ContractTrackEnum.SIGNING.getCode(), new Date());
    }


    /**
     * @desc: 修改草稿
     * @param: reqVo 入参
     * @author: czh
     * @date 2023/7/16
     */
    @Transactional(rollbackFor = {})
    public void update(ContractLogisticsReqVo reqVo) {
        Long contractId = reqVo.getId();
        Date date = new Date();
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(contractId);
        if (Objects.isNull(kwcContractLogistics)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.CONTRACT_NOT_EXISTS);
        }

        LogisticsBaseInfoReqVo baseInfo = reqVo.getBaseInfo();
        kwcContractLogistics.setEntId(LoginUserHolder.getEntId());
        kwcContractLogistics.setContractNo(baseInfo.getContractCode());
        kwcContractLogistics.setName(baseInfo.getContractName());
        kwcContractLogistics.setSigningWay(baseInfo.getSigningWay());
        kwcContractLogistics.setCharging(baseInfo.getCharging());
        kwcContractLogistics.setStartTime(baseInfo.getStartTime());
        kwcContractLogistics.setEndTime(baseInfo.getEndTime());
        if (Objects.nonNull(baseInfo.getEndTime())) {
            kwcContractLogistics.setEndTime(DateUtils.getEndOfDay(baseInfo.getEndTime()));
        }
        kwcContractLogistics.setPerformedAmount(new BigDecimal("0"));
        kwcContractLogistics.setContractPid(reqVo.getPid());
        kwcContractLogistics.setRemark(reqVo.getRemark());

        List<LogisticsGoodsInfoReqVo> goodsInfo = reqVo.getGoodsInfo();
        BigDecimal amountTotal = new BigDecimal(Global.NUMERICAL_ZERO);
        if (CollectionUtils.isNotEmpty(goodsInfo)) {
            for (LogisticsGoodsInfoReqVo logisticsGoodsInfoReqVo : goodsInfo) {
                if (Objects.nonNull(logisticsGoodsInfoReqVo.getAmount())) {
                    amountTotal = amountTotal.add(logisticsGoodsInfoReqVo.getAmount());
                }
            }
        }
        kwcContractLogistics.setAmount(amountTotal);
        kwcContractLogistics.setSigningUrl(reqVo.getContractFile());
        kwcContractLogistics.setStatus(ContractStatusEnum.SAVE.getCode());
        kwcContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
        kwcContractLogistics.setUpdateTime(date);
        if (kwcContractLogisticsMapper.updateById(kwcContractLogistics) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
        }


        //保存交易合同商品信息-先把以前的删除
        List<KwcContractLogisticsGoods> kwcContractLogisticsGoodsList = kwcContractLogisticsGoodsService.queryGoodsInfoByContractId(contractId);
        if (CollectionUtils.isNotEmpty(kwcContractLogisticsGoodsList)) {
            kwcContractLogisticsGoodsList.forEach(item -> {
                item.setDelFlag(Global.YES);
                item.setUpdateBy(LoginUserHolder.getUserId());
                item.setUpdateTime(date);
            });

            if (kwcContractLogisticsGoodsService.updateBatch(kwcContractLogisticsGoodsList) != kwcContractLogisticsGoodsList.size()) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
            }
        }
        kwcContractLogisticsGoodsService.saveContractLogisticsGoods(kwcContractLogistics.getId(), reqVo.getGoodsInfo());

        //保存单位信息-先把以前的删除
        List<KwcContractLogisticsUnit> kwcContractLogisticsUnits = kwcContractLogisticsUnitService.queryByContractId(contractId);
        if (CollectionUtils.isNotEmpty(kwcContractLogisticsUnits)) {
            kwcContractLogisticsUnits.forEach(item -> {
                item.setDelFlag(Global.YES);
                item.setUpdateBy(LoginUserHolder.getUserId());
                item.setUpdateTime(date);
            });

            if (kwcContractLogisticsUnitService.updateBatch(kwcContractLogisticsUnits) != kwcContractLogisticsUnits.size()) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
            }
        }
        kwcContractLogisticsUnitService.saveContractLogisticsUnit(contractId, reqVo.getBaseInfo());
    }

    /**
     * @desc: 手动完结
     * @param: reqVo
     * @author: czh
     * @date 2023/7/16
     */
    @Transactional(rollbackFor = {})
    public void complete(CompleteReqVo reqVo) {
        KwcContractLogistics kwcContractLogistic = kwcContractLogisticsMapper.selectById(reqVo.getId());
        if (Objects.isNull(kwcContractLogistic)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.CONTRACT_NOT_EXISTS);
        }
        if (!kwcContractLogistic.getStatus().equals(ContractStatusEnum.SIGNED.getCode())) {
            throw new SystemException(HttpStatus.CODE_10301, HttpStatus.MSG_028);
        }
        kwcContractLogistic.setStatus(ContractStatusEnum.COMPLETE.getCode());
        kwcContractLogistic.setUpdateBy(LoginUserHolder.getUserId());
        kwcContractLogistic.setUpdateTime(new Date());
        kwcContractLogistic.setPerformedAmount(reqVo.getPerformedAmount());
        kwcContractLogistic.setRemark(reqVo.getRemark());
        if (kwcContractLogisticsMapper.updateById(kwcContractLogistic) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
        }
        kwcContractLogisticsTrackService.saveContractLogisticsTrack(kwcContractLogistic.getId(), ContractTrackEnum.OVER.getCode(), new Date());


        //发送消息
        try {
            List<KwcContractLogisticsUnit> kwcContractLogisticsUnits = kwcContractLogisticsUnitService.queryByContractId(kwcContractLogistic.getId());
            Map<Integer, KwcContractLogisticsUnit> collect = kwcContractLogisticsUnits.stream().collect(Collectors.toMap(KwcContractLogisticsUnit::getUnitType, Function.identity()));
            KwcContractLogisticsUnit kwcContractLogisticsUnit = collect.get(CooperateTypeEnum.CARRIAGE.getCode());
            Long entId = kwcContractLogisticsUnit.getEntId();
            EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(entId);
            Map<String, Object> map = CollectionUtils.createHashMap();
            map.put("entName", entCacheResDto.getFirmName());
            map.put("contract_no", kwcContractLogistic.getContractNo());
            map.put("name", kwcContractLogistic.getName());

            commonBusinessService.sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(kwcContractLogistic.getCreateBy()).setEntId(kwcContractLogistic.getEntId())),
                    MessageEnum.SAELCONTRACT_COMPLETE_CONTRACT,
                    map,
                    consignmentSendContract,
                    appConsignmentSendContract);


            KwcContractLogisticsUnit kwcContractLogisticsUnit2 = collect.get(CooperateTypeEnum.CONSIGN.getCode());
            Long entId1 = kwcContractLogisticsUnit2.getEntId();
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntCacheById(entId1);
            EntCacheResDto entCacheResDto2 = remoteSystemService.queryEntTreeById(entId);
            map.put("entName", entCacheResDto1.getFirmName());
            commonBusinessService.sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(entCacheResDto2.getContactsId()).setEntId(entCacheResDto2.getId())),
                    MessageEnum.BUYCONTRACT_COMPLETE_CONTRACT,
                    map,
                    acceptanceSendContract,
                    appAcceptanceSendContract);
        } catch (Exception e) {
            log.error("完结合同消息出错：", e);
        }
    }


    /**
     * @desc: 手动完结
     * @param: reqVo ids
     * @author: czh
     * @date 2023/7/16
     */
    @Transactional(rollbackFor = {})
    public void delete(String ids) {
        List<Long> contractIdList = Arrays.stream(ids.split(Global.COMMA)).map(Long::parseLong).toList();
        List<KwcContractLogistics> kwcContractLogistics = kwcContractLogisticsMapper.selectBatchIds(contractIdList);
        Date date = new Date();
        kwcContractLogistics.forEach(item -> {
            if (!item.getStatus().equals(ContractStatusEnum.SAVE.getCode())) {
                throw new SystemException(HttpStatus.CODE_10301, HttpStatus.MSG_022);
            }
            item.setDelFlag(Global.YES);
            item.setUpdateBy(LoginUserHolder.getUserId());
            item.setUpdateTime(date);
            if (kwcContractLogisticsMapper.updateById(item) <= 0) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
            }
        });
    }

    /**
     * @return PageResult
     * @desc: 分页查询
     * @param: reqVo
     * @author: czh
     * @date 2023/7/17
     */
    public PageResult queryListByPage(QueryListReqVo reqVo) {
        PageHelper.startPage(reqVo.getPageNum(), reqVo.getPageSize());
        QueryListReqDto queryListReqDto = new QueryListReqDto();
        BeanUtils.copyProperties(reqVo, queryListReqDto);
        List<Long> allEnt = new ArrayList<>();
        if (Objects.isNull(reqVo.getEntId())) {
            queryListReqDto.setEntId(LoginUserHolder.getEntId());
        }
        allEnt.add(queryListReqDto.getEntId());

        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(queryListReqDto.getEntId());
        if (Objects.nonNull(entCacheResDto)) {
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
            List<EntCacheResDto> child = entCacheResDto1.getChild();
            if (CollectionUtils.isNotEmpty(child)) {
                allEnt.addAll(child.stream().map(EntCacheResDto::getId).toList());
            }
        }

        if (StringUtils.isNotBlank(reqVo.getKeywords())) {
            List<KwsUserResDto> userByName = remoteUserService.getUserByName(reqVo.getKeywords());
            if (CollectionUtils.isNotEmpty(userByName)) {
                queryListReqDto.setInitiateList(userByName.stream().map(KwsUserResDto::getId).toList());
            }
        }

        queryListReqDto.setAllEnt(allEnt);
        List<QueryListResDto> queryListResDtos = kwcContractLogisticsMapper.queryList(queryListReqDto);
        if (CollectionUtils.isEmpty(queryListResDtos)) {
            return PageHelperUtil.getPageResult(new PageInfo<>());
        }

        List<QueryListResVo> list = getQueryListResVos(queryListResDtos);
        return PageHelperUtil.getPageResult(new PageInfo<>(list), queryListResDtos, reqVo.getPageSize());
    }


    /**
     * @param queryListResDtos 入参
     * @return QueryListResVo
     * @desc: 抽取公共部分
     * @author: czh
     * @date: 2023/7/18
     */
    private List<QueryListResVo> getQueryListResVos(List<QueryListResDto> queryListResDtos) {
        Map<Long, UserCacheResDto> longUserCacheResDtoMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        List<Long> initiateByList = queryListResDtos.stream().map(QueryListResDto::getInitiateBy).toList();
        if (CollectionUtils.isNotEmpty(initiateByList)) {
            longUserCacheResDtoMap = remoteSystemService.queryUserCacheMapByIds(initiateByList);
        }

        List<QueryListResVo> list = new ArrayList<>();
        for (QueryListResDto queryListResDto : queryListResDtos) {
            QueryListResVo queryListResVo = new QueryListResVo();
            BeanUtils.copyProperties(queryListResDto, queryListResVo);

            if (Objects.nonNull(queryListResDto.getUnitType())) {
                queryListResVo.setCheckedEntName(queryListResDto.getUnitType().compareTo(EntTypeEnum.LOGISTICS3.getCode()) == 0 ? queryListResDto.getEntName() : queryListResDto.getTargetEntName());
                queryListResVo.setCarrierEntName(queryListResDto.getUnitType().compareTo(EntTypeEnum.LOGISTICS3.getCode()) == 0 ? queryListResDto.getTargetEntName() : queryListResDto.getEntName());
            }

            UserCacheResDto userCacheResDto = longUserCacheResDtoMap.get(queryListResDto.getInitiateBy());
            if (Objects.nonNull(userCacheResDto)) {
                queryListResVo.setInitiateName(userCacheResDto.getName());
                queryListResVo.setInitiateEntName(Objects.isNull(userCacheResDto.getEntInfo()) ? "" : userCacheResDto.getEntInfo().getFirmName());
            }
            queryListResVo.setChargingName(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), String.valueOf(queryListResDto.getCharging())));
            queryListResVo.setStatusName(Objects.requireNonNull(ContractStatusEnum.getName(queryListResDto.getStatus())).getName());
            queryListResVo.setSigningWayName(DictEnum.getLabel(DictTypeEnum.SIGNING_TYPE.getType(), queryListResDto.getSigningWay()));
            queryListResVo.setSigningWay(queryListResDto.getSigningWay());
            queryListResVo.setPerformedAmount(queryListResDto.getPerformedAmount());
            queryListResVo.setAmount(queryListResDto.getAmount());

            if (Objects.nonNull(queryListResVo.getEndTime())) {
                queryListResVo.setEndTime(DateUtils.getStartOfDay(queryListResVo.getEndTime()));
                String endDate = DateUtils.format(queryListResVo.getEndTime(), DateUtils.DATE_PATTERN);
                if (org.apache.commons.lang3.StringUtils.equals(endDate,"9999-12-30")){
                    queryListResVo.setEndTime(null);
                }
            }
            list.add(queryListResVo);
        }
        return list;
    }

    public void export(QueryListReqVo reqVo, HttpServletResponse response) {
        QueryListReqDto queryListReqDto = new QueryListReqDto();
        BeanUtils.copyProperties(reqVo, queryListReqDto);
        queryListReqDto.setIdList(StringUtils.splitStrToList(reqVo.getIds(), Global.COMMA, Long.class));
        List<Long> allEnt = new ArrayList<>();
        if (Objects.isNull(reqVo.getEntId())) {
            queryListReqDto.setEntId(LoginUserHolder.getEntId());
        }
        allEnt.add(queryListReqDto.getEntId());

        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(queryListReqDto.getEntId());
        if (Objects.nonNull(entCacheResDto)) {
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
            List<EntCacheResDto> child = entCacheResDto1.getChild();
            if (CollectionUtils.isNotEmpty(child)) {
                allEnt.addAll(child.stream().map(EntCacheResDto::getId).toList());
            }
        }
        queryListReqDto.setAllEnt(allEnt);
        List<QueryListResDto> queryListResDtos = kwcContractLogisticsMapper.queryList(queryListReqDto);
        if (CollectionUtils.isEmpty(queryListResDtos)) {
            throw new SystemException(HttpStatus.SUCCESS_CODE, "暂无数据，请确认！");
        }

        List<QueryListResVo> list = getQueryListResVos(queryListResDtos);
        List<LogisticsListExport> dataList = BeanUtils.copyToList(list, LogisticsListExport.class);
        ExcelUtil.downData(response, LogisticsListExport.class, dataList);
    }


    /**
     * @return QueryListResVo
     * @desc: 查询当前企业的托运合同
     * @author: czh
     * @date: 2023/7/18
     */
    public List<QueryListResVo> queryCurrentEntCheckedContractList() {
        Long entId = LoginUserHolder.getEntId();
        QueryListReqDto queryListReqDto = new QueryListReqDto();
        queryListReqDto.setEntId(entId);
        queryListReqDto.setStatus(ContractStatusEnum.SIGNED.getCode());
        queryListReqDto.setEntType(EntTypeEnum.LOGISTICS3.getCode());
        List<QueryListResDto> queryListResDtos = kwcContractLogisticsMapper.queryList(queryListReqDto);
        if (CollectionUtils.isEmpty(queryListResDtos)) {
            return Collections.emptyList();
        }
        return getQueryListResVos(queryListResDtos);
    }


    /**
     * @return HttpResult
     * @desc: 分组查询
     * @author: czh
     * @date: 2023/7/18
     */
    public List<FindListGroupResVo> findListGroup(QueryListReqVo reqVo) {
        ContractStatusEnum[] values = ContractStatusEnum.values();
        List<FindListGroupResVo> list = new ArrayList<>();
        FindListGroupResVo total = new FindListGroupResVo();
        total.setCount(0);
        list.add(total);
        for (ContractStatusEnum contractStatusEnum : values) {
            FindListGroupResVo findListGroupResVo = new FindListGroupResVo();
            findListGroupResVo.setStatus(contractStatusEnum.getCode());
            findListGroupResVo.setStatusName(contractStatusEnum.getName());
            findListGroupResVo.setCount(0);
            list.add(findListGroupResVo);
        }

        QueryListReqDto queryListReqDto = new QueryListReqDto();
        BeanUtils.copyProperties(reqVo, queryListReqDto);
        List<Long> allEnt = new ArrayList<>();
        if (Objects.isNull(reqVo.getEntId())) {
            queryListReqDto.setEntId(LoginUserHolder.getEntId());
        }
        allEnt.add(queryListReqDto.getEntId());

        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(queryListReqDto.getEntId());
        if (Objects.nonNull(entCacheResDto)) {
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
            List<EntCacheResDto> child = entCacheResDto1.getChild();
            if (CollectionUtils.isNotEmpty(child)) {
                allEnt.addAll(child.stream().map(EntCacheResDto::getId).toList());
            }
        }
        queryListReqDto.setAllEnt(allEnt);
        List<QueryListResDto> queryListResDtoList = kwcContractLogisticsMapper.queryList(queryListReqDto);
        if (CollectionUtils.isNotEmpty(queryListResDtoList)) {
            Map<Integer, List<QueryListResDto>> collect = queryListResDtoList.stream().collect(Collectors.groupingBy(QueryListResDto::getStatus));
            for (FindListGroupResVo findListGroupResVo : list) {
                List<QueryListResDto> queryListResDtos = collect.get(findListGroupResVo.getStatus());
                findListGroupResVo.setCount(CollectionUtils.isEmpty(queryListResDtos) ? Global.NUMERICAL_ZERO : queryListResDtos.size());
            }
            //给汇总项求和
            list.get(0).setCount(queryListResDtoList.size());
        }
        return list;
    }

    @Transactional(rollbackFor = {})
    public void approval(Long id, Integer status, String remark) {
        LambdaQueryWrapper<KwcContractLogistics> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwcContractLogistics::getId, id).
                eq(KwcContractLogistics::getDelFlag, Global.NO).
                eq(KwcContractLogistics::getStatus, ContractStatusEnum.SUBMIT.getCode());
        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectOne(wrapper);
        if (Objects.isNull(kwcContractLogistics)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.CONTRACT_NOT_EXISTS);
        }

        kwcContractLogistics.setStatus(status);
        kwcContractLogistics.setRemark(remark);
        kwcContractLogistics.setUpdateTime(new Date());
        kwcContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
        if (kwcContractLogisticsMapper.updateById(kwcContractLogistics) <= 0) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
        }
    }


    /**
     * @param reqVo 分页查询
     * @return PageResult
     * @desc: 运营端查物流合同
     * @author: czh
     * @date: 2023/9/13
     */
    public PageResult queryLogisticsByPage(QueryListReqVo reqVo) {
        PageHelper.startPage(reqVo.getPageNum(), reqVo.getPageSize());

        //新增客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                return PageHelperUtil.getPageResult(new PageInfo<>());
            }
            authEntIdList.addAll(ids);
        }

        List<QueryListResDto> queryListResDtos = kwcContractLogisticsMapper.queryLogisticsList(reqVo, authEntIdList);
        if (CollectionUtils.isEmpty(queryListResDtos)) {
            return PageHelperUtil.getPageResult(new PageInfo<>());
        }

        List<QueryListResVo> list = getLogisticsResVo(queryListResDtos);
        return PageHelperUtil.getPageResult(new PageInfo<>(list), queryListResDtos, reqVo.getPageSize());
    }

    /**
     * 转换为vo
     */
    private List<QueryListResVo> getLogisticsResVo(List<QueryListResDto> queryListResDtos) {
        Map<Long, UserCacheResDto> longUserCacheResDtoMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        List<Long> initiateByList = queryListResDtos.stream().map(QueryListResDto::getInitiateBy).toList();
        if (CollectionUtils.isNotEmpty(initiateByList)) {
            longUserCacheResDtoMap = remoteSystemService.queryUserCacheMapByIds(initiateByList);
        }

        List<QueryListResVo> list = new ArrayList<>();
        for (QueryListResDto queryListResDto : queryListResDtos) {
            QueryListResVo queryListResVo = new QueryListResVo();
            BeanUtils.copyProperties(queryListResDto, queryListResVo);
            UserCacheResDto userCacheResDto = longUserCacheResDtoMap.get(queryListResDto.getInitiateBy());
            if (Objects.nonNull(userCacheResDto)) {
                queryListResVo.setInitiateName(userCacheResDto.getName());
                queryListResVo.setInitiateEntName(Objects.isNull(userCacheResDto.getEntInfo()) ? "" : userCacheResDto.getEntInfo().getFirmName());
            }
            queryListResVo.setChargingName(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), String.valueOf(queryListResDto.getCharging())));
            queryListResVo.setStatusName(Objects.requireNonNull(ContractStatusEnum.getName(queryListResDto.getStatus())).getName());
            queryListResVo.setSigningWayName(DictEnum.getLabel(DictTypeEnum.SIGNING_TYPE.getType(), queryListResDto.getSigningWay()));
            queryListResVo.setSigningWay(queryListResDto.getSigningWay());
            queryListResVo.setPerformedAmount(queryListResDto.getPerformedAmount());
            queryListResVo.setAmount(queryListResDto.getAmount());
            list.add(queryListResVo);
        }
        return list;
    }

    /**
     * @return HttpResult
     * @desc: 分组查询
     * @author: czh
     * @date: 2023/9/13
     */
    public List<FindListGroupResVo> findLogisticsListGroup(QueryListReqVo reqVo) {
        ContractStatusEnum[] values = ContractStatusEnum.values();
        List<FindListGroupResVo> list = new ArrayList<>();
        FindListGroupResVo total = new FindListGroupResVo();
        total.setCount(0);
        list.add(total);
        for (ContractStatusEnum contractStatusEnum : values) {
            FindListGroupResVo findListGroupResVo = new FindListGroupResVo();
            findListGroupResVo.setStatus(contractStatusEnum.getCode());
            findListGroupResVo.setStatusName(contractStatusEnum.getName());
            findListGroupResVo.setCount(0);
            list.add(findListGroupResVo);
        }
        //新增客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                return list;
            }
            authEntIdList.addAll(ids);
        }
        List<QueryListResDto> queryListResDtoList = kwcContractLogisticsMapper.queryLogisticsList(reqVo, authEntIdList);
        if (CollectionUtils.isNotEmpty(queryListResDtoList)) {
            Map<Integer, List<QueryListResDto>> collect = queryListResDtoList.stream().collect(Collectors.groupingBy(QueryListResDto::getStatus));
            for (FindListGroupResVo findListGroupResVo : list) {
                List<QueryListResDto> queryListResDtos = collect.get(findListGroupResVo.getStatus());
                findListGroupResVo.setCount(CollectionUtils.isEmpty(queryListResDtos) ? Global.NUMERICAL_ZERO : queryListResDtos.size());
            }
            //给汇总项求和
            list.get(0).setCount(queryListResDtoList.size());
        }
        return list;
    }


    /**
     * @param reqVo 查询参数
     * @desc: 运营端查物流合同导出
     * @author: czh
     * @date: 2023/9/13
     */
    public void exportLogisticsList(QueryListReqVo reqVo, HttpServletResponse response) {
        reqVo.setIdList(StringUtils.splitStrToList(reqVo.getIds(), Global.COMMA, Long.class));
        //新增客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                throw new SystemException(HttpStatus.SUCCESS_CODE, "暂无数据，请确认！");
            }
            authEntIdList.addAll(ids);
        }
        List<QueryListResDto> queryListResDtos = kwcContractLogisticsMapper.queryLogisticsList(reqVo, authEntIdList);
        if (CollectionUtils.isEmpty(queryListResDtos)) {
            throw new SystemException(HttpStatus.SUCCESS_CODE, "暂无数据，请确认！");
        }
        List<QueryListResVo> list = getLogisticsResVo(queryListResDtos);
        List<LogisticsListExport> dataList = BeanUtils.copyToList(list, LogisticsListExport.class);
        ExcelUtil.downData(response, LogisticsListExport.class, dataList);
    }

    public PageDataResult<QueryLogisticListResp> queryLogisticsContractListByPage(QueryLogisticListReq req) {
        log.info("分页查询物流合同参数：{}", JSON.toJSONString(req));
        Long entId;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getEntId())) {
            entId = Long.valueOf(req.getEntId());
        } else {
            entId = LoginUserHolder.getEntId();
        }

        List<Long> entIdList = Lists.newArrayList();
        entIdList.add(entId);
        Integer type = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getConsignCompanyId())) {
            entIdList.add(Long.valueOf(req.getConsignCompanyId()));
            type = CooperateTypeEnum.CONSIGN.getCode();
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getCarriageCompanyId())) {
            entIdList.add(Long.valueOf(req.getCarriageCompanyId()));
            type = CooperateTypeEnum.CARRIAGE.getCode();
        }
        //查询物流企业
        Set<Long> contractIdList = Sets.newHashSet();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIdList)) {
            List<KwcContractLogisticsUnit> units = kwcContractLogisticsUnitRepository.queryByEntIds(entIdList, type);
            if (CollectionUtils.isNotEmpty(units)) {
                Set<Long> contractIds = units.stream().filter(x -> Objects.equals(x.getEntId(), entId))
                        .map(KwcContractLogisticsUnit::getContractId)
                        .collect(Collectors.toSet());
                contractIdList = units.stream()
                        .filter(x -> contractIds.contains(x.getContractId()))
                        .map(KwcContractLogisticsUnit::getContractId).collect(Collectors.toSet());
            }
        }
        if (CollectionUtils.isEmpty(contractIdList) && CollectionUtils.isNotEmpty(entIdList)){
            return PageDataResult.empty(req.getPageNum(),req.getPageSize());
        }
        applyContractTypeFilterToIds(req, entId, contractIdList);
        if (CollectionUtils.isEmpty(contractIdList)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
        contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
        if (CollectionUtils.isEmpty(contractIdList)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        IPage<KwcContractLogistics> page = kwcContractLogisticsRepository.queryByPage(req.getPageNum(), req.getPageSize(),
                req.getContractNo(),
                req.getContractName(), req.getStatus(), contractIdList);
        List<KwcContractLogistics> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        //发起人id
        List<Long> userIds =
                records.stream()
                        .map(KwcContractLogistics::getCreateBy).distinct()
                        .collect(Collectors.toList());
        Map<Long, UserCacheResDto> longUserCacheResDtoMap = Maps.newHashMap();
        //获取员工信息
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(userIds)) {
            longUserCacheResDtoMap = remoteSystemService.queryUserCacheMapByIds(userIds);
        }

        //合同id
        Set<Long> contractIds = records.stream()
                .map(KwcContractLogistics::getId)
                .collect(Collectors.toSet());
        //查询物流商品信息
        List<KwcContractLogisticsGoods> kwcContractLogisticsGoods = kwcContractLogisticsGoodsRepository.queryByContractIds(contractIds);
        Map<Long, List<KwcContractLogisticsGoods>> contractIdAndGoodsMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwcContractLogisticsGoods)) {
            //按照合同id进行分组
            contractIdAndGoodsMap =
                    kwcContractLogisticsGoods.stream().collect(Collectors.groupingBy(KwcContractLogisticsGoods::getContractId));
        }

        //查询物流企业信息
        List<KwcContractLogisticsUnit> kwcContractLogisticsUnits =
                kwcContractLogisticsUnitRepository.queryByContractIds(contractIds);
        Map<String, KwcContractLogisticsUnit> contractUniTypeAndUnitMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwcContractLogisticsUnits)) {
            //合同id和单位类型组合成key映射物流企业信息
            contractUniTypeAndUnitMap = kwcContractLogisticsUnits.stream()
                    .collect(Collectors.toMap(k -> k.getContractId() + "-" + k.getUnitType(),
                            Function.identity(), (x, y) -> x));
        }

        // 根据物流合同查询运单
        List<RWaybillSubOrderVo> rWaybillSubOrderVos = transportRemoteService.queryWaybillOrderByLogContractIds(contractIds);
        Map<Long, RWaybillSubOrderVo> logTradeOrderIdAndWaybillMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(rWaybillSubOrderVos)) {
            logTradeOrderIdAndWaybillMap = rWaybillSubOrderVos.stream()
                    .collect(Collectors.toMap(RWaybillSubOrderVo::getLogContractId, Function.identity(), (x, y) -> x));
        }
        List<WayContaractbillOrderVo> wayContaractbillOrderVos = transportRemoteService.queryLogisticContractByContTradeIds(contractIds);
        Map<Long, WayContaractbillOrderVo> contractIdAndLogisticsOrderMap = Optional.ofNullable(wayContaractbillOrderVos)
                .orElse(List.of())
                .stream()
                .collect(Collectors.toMap(WayContaractbillOrderVo::getContractId, Function.identity(), (x, y) -> x));
        Map<Long, UserCacheResDto> finalLongUserCacheResDtoMap = longUserCacheResDtoMap;
        Map<String, KwcContractLogisticsUnit> finalContractUniTypeAndUnitMap = contractUniTypeAndUnitMap;
        Map<Long, List<KwcContractLogisticsGoods>> finalContractIdAndGoodsMap = contractIdAndGoodsMap;
        Map<Long, RWaybillSubOrderVo> finalLogTradeOrderIdAndWaybillMap = logTradeOrderIdAndWaybillMap;
        List<QueryLogisticListResp> resp = records.stream()
                .map(r -> getQueryLogisticListResp(r, finalContractUniTypeAndUnitMap,
                        finalContractIdAndGoodsMap, finalLongUserCacheResDtoMap, finalLogTradeOrderIdAndWaybillMap,
                        contractIdAndLogisticsOrderMap, entId))
                .collect(Collectors.toList());

        return PageDataResult.of(page, resp);
    }

    /**
     * 合同类型筛选：1 托运合同 2 承运合同（相对当前查看企业 entId 在合同中的角色）
     */
    private void applyContractTypeFilterToIds(QueryLogisticListReq req, Long entId, Set<Long> contractIdList) {
        if (req == null || entId == null || CollectionUtils.isEmpty(contractIdList)) {
            return;
        }
        Integer ct = req.getContractType();
        if (ct == null || (ct != 1 && ct != 2)) {
            return;
        }
        int unitType = ct == 1 ? CooperateTypeEnum.CONSIGN.getCode() : CooperateTypeEnum.CARRIAGE.getCode();
        List<KwcContractLogisticsUnit> typeUnits = kwcContractLogisticsUnitRepository.queryByEntIdAndEntType(entId, unitType);
        Set<Long> allowed = typeUnits.stream()
                .map(KwcContractLogisticsUnit::getContractId)
                .collect(Collectors.toSet());
        contractIdList.retainAll(allowed);
    }

    @NotNull
    private static QueryLogisticListResp getQueryLogisticListResp(KwcContractLogistics r,
                                                                  Map<String, KwcContractLogisticsUnit> finalContractUniTypeAndUnitMap,
                                                                  Map<Long, List<KwcContractLogisticsGoods>> finalContractIdAndGoodsMap,
                                                                  Map<Long, UserCacheResDto> finalLongUserCacheResDtoMap,
                                                                  Map<Long, RWaybillSubOrderVo> logTradeOrderIdAndWaybillMap,
                                                                  Map<Long, WayContaractbillOrderVo> contractIdAndLogisticsOrderMap,
                                                                  Long viewerEntId) {
        QueryLogisticListResp queryLogisticListResp = new QueryLogisticListResp();
        queryLogisticListResp.setId(r.getId());
        queryLogisticListResp.setContractStatus(r.getStatus());
        queryLogisticListResp.setContractStatusDesc(ContractStatusEnum.getNameByCode(r.getStatus()));
        KwcContractLogisticsUnit logisticsUnit = finalContractUniTypeAndUnitMap.get(r.getId() + "-" + CooperateTypeEnum.CONSIGN.getCode());
        if (Objects.nonNull(logisticsUnit)){
            queryLogisticListResp.setConsignUnit(String.valueOf(logisticsUnit.getEntId()));
            queryLogisticListResp.setConsignUnitName(logisticsUnit.getFirmName());
        }
        KwcContractLogisticsUnit carriageUnit =
                finalContractUniTypeAndUnitMap.get(r.getId() + "-" + CooperateTypeEnum.CARRIAGE.getCode());
        if (Objects.nonNull(carriageUnit)){
            queryLogisticListResp.setCarriageUnit(String.valueOf(carriageUnit.getEntId()));
            queryLogisticListResp.setCarriageUnitName(carriageUnit.getFirmName());
        }
        if (Objects.nonNull(viewerEntId)) {
            if (Objects.nonNull(logisticsUnit) && Objects.equals(viewerEntId, logisticsUnit.getEntId())) {
                queryLogisticListResp.setContractType(1);
                queryLogisticListResp.setContractTypeDesc("托运合同");
            } else if (Objects.nonNull(carriageUnit) && Objects.equals(viewerEntId, carriageUnit.getEntId())) {
                queryLogisticListResp.setContractType(2);
                queryLogisticListResp.setContractTypeDesc("承运合同");
            }
        }

        queryLogisticListResp.setContractCode(r.getContractNo());
        queryLogisticListResp.setContractName(r.getName());
        queryLogisticListResp.setSignWay(r.getSigningWay());
        queryLogisticListResp.setSignWayDesc(DictEnum.getLabel(DictTypeEnum.SIGNING_TYPE.getType(),
                String.valueOf( r.getSigningWay())));
        //设置派车方式和派车方式描述字段
        queryLogisticListResp.setDispatchWay(r.getDispatchWay());
        queryLogisticListResp.setDispatchWayDesc(DispatchingTypeEnum.getLabel(r.getDispatchWay()));

        List<KwcContractLogisticsGoods> goods = finalContractIdAndGoodsMap.get(r.getId());
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(goods)){
            boolean b = goods.stream().anyMatch(g -> Objects.isNull(g.getAmount()));
            if (b){
                queryLogisticListResp.setContractTransportAmount(null);
            }else {
                BigDecimal contractTransportAmount = goods.stream()
                        .map(KwcContractLogisticsGoods::getAmount)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                queryLogisticListResp.setContractTransportAmount(contractTransportAmount.setScale(2, RoundingMode.HALF_UP).toPlainString());
            }
         }
        RWaybillSubOrderVo waybillSubOrderVo = logTradeOrderIdAndWaybillMap.getOrDefault(r.getId(), new RWaybillSubOrderVo());
        List<RWaybillSubOrderVo.BillSubOrder> subOrders = waybillSubOrderVo.getSubOrders();
        BigDecimal totalTransportAmount = BigDecimal.ZERO;
        BigDecimal totalAmount = BigDecimal.ZERO;
//        BigDecimal performedAmount = BigDecimal.ZERO;
//        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(subOrders)){
//            String billMode = subOrders.get(0).getBillMode();
//            if (org.apache.commons.lang3.StringUtils.equals(billMode, DictEnum.LOAD_UNLOAD_WAY_1.getValue())){
//                totalTransportAmount = subOrders.stream()
//                        .filter(x->Arrays.asList(CarWaybillV1Enum.COMPLETION_LOADING.getCode(),CarWaybillV1Enum.COMPLETED.getCode()).contains(x.getStatus()))
//                        .map(RWaybillSubOrderVo.BillSubOrder::getLoadAmount)
//                        .filter(Objects::nonNull)
//                        .reduce(BigDecimal.ZERO, BigDecimal::add);
//            }else {
//                totalTransportAmount = subOrders.stream()
//                        .filter(x->Objects.equals(x.getStatus(), CarWaybillV1Enum.COMPLETED.getCode()))
//                        .map(RWaybillSubOrderVo.BillSubOrder::getUnloadAmount)
//                        .filter(Objects::nonNull)
//                        .reduce(BigDecimal.ZERO, BigDecimal::add);
//            }
//
//            queryLogisticListResp.setTotalTransportAmount(totalTransportAmount.setScale(2, RoundingMode.HALF_UP).toPlainString());
//        }
        WayContaractbillOrderVo wayContaractbillOrderVo = contractIdAndLogisticsOrderMap.get(r.getId());
        if (Objects.nonNull(wayContaractbillOrderVo) ){
            List<KwtLogisticsOrderVO> orderVos = wayContaractbillOrderVo.getOrderVos();
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(orderVos)){
                String billingMode = orderVos.get(0).getBillingMode();
                if (org.apache.commons.lang3.StringUtils.equals(billingMode, DictEnum.LOAD_UNLOAD_WAY_1.getValue())){
                    totalTransportAmount = orderVos.stream()
                            .map(KwtLogisticsOrderVO::getTotalLoadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);


                    totalAmount = orderVos.stream()
                            .filter(x->Arrays.asList(CarWaybillV1Enum.COMPLETION_LOADING.getCode(),CarWaybillV1Enum.COMPLETED.getCode()).contains(x.getStatus()))
                            .map(vo -> {
                                BigDecimal loadAmount = vo.getTotalLoadAmount();
                                BigDecimal price = vo.getPrice() != null ? vo.getPrice() : BigDecimal.ONE;
                                return loadAmount != null ? loadAmount.multiply(price) : BigDecimal.ZERO;
                            })
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }else {
                    totalTransportAmount = orderVos.stream()
                            .map(KwtLogisticsOrderVO::getTotalUnloadAmount)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    totalAmount = orderVos.stream()
                            .filter(x->Arrays.asList(CarWaybillV1Enum.COMPLETION_LOADING.getCode(),CarWaybillV1Enum.COMPLETED.getCode()).contains(x.getStatus()))
                            .map(vo -> {
                                BigDecimal loadAmount = vo.getTotalUnloadAmount();
                                BigDecimal price = vo.getPrice() != null ? vo.getPrice() : BigDecimal.ONE;
                                return loadAmount != null ? loadAmount.multiply(price) : BigDecimal.ZERO;
                            })
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }
            }
        }
        queryLogisticListResp.setPerformedAmount(totalTransportAmount.setScale(2, RoundingMode.HALF_UP).toPlainString());
        queryLogisticListResp.setTotalTransportAmount(totalAmount.setScale(2, RoundingMode.HALF_UP).toPlainString());
        String startDate = DateUtils.format(r.getStartTime(), DateUtils.DATE_PATTERN);
        queryLogisticListResp.setStartDate(startDate);
        String endDate = DateUtils.format(r.getEndTime(), DateUtils.DATE_PATTERN);
        queryLogisticListResp.setEndDate(org.apache.commons.lang3.StringUtils.equals(endDate,"9999-12-30") ? "": endDate);
        queryLogisticListResp.setInitiatorId(r.getCreateBy());
        UserCacheResDto userCacheResDto = finalLongUserCacheResDtoMap.getOrDefault(r.getCreateBy(), new UserCacheResDto());
        queryLogisticListResp.setInitiator(userCacheResDto.getName());
        EntCacheResDto entInfo = userCacheResDto.getEntInfo();
        queryLogisticListResp.setInitiatorUnit(Objects.nonNull(entInfo) ? entInfo.getFirmName() : null);
        queryLogisticListResp.setInitiatorTime(DateUtils.format(r.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
        queryLogisticListResp.setRemark(r.getRemark());


        return queryLogisticListResp;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean addOrUpdateLogisticsContract(LogisticListReq req) {
        log.info("新增物流合同，请求参数 :{}", JSON.toJSONString(req));
        //查询物流合同
        long contactId = new IdWorker(1L).nextId();

        KwcContractLogistics saveContractLogistics = new KwcContractLogistics();
        Date date = new Date();
        LogisticListReq.TradeBaseInfo baseInfo = req.getBaseInfo();
        if(Objects.equals(baseInfo.getSettlement(),1)){
            throw new BusinessException("暂不支持普通结算模式");
        }
        int transportBizType = resolveTransportBizType(baseInfo);
        baseInfo.setTransportBizType(transportBizType);
        validateLogisticsContractBiz(req, transportBizType);
        if (Objects.nonNull(req.getId())){
            saveContractLogistics.setId(req.getId());
        }else {
            KwcContractLogistics kwcContractLogistics = kwcContractLogisticsRepository.queryByContractCode(req.getBaseInfo().getContractCode());
            if (Objects.nonNull(kwcContractLogistics)){
                throw new BusinessException("合同编号已存在");
            }
            saveContractLogistics.setId(contactId);
        }
        saveContractLogistics.setEntId(LoginUserHolder.getEntId());
        saveContractLogistics.setContractNo(baseInfo.getContractCode());
        saveContractLogistics.setName(baseInfo.getContractName());
        saveContractLogistics.setSigningWay(baseInfo.getSigningWay());
        saveContractLogistics.setDispatchWay(baseInfo.getDispatchWay());
        saveContractLogistics.setSettlement(baseInfo.getSettlement());
        saveContractLogistics.setStartTime(baseInfo.getStartTime());
        if (Objects.isNull(baseInfo.getEndTime())){
            LocalDate localDate = LocalDate.of(9999, 12, 30);
            Date date1 = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            saveContractLogistics.setEndTime(DateUtils.getEndOfDay(date1));
        }else {
            saveContractLogistics.setEndTime(DateUtils.getEndOfDay(baseInfo.getEndTime()));
        }
        List<Long> entIdList = new ArrayList<>();
        if (Objects.nonNull(baseInfo.getProvideEntId())) {
            entIdList.add(baseInfo.getProvideEntId());
        }

        if (Objects.nonNull(baseInfo.getPurchaseEntId())) {
            entIdList.add(baseInfo.getPurchaseEntId());
        }
        Map<Long, EntCacheResDto> entCacheResDtoMap = commonBusinessService.queryEntCacheMapByIds(entIdList);
        //校验自动派单合同的托运单位是否为供应商类型
        checkAutoDispatchingContractEntType(baseInfo,entCacheResDtoMap);
        //校验物流企业是否存在同时段的自动派车合同
        checkAutoDispatchingContractExist(baseInfo);

        saveContractLogistics.setStatus(ContractStatusEnum.SUBMIT.getCode());
        saveContractLogistics.setCreateBy(LoginUserHolder.getUserId());
        if (Objects.nonNull(req.getId())){
            saveContractLogistics.setCreateTime(null);
        }else {
            saveContractLogistics.setCreateTime(date);
        }

        saveContractLogistics.setUpdateBy(LoginUserHolder.getUserId());
        saveContractLogistics.setUpdateTime(date);
        saveContractLogistics.setTransportBizType(transportBizType);
        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(transportBizType)) {
            saveContractLogistics.setCommonPrice(null);
            saveContractLogistics.setAllowedError(baseInfo.getAllowedError().setScale(4, RoundingMode.HALF_UP));
        } else {
            saveContractLogistics.setCommonPrice(baseInfo.getCommonPrice());
            saveContractLogistics.setAllowedError(null);
        }
        saveContractLogistics.setSigningUrl(req.getContractFile());
        kwcContractLogisticsRepository.saveOrUpdateLogistics(saveContractLogistics);

        //保存交易商品信息
        saveLogisticsGoods(req, saveContractLogistics.getId());
        //保存物流企业信息
        if (CollectionUtils.isEmpty(entIdList)) {
            return false;
        }
        saveLogisticListUnit(entIdList, baseInfo, saveContractLogistics.getId(), date,entCacheResDtoMap);

        //如果是自动派单合同需要初始化物流企业评分记录和评分记录明细
        if(DispatchingTypeEnum.AUTO.getValue().equals(baseInfo.getDispatchWay())){
            logisticsScoreService.initLogisticsScore(baseInfo);
        }
        return Boolean.TRUE;
    }

    private static int resolveTransportBizType(LogisticListReq.TradeBaseInfo baseInfo) {
        Integer t = baseInfo.getTransportBizType();
        if (t == null) {
            return LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode();
        }
        if (!Objects.equals(t, LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode())
                && !Objects.equals(t, LogisticsTransportBizTypeEnum.RAW_ORE_TRANSFER.getCode())) {
            throw new BusinessException("合同类型无效，请选择贸易运输或原矿转运");
        }
        return t;
    }

    private void validateLogisticsContractBiz(LogisticListReq req, int transportBizType) {
        LogisticListReq.TradeBaseInfo baseInfo = req.getBaseInfo();
        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(transportBizType)) {
            if (baseInfo.getAllowedError() == null) {
                throw new BusinessException("原矿转运合同须填写允许误差");
            }
            if (baseInfo.getAllowedError().compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException("允许误差须大于0");
            }
            if (baseInfo.getAllowedError().compareTo(new BigDecimal("1000")) > 0) {
                throw new BusinessException("允许误差不能超过1000‰");
            }
            if (baseInfo.getCommonPrice() != null && baseInfo.getCommonPrice().compareTo(BigDecimal.ZERO) > 0) {
                throw new BusinessException("原矿转运合同不可录入通用运价");
            }
            List<LogisticListReq.TradeGoodsInfo> goodsInfos = req.getGoodsInfo();
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(goodsInfos)) {
                for (LogisticListReq.TradeGoodsInfo g : goodsInfos) {
                    if (g.getPrice() != null && g.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                        throw new BusinessException("原矿转运合同不可录入运输单价");
                    }
                }
            }
        }
    }

    private void checkAutoDispatchingContractEntType(LogisticListReq.TradeBaseInfo baseInfo,Map<Long, EntCacheResDto> entCacheResDtoMap) {
        if(DispatchingTypeEnum.AUTO.getValue().equals(baseInfo.getDispatchWay())){
            EntCacheResDto entCacheResDto = entCacheResDtoMap.get(baseInfo.getProvideEntId());
            if (entCacheResDto != null && !entCacheResDto.getEntTypes().contains(String.valueOf(EntTypeEnum.SUPPLIER.getCode()))) {
                throw new BusinessException("自动派车合同的托运单位必须为供应商");
            }
        }
    }

    public void checkAutoDispatchingContractExist(LogisticListReq.TradeBaseInfo baseInfo) {
        List<KwcContractLogisticsUnit> units = kwcContractLogisticsUnitRepository.queryByEntIdAndEntType(baseInfo.getPurchaseEntId(), EntTypeEnum.LOGISTICS4.getCode());
        if (CollectionUtils.isNotEmpty(units)) {
            Set<Long> contractIdList = units.stream().map(KwcContractLogisticsUnit::getContractId).collect(Collectors.toSet());
            KwcContractLogistics kwcContractLogistics = kwcContractLogisticsRepository.queryBy(contractIdList,baseInfo.getStartTime(),baseInfo.getEndTime(),DispatchingTypeEnum.AUTO.getValue());
            if (Objects.nonNull(kwcContractLogistics)){
                throw new BusinessException("当前物流企业在合同时间段内已存在自动派车合同");
            }
        }
    }

    private String changeFile(String contractFile) {
        if (StringUtils.isNotBlank(contractFile)) {
            JSONArray jsonArray = JSONArray.parseArray(contractFile);
            for (int n = 0; n < jsonArray.size(); n++) {
                JSONObject jsonObject = jsonArray.getJSONObject(n);
                String url = jsonObject.getString("url");
                jsonObject.put("url", FileUtils.replaceAll(url));
            }
            return JSON.toJSONString(jsonArray);
        }
        return null;
    }
    private void saveLogisticsGoods(LogisticListReq req, long contactId) {
        //删除商品
        kwcContractLogisticsGoodsRepository.deleteByContractId(contactId);
        LogisticListReq.TradeBaseInfo baseInfo = req.getBaseInfo();
        List<LogisticListReq.TradeGoodsInfo> goodsInfos = req.getGoodsInfo();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(goodsInfos)){
            return;
        }
        // 检查goodsId是否有重复
        Set<Long> goodsIdSet = new HashSet<>();
        boolean hasDuplicate = goodsInfos.stream()
                .map(LogisticListReq.TradeGoodsInfo::getGoodsId)
                .anyMatch(goodsId -> !goodsIdSet.add(goodsId));

        if (hasDuplicate) {
            // 存在重复的goodsId
            throw new BusinessException("商品不能重复");
        }
        List<KwcContractLogisticsGoods> goods = goodsInfos.stream()
                .map(x -> getKwcContractLogisticsGoods(x, contactId,baseInfo))
                .collect(Collectors.toList());
        kwcContractLogisticsGoodsRepository.saveLogisticsGoods(goods);
    }

    @NotNull
    private static KwcContractLogisticsGoods getKwcContractLogisticsGoods(LogisticListReq.TradeGoodsInfo x,
                                                                          long contactId,LogisticListReq.TradeBaseInfo baseInfo) {
        KwcContractLogisticsGoods logisticsGoods = new KwcContractLogisticsGoods();
        Date date1 = new Date();
        logisticsGoods.setContractId(contactId);
        logisticsGoods.setGoodsId(x.getGoodsId());
        logisticsGoods.setGoodsName(x.getGoodsName());
        logisticsGoods.setSkuId(0L);
        logisticsGoods.setAmount(x.getAmount());
        logisticsGoods.setUnit(x.getUnit());
        if (LogisticsTransportBizTypeEnum.isRawOreTransfer(baseInfo.getTransportBizType())) {
            logisticsGoods.setPrice(null);
        } else if (Objects.isNull(x.getPrice())) {
            logisticsGoods.setPrice(Objects.nonNull(baseInfo.getCommonPrice())? baseInfo.getCommonPrice().setScale(2,
                    RoundingMode.HALF_UP) : null);
        }else {
            logisticsGoods.setPrice(x.getPrice());
        }
        logisticsGoods.setPriceUnit(x.getAmountUnit());
        logisticsGoods.setCreateBy(LoginUserHolder.getUserId());
        logisticsGoods.setCreateTime(date1);
        logisticsGoods.setUpdateBy(LoginUserHolder.getUserId());
        logisticsGoods.setUpdateTime(date1);
        return logisticsGoods;
    }

    private void saveLogisticListUnit(List<Long> entIdList, LogisticListReq.TradeBaseInfo baseInfo, long contactId, Date date,Map<Long, EntCacheResDto> entCacheResDtoMap) {

        List<KwcContractLogisticsUnit> units = Lists.newArrayList();
        //存供应商
        if(Objects.nonNull(baseInfo.getProvideEntId())) {
            buildLogisticsUnit(contactId, baseInfo.getProvideEntId(), baseInfo.getProvidePhone(), entCacheResDtoMap,
                    date, units,CooperateTypeEnum.CONSIGN.getCode());
        }
        //存采购商
        if (Objects.nonNull(baseInfo.getPurchaseEntId())) {
            buildLogisticsUnit(contactId, baseInfo.getPurchaseEntId(), baseInfo.getPurchasePhone(), entCacheResDtoMap
                    , date, units,CooperateTypeEnum.CARRIAGE.getCode());
        }
        //删除企业
        kwcContractLogisticsUnitRepository.removeByContractId(contactId);
        kwcContractLogisticsUnitRepository.saveUnits(units);
    }


    private static void buildLogisticsUnit(long contactId, Long entId, String phone ,
                                           Map<Long
            , EntCacheResDto> entCacheResDtoMap, Date date, List<KwcContractLogisticsUnit> units,Integer unitType) {
        KwcContractLogisticsUnit kwcContractTradeUnit = new KwcContractLogisticsUnit();
        kwcContractTradeUnit.setId(new IdWorker(1L).nextId());
        kwcContractTradeUnit.setContractId(contactId);
        kwcContractTradeUnit.setUnitType(unitType);
        kwcContractTradeUnit.setEntId(entId);
        EntCacheResDto entCacheResDto = entCacheResDtoMap.get(kwcContractTradeUnit.getEntId());
        kwcContractTradeUnit.setFirmName("");
        kwcContractTradeUnit.setContacts("");
        kwcContractTradeUnit.setPhone("");
        if (Objects.nonNull(entCacheResDto)) {
            kwcContractTradeUnit.setFirmName(entCacheResDto.getFirmName());
            kwcContractTradeUnit.setContacts(entCacheResDto.getContacts());
            kwcContractTradeUnit.setPhone(entCacheResDto.getPhone());
            kwcContractTradeUnit.setContactsId(entCacheResDto.getContactsId());
        }

        kwcContractTradeUnit.setSignPhone(phone);
        kwcContractTradeUnit.setStatus(Global.NO);
        kwcContractTradeUnit.setCreateBy(LoginUserHolder.getUserId());
        kwcContractTradeUnit.setCreateTime(date);
        kwcContractTradeUnit.setUpdateBy(LoginUserHolder.getUserId());
        kwcContractTradeUnit.setUpdateTime(date);
        kwcContractTradeUnit.setDelFlag(Global.NO);
        units.add(kwcContractTradeUnit);
    }

    public QueryLogisticDetailResp queryLogisticsContractDetail(ContractDetailReq req) {
        log.info("查询物流合同明细参数：{}", JSON.toJSONString( req));
        if (Objects.isNull(req.getContractId())){
            throw new BusinessException("物流合同id不能为空");
        }
        KwcContractLogistics logistics = kwcContractLogisticsRepository.queryById(Long.valueOf(req.getContractId()));
        if (Objects.isNull(logistics)){
            throw new BusinessException("物流合同不存在");
        }

        //合同id
        Long contractId = logistics.getId();

        //查询物流商品信息
        List<KwcContractLogisticsGoods> kwcContractLogisticsGoods =kwcContractLogisticsGoodsRepository.queryByContractId(contractId);


        List<KwcContractLogisticsUnit> kwcContractLogisticsUnits =
                kwcContractLogisticsUnitRepository.queryByContractId(contractId);
        Map<String, KwcContractLogisticsUnit> contractUniTypeAndUnitMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwcContractLogisticsUnits)){
            //合同id和单位类型组合成key映射物流企业信息
            contractUniTypeAndUnitMap = kwcContractLogisticsUnits.stream()
                    .collect(Collectors.toMap(k->k.getContractId() + "-" + k.getUnitType(), Function.identity(),
                            (x, y) -> x));
        }
        //查询字典
        Map<String, Map<String, String>> dictValueAndDictResDtoMap = remoteSystemService.queryDictByType(Arrays.asList(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.GOODS_SPEC.getType()));
//        Map<String, SysDictResDto> dictValueAndDictResDtoMap = new HashMap<>();
//        if (CollectionUtils.isNotEmpty(sysDictResDtos)){
//            //字典value映射字典
//            dictValueAndDictResDtoMap = sysDictResDtos.stream()
//                    .collect(Collectors.toMap(SysDictResDto::getValue, Function.identity()));
//
//        }

        return getQueryLogisticDetailResp(logistics, contractUniTypeAndUnitMap, kwcContractLogisticsGoods,dictValueAndDictResDtoMap);

    }

    @NotNull
    private QueryLogisticDetailResp getQueryLogisticDetailResp(KwcContractLogistics logistics,
                                                               Map<String, KwcContractLogisticsUnit> contractUniTypeAndUnitMap,
                                                               List<KwcContractLogisticsGoods> kwcContractLogisticsGoods,
                                                               Map<String, Map<String, String>> dictValueAndDictResDtoMap) {
        QueryLogisticDetailResp queryLogisticListResp = new QueryLogisticDetailResp();
        queryLogisticListResp.setId(logistics.getId());
        queryLogisticListResp.setPid(logistics.getContractPid());
        QueryLogisticDetailResp.TradeBaseInfo tradeBaseInfo = new QueryLogisticDetailResp.TradeBaseInfo();
        KwcContractLogisticsUnit logisticsUnit = contractUniTypeAndUnitMap.get(logistics.getId() + "-" + CooperateTypeEnum.CARRIAGE.getCode());
        if (Objects.nonNull(logisticsUnit)){
            tradeBaseInfo.setPurchaseEntId(logisticsUnit.getEntId());
            tradeBaseInfo.setPurchasePhone(logisticsUnit.getPhone());
        }
        KwcContractLogisticsUnit providerLogisticsUnit =
                contractUniTypeAndUnitMap.get(logistics.getId() + "-" + CooperateTypeEnum.CONSIGN.getCode());
        if (Objects.nonNull(providerLogisticsUnit)){
            tradeBaseInfo.setProvideEntId(providerLogisticsUnit.getEntId());
            tradeBaseInfo.setProvidePhone(providerLogisticsUnit.getPhone());
        }

        tradeBaseInfo.setContractCode(logistics.getContractNo());
        tradeBaseInfo.setContractName(logistics.getName());
        if (Objects.nonNull(logistics.getEndTime())) {
            String endDate = DateUtils.format(logistics.getEndTime(), DateUtils.DATE_PATTERN);
            if (org.apache.commons.lang3.StringUtils.equals(endDate,"9999-12-30")){
                tradeBaseInfo.setEndTime(null);
            }else {
                tradeBaseInfo.setEndTime(logistics.getEndTime());
            }
        }
        tradeBaseInfo.setSigningWay(logistics.getSigningWay());
        tradeBaseInfo.setSigningWayDesc(DictEnum.getLabel(DictTypeEnum.SIGNING_TYPE.getType(),
                String.valueOf(logistics.getSigningWay())));

        //派车方式
        tradeBaseInfo.setDispatchWay(logistics.getDispatchWay());
        tradeBaseInfo.setDispatchWayDesc(DispatchingTypeEnum.getLabel(logistics.getDispatchWay()));

        tradeBaseInfo.setStartTime(logistics.getStartTime());

        Integer transportBizType = logistics.getTransportBizType();
        if (transportBizType == null) {
            transportBizType = LogisticsTransportBizTypeEnum.TRADE_TRANSPORT.getCode();
        }
        tradeBaseInfo.setTransportBizType(transportBizType);
        tradeBaseInfo.setTransportBizTypeDesc(LogisticsTransportBizTypeEnum.getLabelByCode(transportBizType));
        tradeBaseInfo.setAllowedError(logistics.getAllowedError());

        BigDecimal commonPrice = logistics.getCommonPrice();
        tradeBaseInfo.setCommonPrice(commonPrice != null && commonPrice.compareTo(BigDecimal.ZERO) == 0 ? null : commonPrice);
        tradeBaseInfo.setContractStatus(String.valueOf(logistics.getStatus()));
        tradeBaseInfo.setContractStatusDesc(ContractStatusEnum.getNameByCode(logistics.getStatus()));
        tradeBaseInfo.setSettlement(logistics.getSettlement());
        tradeBaseInfo.setSettlementDesc(Objects.equals(1, logistics.getSettlement()) ? "普通结算" : "记账模式");

        queryLogisticListResp.setBaseInfo(tradeBaseInfo);
        queryLogisticListResp.setContractFile(logistics.getSigningUrl());
        List<QueryLogisticDetailResp.TradeGoodsInfo> tradeGoodsInfos = Lists.newArrayList();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(kwcContractLogisticsGoods)){
            //查询商品信息
            Map<Long, KwpGoods> kwpGoodsMap = goodsInfoService.getGoodsByIds(kwcContractLogisticsGoods.
                    stream().map(KwcContractLogisticsGoods::getGoodsId)
                            .distinct()
                    .collect(Collectors.toList()));
            tradeGoodsInfos = kwcContractLogisticsGoods.stream()
                    .map(x->getTradeGoodsInfo(x, kwpGoodsMap,dictValueAndDictResDtoMap))
                    .collect(Collectors.toList());
        }

        queryLogisticListResp.setGoodsInfo(tradeGoodsInfos);
        queryLogisticListResp.setRemark(logistics.getRemark());
        return queryLogisticListResp;
    }

    private static QueryLogisticDetailResp.TradeGoodsInfo getTradeGoodsInfo(KwcContractLogisticsGoods x,
                                                                            Map<Long, KwpGoods> kwpGoodsMap,
                                                                            Map<String, Map<String, String>> dictValueAndDictResDtoMap) {
        QueryLogisticDetailResp.TradeGoodsInfo tradeGoodsInfo = new QueryLogisticDetailResp.TradeGoodsInfo();
        tradeGoodsInfo.setGoodsId(x.getGoodsId());
        KwpGoods kwpGoods = kwpGoodsMap.getOrDefault(x.getGoodsId(), new KwpGoods());
       // SysDictResDto sysDictResDto = dictValueAndDictResDtoMap.getOrDefault(kwpGoods.getGoodsType(), new SysDictResDto());
        Map<String, String> goodTypeMap = dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), new HashMap<>());
        Map<String, String> goodSpecMap = dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.GOODS_SPEC.getType(), new HashMap<>());
        tradeGoodsInfo.setGoodsName(kwpGoods.getName()+"/"+goodTypeMap.getOrDefault(kwpGoods.getGoodsType(),"")+"/"+goodSpecMap.getOrDefault(kwpGoods.getSpec(), ""));
        tradeGoodsInfo.setAmount(x.getAmount());
        tradeGoodsInfo.setAmountUnit(x.getUnit());
        tradeGoodsInfo.setPrice(x.getPrice());
        return tradeGoodsInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean updateLogistics(UpdateLogisticsReq req) {
        log.info("更新物流合同参数：{}", JSON.toJSONString( req));
        KwcContractLogistics logistics = kwcContractLogisticsRepository.queryById(req.getLogContractId());
        if (Objects.isNull(logistics)){
            throw new BusinessException("物流合同不存在");
        }
        KwcContractLogistics updateLogistics = new KwcContractLogistics();
        if (Objects.nonNull(req.getLogStatus()) && Objects.equals(logistics.getStatus(),
                ContractStatusEnum.SUBMIT.getCode())){
            updateLogistics.setStatus(req.getLogStatus());
            updateLogistics.setId(logistics.getId());
        }
        if (Objects.nonNull(req.getLogStatus()) && Objects.equals(logistics.getStatus(),ContractStatusEnum.SIGNED.getCode())){
            updateLogistics.setStatus(req.getLogStatus());
            updateLogistics.setId(logistics.getId());
        }
        Boolean result = kwcContractLogisticsRepository.updateLogistics(updateLogistics);
        if(Integer.valueOf(ContractStatusEnum.SIGNED.getCode()).equals(updateLogistics.getStatus()) && result){
            //物流合同签约成功，建立运费清单
            //查询物流企业信息
            List<KwcContractLogisticsUnit> kwcContractLogisticsUnits = kwcContractLogisticsUnitRepository.queryByContractIds(Collections.singleton(logistics.getId()));
            Map<Integer, KwcContractLogisticsUnit> collect = kwcContractLogisticsUnits.stream().collect(Collectors.toMap(KwcContractLogisticsUnit::getUnitType, Function.identity(), (x, y) -> x));
            WalletPayableDto payableAddDto = new WalletPayableDto();
            payableAddDto.setConsignEntId(collect.get(CooperateTypeEnum.CONSIGN.getCode()).getEntId());
            payableAddDto.setCarriageEntId(collect.get(CooperateTypeEnum.CARRIAGE.getCode()).getEntId());
            payableAddDto.setTradeAmount(BigDecimal.ZERO);
            payableAddDto.setRemark("运费清单初始化");
            BaseResult<Object> payable = paymentFeignService.initPayable(payableAddDto);
            if (payable.getCode() == HttpStatus.SUCCESS_CODE){
                log.info("创建运费清单成功");
            }else {
                log.error("创建运费清单失败");
                throw new BusinessException("创建运费清单失败");
            }
        }
        return result;
    }

    public ContractStatusCountResp queryLogisticContractStatusCount( QueryLogisticListReq req) {

        log.info("查询物流合同订单状态统计");
        ContractStatusCountResp contractStatusCountResp = new ContractStatusCountResp();
        contractStatusCountResp.setTotalNum("0");
        List<ContractStatusEnum> statusEnums = Arrays.stream(ContractStatusEnum.values())
                .sorted(Comparator.comparing(ContractStatusEnum::getCode))
                .collect(Collectors.toList());

        Long entId;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getEntId())){
            entId = Long.valueOf(req.getEntId());
        }else {
            entId = LoginUserHolder.getEntId();
        }
        List<Long> entIdList = Lists.newArrayList();
        entIdList.add(entId);
        Integer type = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getConsignCompanyId())){
            entIdList.add(Long.valueOf(req.getConsignCompanyId()));
            type = CooperateTypeEnum.CONSIGN.getCode();
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getCarriageCompanyId())){
            entIdList.add(Long.valueOf(req.getCarriageCompanyId()));
            type = CooperateTypeEnum.CARRIAGE.getCode();
        }
        //查询物流企业
        Set<Long> contractIdList = Sets.newHashSet();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIdList)){
            List<KwcContractLogisticsUnit> units = kwcContractLogisticsUnitRepository.queryByEntIds(entIdList,type);
            if (CollectionUtils.isNotEmpty(units)) {
                Set<Long> contractIds = units.stream().filter(x -> Objects.equals(x.getEntId(), entId))
                        .map(KwcContractLogisticsUnit::getContractId)
                        .collect(Collectors.toSet());
                contractIdList = units.stream()
                        .map(KwcContractLogisticsUnit::getContractId)
                        .filter(contractId ->contractIds.contains(contractId)).collect(Collectors.toSet());
            }
        }
        applyContractTypeFilterToIds(req, entId, contractIdList);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractIdList) && org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIdList)){
            Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = new HashMap<>();
            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
                    .map(x -> getContractStatusCount(x, statusAndLogOrdersMap))
                    .collect(Collectors.toList());
            contractStatusCountResp.setContractStatusInfo(statusCounts);
        }

        if(org.apache.commons.collections4.CollectionUtils.isEmpty(contractIdList)
                && (!org.apache.commons.lang3.StringUtils.isAllBlank(req.getConsignCompanyId(),req.getCarriageCompanyId()) || Objects.nonNull(entId))){
            Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = new HashMap<>();
            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
                    .map(x -> getContractStatusCount(x, statusAndLogOrdersMap))
                    .collect(Collectors.toList());
            contractStatusCountResp.setContractStatusInfo(statusCounts);
            return contractStatusCountResp;
        }


        DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
        contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
        if (CollectionUtils.isEmpty(contractIdList)) {
            Map<Integer, List<KwcContractLogistics>> emptyMap = new HashMap<>();
            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
                    .map(x -> getContractStatusCount(x, emptyMap))
                    .collect(Collectors.toList());
            contractStatusCountResp.setContractStatusInfo(statusCounts);
            return contractStatusCountResp;
        }
        List<KwcContractLogistics> contractLogistics = kwcContractLogisticsRepository.queryList(contractIdList,req.getContractNo(),req.getContractName(),req.getStatus());

        // 如果过滤后无数据，则返回各状态计数均为0的结果
        if (CollectionUtils.isEmpty(contractLogistics)){
            Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = new HashMap<>();
            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
                    .map(x -> getContractStatusCount(x, statusAndLogOrdersMap))
                    .collect(Collectors.toList());
            contractStatusCountResp.setContractStatusInfo(statusCounts);
            return contractStatusCountResp;
        }
        Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap = contractLogistics.stream().collect(Collectors.groupingBy(KwcContractLogistics::getStatus));
        return getContractStatusCountResp(statusEnums, statusAndLogOrdersMap, contractStatusCountResp, contractLogistics);
    }

    @NotNull
    private static ContractStatusCountResp getContractStatusCountResp(List<ContractStatusEnum> statusEnums,
                                                                      Map<Integer, List<KwcContractLogistics>> statusAndLogOrdersMap,
                                                                      ContractStatusCountResp contractStatusCountResp,
                                                                      List<KwcContractLogistics> kwcContractLogistics) {
        List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
                .map(x -> getContractStatusCount(x, statusAndLogOrdersMap))
                .collect(Collectors.toList());
        contractStatusCountResp.setContractStatusInfo(statusCounts);
        contractStatusCountResp.setTotalNum(String.valueOf(kwcContractLogistics.size()));
        return contractStatusCountResp;
    }

    private static ContractStatusCountResp.ContractStatusCount getContractStatusCount(ContractStatusEnum statusEnum, Map<Integer, List<KwcContractLogistics>> finalStatusAndLogOrdersMap1) {
        ContractStatusCountResp.ContractStatusCount contractStatusCount = new ContractStatusCountResp.ContractStatusCount();
        contractStatusCount.setOrderStatus(String.valueOf(statusEnum.getCode()));
        contractStatusCount.setOrderStatusDesc(statusEnum.getName());
        contractStatusCount.setOrderNum(String.valueOf(finalStatusAndLogOrdersMap1.getOrDefault(statusEnum.getCode(), new ArrayList<>()).size()));
        return contractStatusCount;
    }

    public List<TradeEntInfoResVo> queryTradeEntList(TradeEntListQueryFeignDto queryFeignDto) {
        List<TradeEntInfoResVo> resVos =  new ArrayList<>();
        Long entId = queryFeignDto.getCurEntId();
        Set<Long> entIds = Sets.newHashSet();
        entIds.add(entId);
        Set<Long> contractIds = null;
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIds)) {
            List<KwcContractLogisticsUnit> units = kwcContractLogisticsUnitService.queryByEntIds(entIds);
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(units)) {
                contractIds = units.stream()
                        .map(KwcContractLogisticsUnit::getContractId)
                        .collect(Collectors.toSet());
            }
        }
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractIds)) {
            return Collections.emptyList();
        }
        List<KwcContractLogisticsUnit> tradeUnits = kwcContractLogisticsUnitService.queryByContractIdsAndEntType(contractIds, queryFeignDto.getTradeEntType());
        for (KwcContractLogisticsUnit tradeUnit : tradeUnits) {
            TradeEntInfoResVo resVo = new TradeEntInfoResVo();
            resVo.setEntId(tradeUnit.getEntId());
            resVo.setEntName(tradeUnit.getFirmName());
            resVos.add(resVo);
        }
        return resVos;
    }


    /**
     * 根据数据权限过滤物流合同ID集合。
     * <p>
     * 处理逻辑：
     * 1. 如果无需过滤或输入为空，直接返回。
     * 2. 如果不是全部可见（即有企业范围限制），则通过物流合同关联的企业ID进行过滤，只保留当前用户可见企业下的合同。
     * 3. 如果开启了个人数据权限，进一步过滤，只保留销售员为当前用户的合同（通过运单->贸易订单->贸易合同链路关联）。
     * </p>
     *
     * @param contractIdList 待过滤的物流合同ID集合
     * @param perm           数据权限DTO
     * @return 过滤后的物流合同ID集合
     */
    private Set<Long> applyDataPermissionToLogisticsContractIds(Set<Long> contractIdList, DataPermissionDTO perm) {
        // 1. 基础校验：如果权限对象为空、不需要过滤或合同ID列表为空，直接返回原列表
        if (perm == null || !perm.needFilter() || CollectionUtils.isEmpty(contractIdList)) {
            return contractIdList;
        }

        log.debug("开始应用物流合同数据权限过滤, 初始合同数量: {}, 用户ID: {}", contractIdList.size(), perm.getUserId());

        // 2. 企业范围过滤：如果不是全部可见，则根据可见企业ID过滤合同
        if (!perm.isAllVisible()) {
            if (CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
                log.debug("无可见企业权限，清空合同列表");
                contractIdList.clear();
                return contractIdList;
            }

            // 查询可见企业下的所有物流合同单位
            List<KwcContractLogisticsUnit> permUnits =
                    kwcContractLogisticsUnitRepository.queryByEntIds(new ArrayList<>(perm.getVisibleEntIds()), null);

            // 提取这些单位关联的合同ID
            Set<Long> entScopeContractIds = permUnits.stream()
                    .map(KwcContractLogisticsUnit::getContractId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 取交集：只保留在可见企业范围内的合同
            int beforeSize = contractIdList.size();
            contractIdList.retainAll(entScopeContractIds);
            log.debug("企业范围过滤完成, 过滤前: {}, 过滤后: {}", beforeSize, contractIdList.size());
        }

        // 如果经过企业范围过滤后列表为空，直接返回
        if (CollectionUtils.isEmpty(contractIdList)) {
            return contractIdList;
        }

        // 3. 个人数据权限过滤：如果开启，需进一步校验销售员身份
        if (perm.isPersonalDataEnabled()) {
            Long uid = perm.getUserId();
            if (uid == null) {
                log.warn("个人数据权限开启但用户ID为空，清空合同列表");
                contractIdList.clear();
                return contractIdList;
            }

            log.debug("开启个人数据权限过滤, 校验销售员ID: {}", uid);
            // 通过关联的贸易合同销售员进行过滤
            Set<Long> salesMatched = retainLogisticsContractIdsByLinkedTradeSalesman(contractIdList, uid);

            // 更新原列表为过滤后的结果
            contractIdList.clear();
            contractIdList.addAll(salesMatched);
            log.debug("个人数据权限过滤完成, 最终合同数量: {}", contractIdList.size());
        }

        return contractIdList;
    }

    /**
     * 根据关联的贸易合同销售员过滤物流合同ID。
     * <p>
     * 关联链路：物流合同 -> 运单 (RWaybillSubOrderVo) -> 贸易订单ID -> 贸易订单详情 (TradeOrderContractVo) -> 贸易合同ID -> 贸易合同实体 (KwcContractTrade) -> 销售员ID
     * </p>
     *
     * @param logContractIds 物流合同ID集合
     * @param salesmanUserId 销售员用户ID
     * @return 符合销售员权限的物流合同ID集合
     */
    private Set<Long> retainLogisticsContractIdsByLinkedTradeSalesman(Set<Long> logContractIds, Long salesmanUserId) {
        if (CollectionUtils.isEmpty(logContractIds) || salesmanUserId == null) {
            return Collections.emptySet();
        }

        log.debug("开始解析物流合同关联的贸易销售员, 物流合同数: {}", logContractIds.size());

        // 1. 查询物流合同关联的运单信息
        List<RWaybillSubOrderVo> orderLinks = transportRemoteService.queryWaybillOrderByLogContractIds(logContractIds);
        if (CollectionUtils.isEmpty(orderLinks)) {
            log.debug("未找到关联的运单信息");
            return Collections.emptySet();
        }

        // 2. 从运单中提取贸易订单ID (tradeId)
        Set<Long> tradeOrderIds = orderLinks.stream()
                .map(RWaybillSubOrderVo::getTradeId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(tradeOrderIds)) {
            log.debug("运单中未包含有效的贸易订单ID");
            return Collections.emptySet();
        }

        // 3. 批量查询贸易订单详情，获取贸易订单与贸易合同的映射关系
        List<TradeOrderContractVo> tradeOrderContracts = tradeOrderInfoService.queryTradeOrderIds(tradeOrderIds);
        if (CollectionUtils.isEmpty(tradeOrderContracts)) {
            log.debug("未找到对应的贸易订单详情");
            return Collections.emptySet();
        }

        // 4. 构建 物流合同ID -> 贸易合同ID集合 的映射
        Map<Long, Set<Long>> logToTradeContractIds = buildLogContractTradeContractIdsMap(orderLinks, tradeOrderContracts);
        if (logToTradeContractIds.isEmpty()) {
            log.debug("未能建立物流合同到贸易合同的映射");
            return Collections.emptySet();
        }

        // 5. 收集所有涉及的贸易合同ID
        Set<Long> tradeContractIds = logToTradeContractIds.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());

        // 6. 批量查询贸易合同实体，构建 ID -> 实体 的映射，以便获取销售员ID
        Map<Long, KwcContractTrade> tradeMap = kwcContractTradeRepository.findByContractIds(tradeContractIds).stream()
                .collect(Collectors.toMap(KwcContractTrade::getId, Function.identity(), (a, b) -> a));

        // 7. 遍历物流合同，检查其关联的贸易合同中是否有指定销售员
        Set<Long> result = new HashSet<>();
        for (Long logId : logContractIds) {
            Set<Long> relTradeContractIds = logToTradeContractIds.get(logId);
            if (CollectionUtils.isEmpty(relTradeContractIds)) {
                continue;
            }

            // 只要有一个关联的贸易合同的销售员是指定用户，则该物流合同可见
            boolean ok = relTradeContractIds.stream()
                    .map(tradeMap::get)
                    .filter(Objects::nonNull)
                    .anyMatch(t -> salesmanUserId.equals(t.getSalesmanId()));

            if (ok) {
                result.add(logId);
            }
        }

        log.debug("销售员权限过滤结束, 匹配到的物流合同数: {}", result.size());
        return result;
    }

    /**
     * 构建物流合同ID到贸易合同ID集合的映射关系。
     *
     * @param orderLinks         运单列表
     * @param tradeOrderContracts 贸易订单与合同关联列表
     * @return Map<物流合同ID, Set<贸易合同ID>>
     */
    private Map<Long, Set<Long>> buildLogContractTradeContractIdsMap(List<RWaybillSubOrderVo> orderLinks,
                                                                     List<TradeOrderContractVo> tradeOrderContracts) {
        // 构建 贸易订单ID -> 贸易合同ID 的映射
        Map<Long, Long> tradeOrderIdToContractId = tradeOrderContracts.stream()
                .filter(item -> item.getTOrderId() != null && item.getContractId() != null)
                .collect(Collectors.toMap(TradeOrderContractVo::getTOrderId, TradeOrderContractVo::getContractId, (a, b) -> a));

        Map<Long, Set<Long>> result = new HashMap<>();
        for (RWaybillSubOrderVo link : orderLinks) {
            if (link.getLogContractId() == null || link.getTradeId() == null) {
                continue;
            }

            // 获取运单关联的贸易订单对应的贸易合同ID
            Long tradeContractId = tradeOrderIdToContractId.get(link.getTradeId());
            if (tradeContractId == null) {
                continue;
            }

            // 将贸易合同ID加入该物流合同对应的集合中
            result.computeIfAbsent(link.getLogContractId(), k -> new HashSet<>()).add(tradeContractId);
        }

        log.debug("构建物流合同-贸易合同映射完成, 映射数量: {}", result.size());
        return result;
    }

    /**
     * 获取当前用户的数据权限配置
     * <p>
     * 通过远程服务获取当前登录用户的数据权限过滤条件，包括可见企业ID、个人数据权限开关等。
     * 如果获取失败，记录警告日志并返回null，后续逻辑将跳过权限过滤。
     * </p>
     *
     * @return 数据权限DTO，如果获取失败则返回null
     */
    private DataPermissionDTO fetchDataPermissionForCurrentUser() {
        try {
            DataPermissionFilterReqDto reqDto = new DataPermissionFilterReqDto();
            reqDto.setUserId(LoginUserHolder.getUserId());
            reqDto.setRoleId(LoginUserHolder.getCurrentRoleId());
            reqDto.setManager(LoginUserHolder.isManager());
            return dataPermissionFeignService.getDataPermissionFilter(reqDto);
        } catch (Exception e) {
            log.warn("获取物流合同数据权限失败，跳过权限过滤: {}", e.getMessage());
            return null;
        }
    }

    public List<ContractGoodsVo> queryLogisticsGoods(Long contractId, String keyword) {
        return kwcContractLogisticsMapper.selectGoods(contractId,keyword);
    }

    public List<LogisticsEntDto> queryLogisticsContract(String keyword) {
        return kwcContractLogisticsMapper.queryContract(LoginUserHolder.getEntId(), keyword);
    }
}
