package com.jwipc.order.logic.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.jwipc.aggregation.ModelAggregationService;
import com.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.ApiResult;
import com.jwipc.constant.DelFlag;
import com.jwipc.constant.DictCode;
import com.jwipc.constant.EnableStatus;
import com.jwipc.constant.FlagConst;
import com.jwipc.exception.DaoException;
import com.jwipc.inquiry.dto.HistoryPriceInfoDTO;
import com.jwipc.log.constant.ThirdSysType;
import com.jwipc.order.clent.dto.UpdateOrderDTO;
import com.jwipc.order.constant.DeliveryStatus;
import com.jwipc.order.constant.DeliveryType;
import com.jwipc.order.constant.PrintTemplateCode;
import com.jwipc.order.convert.DeliveryOrderConvert;
import com.jwipc.order.convert.DeliveryOrderDetailConvert;
import com.jwipc.order.convert.DeliveryOrderFileConvert;
import com.jwipc.order.dto.*;
import com.jwipc.order.entity.*;
import com.jwipc.order.logic.*;
import com.jwipc.order.model.query.DeliveryOrderQuery;
import com.jwipc.order.service.*;
import com.jwipc.order.util.FtpUtils;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.prop.SysProp;
import com.jwipc.security.LoginUtil;
import com.jwipc.spe.client.QualityManageClient;
import com.jwipc.spe.client.base.dto.QualityManageClientDTO;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.*;
import com.jwipc.sys.client.dto.*;
import com.jwipc.sys.entity.Attachment;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.entity.LogThirdPartyCall;
import com.jwipc.sys.service.IBusinessAttachmentService;
import com.jwipc.sys.service.ILogThirdPartyCallService;
import com.jwipc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;
import static com.jwipc.constant.DictCode.DELIVERY_TYPE;
import static com.jwipc.order.constant.SequenceConst.DELIVERY_CODE;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DeliveryOrderLogicImpl implements DeliveryOrderLogic {

    private final DeliveryOrderControlLogic deliveryOrderControlLogic;
    private final IDeliveryOrderService deliveryOrderService;
    private final FtpFileLogic fileLogic;
    private final IPurchaseOrderService purchaseOrderService;
    private final DeliveryOrderConvert deliveryOrderConvert;
    private final FactoryClient factoryClient;
    private final IDeliveryOrderFileService deliveryOrderFileService;
    private final DeliveryOrderDetailConvert deliveryOrderDetailConvert;
    private final SequenceClient sequenceClient;
    private final IDeliveryOrderDetailService deliveryOrderDetailService;
    private final SupplierClient supplierClient;
    private final DeliveryOrderFileConvert deliveryOrderFileConvert;
    private final DeliveryOrderPushMesLogic deliveryOrderPushMesLogic;
    private final DeliveryOrderPushSapLogic deliveryOrderPushSapLogic;
    private final PurchaseOrderCountLogic purchaseOrderCountLogic;
    private final IAppointmentDockerService appointmentDockerService;
    private final IAppointmentSupplierService appointmentSupplierService;
    private final IPurchaseOrderBomService purchaseOrderBomService;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final IAppointmentRecordService appointmentRecordService;
    private final PrintTemplateClient printTemplateClient;
    private final DictClient dictClient;
    private final ModelAggregationService modelAggregationService;
    private final UserClient userClient;
    private final ProductClient productClient;
    private final IPurchaseOrderDevPlanService purchaseOrderDevPlanService;
    private final QualityManageClient qualityManageClient;
    private final EmailSendClient emailSendClient;
    private final UserPurchaseGroupClient userPurchaseGroupClient;
    private final SysProp sysProp;
    private final static String DeliveryOrderLock = "DeliveryOrderLock_";
    private final StringRedisTemplate redisTemplate;
    private final IBusinessAttachmentService businessAttachmentService;
    private final ILogThirdPartyCallService logThirdPartyCallService;

    // 使用静态锁，确保所有实例共享同一把锁
    private static final ReentrantLock lock = new ReentrantLock();
    @Value("${sys.ftp.localTempFileDir}")
    private String LOCAL_TEMP_FILE_DIR;

    @Value("${sys.ftp.remoteRootDir}")
    private String REMOTE_ROOT_DIR;
    @Autowired
    private FtpUtils ftpUtils;


    @Override
    public DeliveryOrder getDeliveryOrderByCode(String code)
    {
        final DeliveryOrder deliveryOrder = deliveryOrderService.getOne(
                new LambdaQueryWrapper<DeliveryOrder>().eq(DeliveryOrder::getOrderCode, code));
        return deliveryOrder;
    }

    @Override
    public DeliveryOrderLookupDTO getDefaultDetail(DeliveryOrderLookupDTO deliveryOrderBaseDTO, Long id)
    {
        if (id != 0L) {
            final DeliveryOrder byId = deliveryOrderService.getById(id);
            DeliveryOrderLookupDTO orderBaseDTO = deliveryOrderConvert.entity2Dto1(byId);
            //如果存在附件需要把附件查询到
            final List<DeliveryOrderFile> list = deliveryOrderFileService.list(
                    new LambdaQueryWrapper<DeliveryOrderFile>().eq(DeliveryOrderFile::getMasterId,
                            orderBaseDTO.getId()));
            final String fileIds = list.stream().map(a -> String.valueOf(a.getFileId()))
                    .collect(Collectors.joining(StrUtil.COMMA));
            orderBaseDTO.setFileIds(fileIds);
            return orderBaseDTO;
        } else {
            //需要判断登录人是不是供应商，如果是供应商直接获取供应商数据
            if (LoginUtil.isSupplier()) {
                if(StringUtils.isNotEmpty(deliveryOrderBaseDTO.getSupplierCode1())&& !deliveryOrderBaseDTO.getSupplierCode1().equals("0")){
                    final SupplierDTO supplierByCode = supplierClient.getSupplierByCode(deliveryOrderBaseDTO.getSupplierCode1());
                    deliveryOrderBaseDTO.setSupplierName(supplierByCode.getSupplierName());
                    deliveryOrderBaseDTO.setSupplierErpCode(deliveryOrderBaseDTO.getSupplierCode1());
                }else{
                    deliveryOrderBaseDTO.setSupplierErpCode(LoginUtil.getSupplierCode());
                    final SupplierDTO supplierByCode = supplierClient.getSupplierByCode(LoginUtil.getSupplierCode());
                    deliveryOrderBaseDTO.setSupplierName(supplierByCode.getSupplierName());
                }
            }
            //需要查询送货单历史最新的发货人和联系方式
            final DeliveryOrder lastDeliveryOrder = deliveryOrderService.getOne(
                    new LambdaQueryWrapper<DeliveryOrder>().eq(DeliveryOrder::getSupplierErpCode,
                                    deliveryOrderBaseDTO.getSupplierErpCode())
                            .eq(DeliveryOrder::getDelFlag, DelFlag.NORMAL.getStatus())
                            .orderBy(true, false, DeliveryOrder::getId), false);
            final PurchaseOrder purchaseOrder = purchaseOrderService.getById(deliveryOrderBaseDTO.getPurOrderId());
            final String remark = purchaseOrder.getRemark();
            if (Objects.isNull(lastDeliveryOrder)) {
                final String facotryAddress = factoryClient.getFacotryAddress(deliveryOrderBaseDTO.getFactoryCode());
                deliveryOrderBaseDTO.setReceiverAddress(facotryAddress);
                final AppointmentDocker docker = appointmentDockerService.getOne(
                        new LambdaQueryWrapper<AppointmentDocker>().eq(AppointmentDocker::getFactoryCode,
                                deliveryOrderBaseDTO.getFactoryCode()), false);
                if (Objects.nonNull(docker)) {
                    deliveryOrderBaseDTO.setDockerCode(docker.getDockerCode());
                }
                return deliveryOrderBaseDTO;
            }
            DeliveryOrderLookupDTO orderBaseDTO = new DeliveryOrderLookupDTO();
            orderBaseDTO.setSupplierErpCode(lastDeliveryOrder.getSupplierErpCode());
            orderBaseDTO.setSupplierName(lastDeliveryOrder.getSupplierName());
            orderBaseDTO.setFactoryCode(deliveryOrderBaseDTO.getFactoryCode());
            orderBaseDTO.setFactoryName(deliveryOrderBaseDTO.getFactoryName());
            orderBaseDTO.setCompanyCode(deliveryOrderBaseDTO.getCompanyCode());
            orderBaseDTO.setCompanyName(deliveryOrderBaseDTO.getCompanyName());
            orderBaseDTO.setId(null);
            orderBaseDTO.setConsigner(lastDeliveryOrder.getConsigner());
            orderBaseDTO.setPhone(lastDeliveryOrder.getPhone());
            orderBaseDTO.setRemark(remark);
            final String facotryAddress = factoryClient.getFacotryAddress(deliveryOrderBaseDTO.getFactoryCode());
            orderBaseDTO.setReceiverAddress(facotryAddress);
            final AppointmentDocker docker = appointmentDockerService.getOne(
                    new LambdaQueryWrapper<AppointmentDocker>().eq(AppointmentDocker::getFactoryCode,
                            deliveryOrderBaseDTO.getFactoryCode()), false);
            if (Objects.nonNull(docker)) {
                orderBaseDTO.setDockerCode(docker.getDockerCode());
            }
            return orderBaseDTO;
        }

    }

    /**
     * 注意这个地方只有新增直接发货不存在修改
     *
     * @param deliveryOrderSaveDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DS(SLAVE)
    public Pair<String, Set<String>> saveOrUpdate(DeliveryOrderSaveDTO deliveryOrderSaveDTO) {
        //增加redis锁如果这个供应商的数据正在处理就直接返回
        final String lockKey = DeliveryOrderLock + LoginUtil.getUserId();
        if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
            log.info("系统正在处理，请稍后");
            throw new DaoException("系统正在处理，请稍后提交!");
        }
//        if (!LoginUtil.isSupplier()) {
//            //需要判断供应商编码是不是1001和5012
//            if (deliveryOrderSaveDTO.getSupplierErpCode().equals("1001") ||
//                    deliveryOrderSaveDTO.getSupplierErpCode().equals("5012")) {
//                throw new DaoException("1001和5012为物流商，采购不允许代创建送货单!");
//            }
//        }
        //需要保存送货单信息
        DeliveryOrder deliveryOrder = deliveryOrderConvert.dto2Entity(deliveryOrderSaveDTO);
        final List<DeliveryOrderDetailBaseDTO> item = deliveryOrderSaveDTO.getItem();
        if (CollectionUtils.isEmpty(item)) {
            throw new DaoException("没有送货单明细行");
        }
        //增加送货单订单+行号重复校验
        //增加校验是否有重复的check
        Map<String, Integer> checkMap = new HashMap<>();
        for (DeliveryOrderDetailBaseDTO orderDetail : item) {
           String orderCode = orderDetail.getPurchaseOrderCode();
           String orderRow = orderDetail.getPurchaseOrderRow();
           String key = orderCode+":"+orderRow;
            if( checkMap.get(key) == null){
                checkMap.put(key,1);
            }else{
                checkMap.put(key,checkMap.get(key) + 1);
            }
        }

        for (DeliveryOrderDetailBaseDTO orderDetail : item) {
            String orderCode = orderDetail.getPurchaseOrderCode();
            String orderRow = orderDetail.getPurchaseOrderRow();
            String key = orderCode+":"+orderRow;
            if(checkMap.get(key) > 1){
                final String format = StrUtil.format("创建送货单失败:{}-{},订单和订单行号重复", orderCode,
                        orderRow);
                throw new DaoException(format);
            }
        }




        List<DeliveryOrderDetail> details = deliveryOrderDetailConvert.dtos2Entities(item);
        //我选择需要根据集合的物料编码进行排序
        details = details.stream().sorted(Comparator.comparing(DeliveryOrderDetail::getMaterialCode))
                .collect(Collectors.toList());
        //需要校验明细和行的工厂是否一致
        if (!details.stream().allMatch(a -> a.getFactoryCode().equals(deliveryOrder.getFactoryCode()))) {
            throw new DaoException("送货单明细和行工厂不一致");
        }
        //需要把订单中是锁定的数据查询出来
        //送货单创建成需要把锁定标记给还原
        Set<Long> purchaseOrderDetailIds = new HashSet<>();
        Set<String> unlockPurchaseDetail = Sets.newHashSet();
        //查询订单数据
        final Set<String> purchaseCodes = item.stream().map(DeliveryOrderDetailBaseDTO::getPurchaseOrderCode)
                .collect(Collectors.toSet());
        Map<String, String> purchaseOrderMarkFlagCache = Maps.newHashMap();
        Map<String, PurchaseOrder> purchaseOrderCache = Maps.newHashMap();
        if (CollUtil.isNotEmpty(purchaseCodes)) {
            final List<PurchaseOrder> list = purchaseOrderService.list(
                    new LambdaQueryWrapper<PurchaseOrder>().in(PurchaseOrder::getOrderCode, purchaseCodes));
            for (PurchaseOrder purchaseOrder : list) {
                purchaseOrderMarkFlagCache.put(purchaseOrder.getOrderCode(), purchaseOrder.getMarkFlag());
                purchaseOrderCache.put(purchaseOrder.getOrderCode(), purchaseOrder);
            }

            //2025-06-26判断明细订单里带的物流供应商是否一致
            boolean b = areAllSupplierCodesEqual(list);
            if(!b){
                throw new DaoException("物流供应商不一致");
            }
            List<String> supplierCodes = list.stream()
                    .map(PurchaseOrder::getSupplierCode1)
                    .filter(code -> code != null && !code.isEmpty())
                    .collect(Collectors.toList());
            // 检查所有的supplierCode1值是否与页面上选的相同2025-06-11
            boolean allEqual = areAllSupplierCodesEqual(supplierCodes, deliveryOrderSaveDTO.getSupplierCode1());
            if (!allEqual) {
                throw new DaoException("物流供应商不一致");
            }

        }
        final String purchaseOrderCode1 = details.get(0).getPurchaseOrderCode();
        final PurchaseOrder purchaseOrder = purchaseOrderService.getOne(
                new LambdaQueryWrapper<>(PurchaseOrder.class).eq(PurchaseOrder::getOrderCode, purchaseOrderCode1),
                false);
        deliveryOrder.setPurchaseGroupCode(purchaseOrder.getPurchaseGroupCode());
        deliveryOrder.setPurchaseGroupName(purchaseOrder.getPurchaseGroupName());
        Set<Long> ids = Sets.newHashSet();
        for (DeliveryOrderDetailBaseDTO baseDTO : item) {
            final String purchaseOrderCode = baseDTO.getPurchaseOrderCode();
            final String purchaseOrderRow = baseDTO.getPurchaseOrderRow();
            final PurchaseOrderDetail unlock = purchaseOrderDetailService.getOne(
                    new LambdaQueryWrapper<PurchaseOrderDetail>().eq(PurchaseOrderDetail::getOrderCode,
                            purchaseOrderCode).eq(PurchaseOrderDetail::getOrderRow, purchaseOrderRow), false);
            final String markFlag = purchaseOrderMarkFlagCache.get(purchaseOrderCode);
            DeliveryType deliveryType = DeliveryType.forCode(markFlag);
            //如果是境外交货，则设置为订单交货
            if (ObjectUtil.isNotNull(deliveryOrderSaveDTO.getOverseasFlag())&&deliveryOrderSaveDTO.getOverseasFlag()==1){
                deliveryType = DeliveryType.ORDER;
            }
            if (deliveryType.equals(DeliveryType.ORDER)) {
                unlockPurchaseDetail.add(unlock.getOrderCode() + unlock.getOrderRow());
                final BigDecimal noClearNum = unlock.getNoClearNum();
                //需要比较下这个未清-在途是否大于等于送货数量
                BigDecimal count = deliveryOrderDetailService.findCountByPurchaseDetail(unlock.getOrderCode(),
                        unlock.getOrderRow(), DeliveryStatus.SHIPPED.getStatus(), DelFlag.NORMAL.getStatus());
                final BigDecimal enableNum = noClearNum.subtract(count);
                if (enableNum.compareTo(baseDTO.getNum()) < 0) {
                    final String format = StrUtil.format("创建失败:{}-{},可送货数量不足", purchaseOrderCode,
                            purchaseOrderRow);
                    throw new DaoException(format);
                }
            } else if (Objects.nonNull(unlock.getUnlockFlag()) &&
                    unlock.getUnlockFlag().equals(FlagConst.Y.getCode())) {
                unlockPurchaseDetail.add(unlock.getOrderCode() + unlock.getOrderRow());
                purchaseOrderDetailIds.add(unlock.getId());
                final BigDecimal noClearNum = unlock.getNoClearNum();
                //需要比较下这个未清-在途是否大于等于送货数量
                BigDecimal count = deliveryOrderDetailService.findCountByPurchaseDetail(unlock.getOrderCode(),
                        unlock.getOrderRow(), DeliveryStatus.SHIPPED.getStatus(), DelFlag.NORMAL.getStatus());
                final BigDecimal enableNum = noClearNum.subtract(count);
                final BigDecimal unlockNum = unlock.getUnlockNum();
                if (unlockNum.compareTo(baseDTO.getNum()) < 0) {
                    final String format = StrUtil.format("创建失败:{}-{},解锁可送货数量不足", purchaseOrderCode,
                            purchaseOrderRow);
                    throw new DaoException(format);
                }
                if (enableNum.compareTo(baseDTO.getNum()) < 0) {
                    final String format = StrUtil.format("创建失败:{}-{},可送货数量不足", purchaseOrderCode,
                            purchaseOrderRow);
                    throw new DaoException(format);
                }

            } else {
                final BigDecimal noClearNum = unlock.getNoClearNum();
                //需要比较下这个未清-在途是否大于等于送货数量
                BigDecimal count = deliveryOrderDetailService.findCountByPurchaseDetail(unlock.getOrderCode(),
                        unlock.getOrderRow(), DeliveryStatus.SHIPPED.getStatus(), DelFlag.NORMAL.getStatus());
                final BigDecimal enableNum = noClearNum.subtract(count);
                if (enableNum.compareTo(baseDTO.getNum()) < 0) {
                    final String format = StrUtil.format("创建失败:{}-{},可送货数量不足", purchaseOrderCode,
                            purchaseOrderRow);
                    throw new DaoException(format);
                }
            }
        }

        if (Objects.isNull(deliveryOrder.getId())) {
            deliveryOrder.setCreateId(LoginUtil.getUserId());
            deliveryOrder.setCreateTime(LocalDateTime.now());
            for (DeliveryOrderDetail detail : details) {
                detail.setId(null);
            }
        } else {
            //
            final DeliveryOrder order = deliveryOrderService.getById(deliveryOrder.getId());
            if (order.getDelFlag() == DelFlag.DELETE.getStatus()) {
                throw new DaoException("送货单已删除无法保存");
            }
            deliveryOrder.setUpdateId(LoginUtil.getUserId());
            deliveryOrder.setUpdateTime(LocalDateTime.now());
        }
        if (deliveryOrderSaveDTO.getDeliveryFlag() == FlagConst.Y.getCode()) {
            deliveryOrder.setState(DeliveryStatus.SHIPPED.getStatus());
        } else {
            deliveryOrder.setState(DeliveryStatus.NEW.getStatus());
        }
        //需要增加逻辑判断，如果是供应商创建的数据供应商可见的标记都是是
        if (LoginUtil.isSupplier()) {
            deliveryOrder.setSupplierVisible(FlagConst.Y.getCode());
        } else {
            //如果是采购的需要取订单，如果订单是供应商可见，送货单也是是
            Set<Integer> supplierVisibleSet = Sets.newHashSet();
            Integer supplierVisible = FlagConst.N.getCode();
            for (PurchaseOrder value : purchaseOrderCache.values()) {
                supplierVisibleSet.add(value.getSupplierVisible());
                supplierVisible = value.getSupplierVisible();
            }
            if (supplierVisibleSet.size() > 1) {
                throw new DaoException("送货单创建发生错误，不能混合创建!");
            }
            deliveryOrder.setSupplierVisible(supplierVisible);
        }
        //保存之前需要校验逻辑
        //需要去取数量，进行校验
        List<AppointmentQuantitySapDTO.Item> result = Lists.newArrayList();
        Map<String, BigDecimal> count = Maps.newHashMap();
        Map<String, String> orderInfo = Maps.newHashMap();
        for (DeliveryOrderDetail detail : details) {
            //需要排除掉解锁的
            if (unlockPurchaseDetail.contains(detail.getPurchaseOrderCode() + detail.getPurchaseOrderRow())) {
                continue;
            }
            final AppointmentQuantitySapDTO.Item item1 = new AppointmentQuantitySapDTO.Item();
            item1.setMATNR(detail.getMaterialCode());
            item1.setWERKS(detail.getFactoryCode());
            result.add(item1);
            final String key = item1.getMATNR() + StrUtil.AT + StrUtil.AT + item1.getWERKS();
            if (Objects.isNull(count.get(key))) {
                count.put(key, detail.getNum());
            } else {
                final BigDecimal add = count.get(key).add(detail.getNum());
                count.put(key, add);
            }
            orderInfo.put(key, StrUtil.format("{}-{}", detail.getPurchaseOrderCode(), detail.getPurchaseOrderRow()));
        }
        //如果是境外交货，则设置为订单交货
        if (deliveryOrderSaveDTO.getOverseasFlag()!=1){
            final Map<String, BigDecimal> longBigDecimalMap = purchaseOrderCountLogic.getMaterialQuantity(result);
            for (String s : longBigDecimalMap.keySet()) {
                final BigDecimal bigDecimal = longBigDecimalMap.get(s);
                final BigDecimal bigDecimal1 = count.get(s);
                if (bigDecimal.compareTo(bigDecimal1) < 0) {
                    throw new DaoException(StrUtil.format("创建失败:{},SAP可送货数量不足", orderInfo.get(s)));
                }
            }
        }
        //物流商创建的送货单 需要根据送货单行进行拆分，如果送货单行有N个供应商需要创建N个单头
        //      final String sequenceNo = sequenceClient.createSequenceNo(DELIVERY_CODE.getCode());
        //            deliveryOrder.setOrderCode(sequenceNo);
        //如果是境外交货，只有一个供应商
        Set<String> supplierCodes = new HashSet<>();
        if (ObjectUtil.isNotNull(deliveryOrderSaveDTO.getOverseasFlag())&&deliveryOrderSaveDTO.getOverseasFlag()==1){
            supplierCodes.add(deliveryOrderSaveDTO.getSupplierErpCode());
        }else {
            supplierCodes = details.stream().map(DeliveryOrderDetail::getSupplierCode)
                    .collect(Collectors.toSet());
        }
        boolean agent = false;
        if (LoginUtil.isSupplier()) {
            if(StringUtils.isNotEmpty(deliveryOrderSaveDTO.getSupplierCode1()) && !deliveryOrderSaveDTO.getSupplierCode1().equals("0")){
                final Pair<Boolean, List<SupplierDTO>> agentList = supplierClient.getAgentList(deliveryOrderSaveDTO.getSupplierCode1());
                agent = agentList.getKey();
            }else{
                final Pair<Boolean, List<SupplierDTO>> agentList = supplierClient.getAgentList(LoginUtil.getSupplierCode());
                agent = agentList.getKey();
            }

        }
        //现货订单及订单类型
        boolean xhdd = false;
        String ddlx=null;
        Map.Entry<String, PurchaseOrder> firstEntry = purchaseOrderCache.entrySet().stream().findFirst().orElse(null);
        if (firstEntry != null) {
            PurchaseOrder firstValue = firstEntry.getValue();
            if(StringUtils.isNotEmpty(firstValue.getColumn3())){
                xhdd = true;
            }
            ddlx = firstValue.getOrderTypeCode();
        }

        Map<String, Long> deliveryOrderIdCache = Maps.newHashMap();
        Map<String, String> deliveryOrderCodeCache = Maps.newHashMap();
        List<DeliveryOrder> deliveryOrders = Lists.newArrayList();
        List<String>  ss= new ArrayList<>();
        for (PurchaseOrder value : purchaseOrderCache.values()) {
            String lx="C";
            String xh=value.getColumn3();
            String dd=value.getOrderTypeCode();
            if ("X".equals(xh)) {
                lx = "X";//现货
            }else{
                if (agent) {
                    lx = "H";
                }else {
                    if ("Z006".equals(dd) || "Z012".equals(dd)) {//免费
                        lx = "Y";
                    }
                }
            }
            ss.add(lx);
        }
       Set  se= new HashSet<>(ss);
        if ( se.size() > 1) {
            throw new DaoException(StrUtil.format("创建失败:样品到料、现货到料、国内到料、港料到料不能同时存在"));
        }
        Long deliveryId = null;
        String deliveryCode1= null;
        for (String s : supplierCodes) {
            deliveryOrder.setId(null);
            String deliveryCode =  sequenceClient.createDeliverySequence(DELIVERY_CODE.getCode(), 6, agent,xhdd,ddlx);
            deliveryOrder.setOrderCode(deliveryCode);
            final DeliveryOrder deliveryOrder1 = deliveryOrderConvert.entityCopy(deliveryOrder);
            deliveryOrderService.save(deliveryOrder1);
            deliveryOrderIdCache.put(s, deliveryOrder1.getId());
            deliveryId = deliveryOrder1.getId();
            ids.add(deliveryOrder1.getId());
            deliveryOrderCodeCache.put(s, deliveryOrder1.getOrderCode());
            deliveryCode1 = deliveryOrder1.getOrderCode();
            deliveryOrders.add(deliveryOrder1);
            final String fileIds = deliveryOrderSaveDTO.getFileIds();
            if (StrUtil.isNotEmpty(fileIds)) {
                List<DeliveryOrderFile> fileList = Lists.newArrayList();
                final List<String> files = StrUtil.split(fileIds, StrUtil.COMMA);
                for (String file : files) {
                    DeliveryOrderFile deliveryOrderFile = new DeliveryOrderFile();
                    deliveryOrderFile.setFileId(Long.valueOf(file));
                    deliveryOrderFile.setMasterId(deliveryOrder1.getId());
                    fileList.add(deliveryOrderFile);
                }
                deliveryOrderFileService.saveBatch(fileList);
            }
        }

        //增加送货管控校验：根据供应商编码和物料编码，查询管控表数量是否（1、管控表数量应 >= 本次送货数量 + 以往累计已送货数量 2025-02-12 邓京术
        //key : supplierCode + materialCode
        Map<String,BigDecimal> curSendNumMap = Maps.newHashMap();//当前单送货数量
        Map<String,BigDecimal> controlNumMap = Maps.newHashMap();//管控的总数量
        Map<String,BigDecimal> lastSendNumMap = Maps.newHashMap();//之前已经送货的总数量
        for (DeliveryOrderDetail detail : details) {
            final String supplierCode = detail.getSupplierCode();
            detail.setOrderId(deliveryOrderIdCache.get(supplierCode)==null?deliveryId:deliveryOrderIdCache.get(supplierCode));
            detail.setOrderCode(deliveryOrderCodeCache.get(supplierCode)==null?deliveryCode1:deliveryOrderCodeCache.get(supplierCode));
            detail.setCreateId(LoginUtil.getUserId());
            detail.setCreateTime(LocalDateTime.now());
            detail.setState(DeliveryStatus.SHIPPED.getStatus());

            String key = detail.getSupplierCode() + "@@" + detail.getMaterialCode();
            BigDecimal sendNum = detail.getNum();
            if (curSendNumMap.keySet().contains(key)) {
                curSendNumMap.put(key, sendNum.add(curSendNumMap.get(key)));
            } else {
                controlNumMap.put(key,BigDecimal.ZERO);
                lastSendNumMap.put(key, BigDecimal.ZERO);
                curSendNumMap.put(key, sendNum);
                //查询管控数量
                DeliveryOrderControl deliveryOrderControl = deliveryOrderControlLogic.getControlNum(supplierCode, detail.getMaterialCode());
                if (Objects.nonNull(deliveryOrderControl) && deliveryOrderControl.getControlNum().floatValue() >= 0) {
                    if (DateUtils.formatYYYYMMDDDash(deliveryOrderControl.getEffectiveDate()).isAfter(LocalDateTime.now())) {
                        controlNumMap.put(key,BigDecimal.ZERO);
                    } else {
                        controlNumMap.put(key, deliveryOrderControl.getControlNum());
                        //查询该供应商物料已送货数量
                        BigDecimal lastSendNum = deliveryOrderDetailService.findSendNumBySuplierCodeAndMaterialCode(deliveryOrderControl.getEffectiveDate(), supplierCode, detail.getMaterialCode(), 0);
                        lastSendNumMap.put(key, lastSendNum);
                    }
                }
            }
        }
        //进行送货数量管控的判断 2025-02-12 邓京术
        for (String key : curSendNumMap.keySet()) {
            if (controlNumMap.get(key).floatValue() > 0) {
                BigDecimal sendNum = curSendNumMap.get(key);
                BigDecimal lastSendNum = lastSendNumMap.get(key);
                BigDecimal comNum = controlNumMap.get(key).subtract(sendNum).subtract(lastSendNum);
                //如果管控数量 < 当前送货数量 + 以往已送货数量
                if (comNum.floatValue() < 0) {
                    throw new DaoException(StrUtil.format("创建失败:供应商：{},物料编号：{}，已完成送货数量：{}, 当次送货数量:{}, 大于送货管控数量:{}", key.split("@@")[0],key.split("@@")[1],
                            lastSendNum, sendNum, controlNumMap.get(key)));
                }
            }
        }


        //需要重新排序，根据orderId先分组
        final Map<Long, List<DeliveryOrderDetail>> collect = details.stream()
                .collect(Collectors.groupingBy(DeliveryOrderDetail::getOrderId));
        for (Long l : collect.keySet()) {
            final List<DeliveryOrderDetail> deliveryOrderDetails = collect.get(l);
            //需要按照顺序增加行号
            int rowNo = 1;
            for (DeliveryOrderDetail deliveryOrderDetail : deliveryOrderDetails) {
                deliveryOrderDetail.setOrderRow(String.valueOf(rowNo));
                rowNo++;
            }
        }

        deliveryOrderDetailService.saveOrUpdateBatch(details);

        //需要推送mes
        deliveryOrderPushMesLogic.processor(details, deliveryOrders, "");

        //忽略异常报错
        try {
            //需要推送sap
            for (Long id : ids){
                deliveryOrderPushSapLogic.pushDeliveryToSap(id, "C");
            }
        }catch (Exception ignored){}


        if (CollUtil.isNotEmpty(purchaseOrderDetailIds)) {
            //需要还原锁定标记
            purchaseOrderDetailService.update(
                    new LambdaUpdateWrapper<PurchaseOrderDetail>().set(PurchaseOrderDetail::getUnlockFlag,
                                    FlagConst.N.getCode()).set(PurchaseOrderDetail::getUnlockNum, 0)
                            .in(PurchaseOrderDetail::getId, purchaseOrderDetailIds));
        }

        //需要用订单和行号获取计划交货行的
        Set<String> msg = Sets.newHashSet();
        for (DeliveryOrderDetail order : details) {
            final String purchaseOrderRow = order.getPurchaseOrderRow();
            final String purchaseOrderCode = order.getPurchaseOrderCode();
            final PurchaseOrderDevPlan one = purchaseOrderDevPlanService.getOne(
                    new LambdaQueryWrapper<>(PurchaseOrderDevPlan.class)
                            .eq(PurchaseOrderDevPlan::getPurchaseOrder, purchaseOrderCode)
                            .eq(PurchaseOrderDevPlan::getLineItem, purchaseOrderRow)
                            .apply("(schedule_delivery_quantity-received_quantity)>0")
                            .isNotNull(PurchaseOrderDevPlan::getScheduleDeliveryDate)
                            .orderByAsc(PurchaseOrderDevPlan::getScheduleDeliveryDate), false);
            if (Objects.nonNull(one)) {
                final LocalDate end = one.getScheduleDeliveryDate();
                final LocalDateTime planDeliveryDate = deliveryOrder.getPlanDeliveryDate();
                final LocalDate start = planDeliveryDate.toLocalDate();
                final long between = ChronoUnit.DAYS.between(start, end);
                if (between > 2) {
                    msg.add(StrUtil.format("订单号:{},行号:{}送货日期小于回复交期， 请同步更新订单回复日期",
                            purchaseOrderCode, purchaseOrderRow));
                }
            }
        }
        return Pair.of(ids.stream().map(String::valueOf).collect(Collectors.joining(",")), msg);
    }

    public static boolean areAllSupplierCodesEqual(List<String> supplierCodes, String supplierCodes1) {
        // 如果列表为空，则视为所有值都等于A
        if (CollUtil.isEmpty(supplierCodes)|| (!CollUtil.isEmpty(supplierCodes) && (StringUtils.isEmpty(supplierCodes1) || supplierCodes1.equals("0")))) {
            return true;
        }

        // 检查是否有任何supplierCode1值与A不同
        return supplierCodes.stream()
                .allMatch(code -> Objects.equals(code, supplierCodes1));
    }

    public static boolean areAllSupplierCodesEqual(List<PurchaseOrder> list) {
        if (list == null || list.isEmpty()) {
            return true; // 空列表或null视为所有值相同
        }

        // 获取第一个非空且非空的supplierCode1作为基准
        String firstNonNullCode = list.stream()
                .map(PurchaseOrder::getSupplierCode1)
                .filter(Objects::nonNull)
                .filter(code -> !code.isEmpty())
                .findFirst()
                .orElse(null);

        // 如果没有非空值，则所有值视为相同（均为null或空）
        if (firstNonNullCode == null) {
            // 检查是否所有值均为null或空
            boolean allNullOrEmpty = list.stream()
                    .map(PurchaseOrder::getSupplierCode1)
                    .allMatch(code -> code == null || code.isEmpty());
            return allNullOrEmpty;
        }

        // 检查所有非空值是否与基准值相同
        return list.stream()
                .map(PurchaseOrder::getSupplierCode1)
                .allMatch(code ->
                        firstNonNullCode.equals(code)
                );
    }
    @Override
    public PageView getList(DeliveryOrderQuery query) {
        Page<DeliveryOrder> page = PageUtil.toPage(query);
        if (LoginUtil.isSupplier()) {
            query.setSupplierCode(LoginUtil.getSupplierCode());
            //判断当前的供应商是否有角色编码
            final List<String> roleCodes = LoginUtil.getRoleCodes();
            //判断是否存在特殊角色 special 如果存在并且没有输入查询条件就返回空数据
            if (roleCodes.contains(DictCode.SUPPLIER_SPECIAL_ROLE)) {
                final Map<String, Object> map = BeanUtil.beanToMap(query, false, false);
                Set<String> keySet = Sets.newHashSet();
//                keySet.add("state");
//                keySet.add("orderCode");
//                keySet.add("poCode");
                keySet.add("materialCodeOrName");
//                keySet.add("purchaseGroupCode");
//                keySet.add("factoryCode");
//                keySet.add("startCreateDate");
//                keySet.add("endCreateDate");
//                keySet.add("remark");
                boolean isOk = keySet.stream().allMatch(key -> {
                    if (Objects.nonNull(map.get(key))) {
                        if (Strings.isNullOrEmpty(map.get(key).toString())) {
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        return true;
                    }
                });
                if (isOk) {
                    return PageUtil.getPV(Collections.emptyList(), 0);
                }
            }
            query.setSupplierVisible(FlagConst.Y.getCode());
        } else {
            final Set<String> userPurchaseGroupCode = userPurchaseGroupClient.getUserPurchaseGroupCode(
                    LoginUtil.getUserId());
            query.setUserPurchaseGroupCodes(userPurchaseGroupCode);
        }
        //排序判断
        if (StringUtils.isNotEmpty(query.getSort()) && query.getSort().equals("planDeliveryDateStr")) {
            query.setSort("planDeliveryDate");
        }
        //默认排序用送货单的创建时间倒序
        if (StringUtils.isEmpty(query.getSort())) {
            query.setSort("createTime");
            query.setOrder("desc");
        }
        List<DeliveryOrder> list = deliveryOrderService.findList(page, query);
        Set<String> supplierCodes = Sets.newHashSet();
        //判断供应商是否配置了预约
        if (CollUtil.isNotEmpty(list)) {
            supplierCodes = list.stream().map(DeliveryOrder::getSupplierErpCode).collect(Collectors.toSet());
            final List<AppointmentSupplier> list1 = appointmentSupplierService.list(
                    new LambdaQueryWrapper<AppointmentSupplier>().in(AppointmentSupplier::getSupplierCode,
                                    supplierCodes).eq(AppointmentSupplier::getDeleteFlag, DelFlag.NORMAL.getStatus())
                            .eq(AppointmentSupplier::getStatus, EnableStatus.ENABLE.getStatus()));
            list1.stream().map(AppointmentSupplier::getSupplierCode).forEach(supplierCodes::remove);//去掉已经配置的
        }
        List<DeliveryOrderListDTO> dtos = deliveryOrderConvert.entities2Dtos1(list);
        final Set<Long> orderIds = list.stream().map(DeliveryOrder::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(orderIds)) {
            final List<DeliveryOrderFile> list1 = deliveryOrderFileService.list(
                    new LambdaUpdateWrapper<DeliveryOrderFile>().in(DeliveryOrderFile::getMasterId, orderIds));
            final Map<Long, List<Long>> map = list1.stream().collect(
                    Collectors.groupingBy(DeliveryOrderFile::getMasterId,
                            Collectors.mapping(DeliveryOrderFile::getFileId, Collectors.toList())));
            // 送货单附件
            final List<BusinessAttachment> businessAttachmentList = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>()
                    .in(BusinessAttachment::getBusinessId, orderIds).eq(BusinessAttachment::getBusinessTypeCode, "delivery_order"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (DeliveryOrderListDTO dto : dtos) {
                dto.setPlanDeliveryDateStr(DateUtils.formatYYYYMMDDDash(dto.getPlanDeliveryDate()));
                final String supplierErpCode = dto.getSupplierErpCode();
                if (supplierCodes.contains(supplierErpCode)) {
                    dto.setIsAppointment(FlagConst.N.getCode());
                } else {
                    dto.setIsAppointment(FlagConst.Y.getCode());
                }
                final Long id = dto.getId();
                if (Objects.nonNull(map.get(id))) {
                    final String fileIds = map.get(id).stream().map(String::valueOf)
                            .collect(Collectors.joining(StrUtil.COMMA));
                    dto.setFileIds(fileIds);
                }
                if (Objects.nonNull(businessAttachmentMap.get(id))) {
                    dto.setAttachmentFiles("1");
                }
            }
        }
        return PageUtil.getPV(dtos, page.getTotal());
    }

    @Override
    public List<DeliveryOrderBaseDTO> getListAll(DeliveryOrderQuery query) {
        if (LoginUtil.isSupplier()) {
            query.setSupplierCode(LoginUtil.getSupplierCode());
            //判断当前的供应商是否有角色编码
            final List<String> roleCodes = LoginUtil.getRoleCodes();
            //判断是否存在特殊角色 special 如果存在并且没有输入查询条件就返回空数据
            if (roleCodes.contains(DictCode.SUPPLIER_SPECIAL_ROLE)) {
                final Map<String, Object> map = BeanUtil.beanToMap(query, false, false);
                Set<String> keySet = Sets.newHashSet();
//                keySet.add("state");
//                keySet.add("orderCode");
//                keySet.add("poCode");
                keySet.add("materialCodeOrName");
//                keySet.add("purchaseGroupCode");
//                keySet.add("factoryCode");
//                keySet.add("startCreateDate");
//                keySet.add("endCreateDate");
//                keySet.add("remark");
                boolean isOk = keySet.stream().allMatch(key -> {
                    if (Objects.nonNull(map.get(key))) {
                        if (Strings.isNullOrEmpty(map.get(key).toString())) {
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        return true;
                    }
                });
                if (isOk) {
                    return Collections.emptyList();
                }
            }
            query.setSupplierVisible(FlagConst.Y.getCode());
        } else {
            final Set<String> userPurchaseGroupCode = userPurchaseGroupClient.getUserPurchaseGroupCode(
                    LoginUtil.getUserId());
            query.setUserPurchaseGroupCodes(userPurchaseGroupCode);
        }

        //需要单独查询分页总数
        query.setRows(1);
        query.setPage(1);
        Page<DeliveryOrder> orderDetailPOPage = PageUtil.toPage(query);
        deliveryOrderService.findList(orderDetailPOPage, query);
        if (orderDetailPOPage.getTotal() > sysProp.getExportMaxCount()) {
            throw new DaoException(StrUtil.format("导出数据超过{}条", sysProp.getExportMaxCount()));
        }
        List<DeliveryOrder> list = deliveryOrderService.findList(query);
        List<DeliveryOrderBaseDTO> dtos = deliveryOrderConvert.entities2Dtos(list);
        for (DeliveryOrderBaseDTO dto : dtos) {
            dto.setPlanDeliveryDateStr(DateUtils.formatYYYYMMDDDash(dto.getPlanDeliveryDate()));
        }
        return dtos;
    }

    @Override
    public DeliveryPrintDTO getPrintData(String ids) {
        final List<String> split = StrUtil.split(ids, ',');
        DeliveryPrintDTO printDTOS = new DeliveryPrintDTO();
        final PrintTemplateCDTO printTemplate = printTemplateClient.getPrintTemplate(
                PrintTemplateCode.DELIVERY.getCode());
        printDTOS.setTmpJson(printTemplate.getTemplateJson());
        printDTOS.setData(Lists.newArrayList());
        //缓存字典
        final Map<String, String> dictCache = dictClient.getDicMapByType(DELIVERY_TYPE.getCode());
        final Map<String, String> reasonsDict = dictClient.getDicMapByType(
                DictCode.REASONS_FOR_NONCONFORMITY.getCode());
        List<DeliveryPrintSendEmailDTO> emailDTOS = Lists.newArrayList();
        Map<String, SupplierDTO> supplierCache = Maps.newHashMap();
        for (String id : split) {
            final DeliveryOrderPrintDTO deliveryOrderPrintDTO = new DeliveryOrderPrintDTO();
            DeliveryOrder deliveryOrder = deliveryOrderService.getById(id);
            final Integer directShipment = deliveryOrder.getDirectShipment();
            final String s = dictCache.get(directShipment.toString());
            deliveryOrderPrintDTO.setDirectShipment(s);
            deliveryOrderPrintDTO.setOrderCode(deliveryOrder.getOrderCode());
            if (StringUtils.isNotEmpty(deliveryOrder.getEntrustNo())) {
                deliveryOrderPrintDTO.setEntrustNo(deliveryOrder.getOrderCode() + " (" + deliveryOrder.getEntrustNo() + ")");
            } else {
                deliveryOrderPrintDTO.setEntrustNo(deliveryOrder.getOrderCode());
            }
            deliveryOrderPrintDTO.setCompanyName(deliveryOrder.getCompanyName());
            deliveryOrderPrintDTO.setConsigner(deliveryOrder.getConsigner());
            deliveryOrderPrintDTO.setSupplierName(deliveryOrder.getSupplierName());
            deliveryOrderPrintDTO.setDeliveryDate(deliveryOrder.getDeliveryDate());
            deliveryOrderPrintDTO.setPlanDeliveryDate(
                    DateUtils.formatYYYYMMDDDash(deliveryOrder.getPlanDeliveryDate()));
            //需要判断单头供应商和明细供应商是否一致如果不一致就说明是物流商
            final String currentSupplierCode = deliveryOrder.getSupplierErpCode();
            final LambdaQueryWrapper<DeliveryOrderDetail> eq = new LambdaQueryWrapper<DeliveryOrderDetail>().eq(
                            DeliveryOrderDetail::getOrderId, id)
                    .eq(DeliveryOrderDetail::getDelFlag, DelFlag.NORMAL.getStatus());
            eq.last("ORDER BY CAST(order_row AS UNSIGNED) ASC");
            List<DeliveryOrderDetail> deliveryOrderDetailList = deliveryOrderDetailService.list(eq);
            String detailSupplierCode = StrUtil.EMPTY;
            for (DeliveryOrderDetail deliveryOrderDetail : deliveryOrderDetailList) {
//                final String materialName = deliveryOrderDetail.getMaterialName();
//                final String sub = StrUtil.sub(materialName, 0, 40);
                detailSupplierCode = deliveryOrderDetail.getSupplierCode();
//                deliveryOrderDetail.setMaterialName(sub);
            }
            String detailSupplierName = StrUtil.EMPTY;
            if (!StrUtil.equals(currentSupplierCode, detailSupplierCode)) {
                final SupplierDTO supplierDTO = supplierCache.get(detailSupplierCode);
                if (Objects.isNull(supplierDTO)) {
                    final SupplierDTO supplierByCode = supplierClient.getSupplierByCode(detailSupplierCode);
                    supplierCache.put(detailSupplierCode, supplierByCode);
                }
                final SupplierDTO dto = supplierCache.get(detailSupplierCode);
                detailSupplierName = dto.getSupplierName();
            }

            //需要查询组件用量
            final List<DeliveryOrderDetailPrintDTO> allDetails = Lists.newArrayList();
            String purchaseOrderNo = StrUtil.EMPTY;
            for (DeliveryOrderDetail orderDetail : deliveryOrderDetailList) {
                DeliveryPrintSendEmailDTO dto = new DeliveryPrintSendEmailDTO();
                dto.setSupplierCode(orderDetail.getSupplierCode());
                dto.setMaterialCode(orderDetail.getMaterialCode());
                dto.setDeliverCode(deliveryOrder.getOrderCode());
                dto.setDate(DateUtils.formatYYYYMMDDDash(deliveryOrder.getPlanDeliveryDate()));
                emailDTOS.add(dto);
                purchaseOrderNo = orderDetail.getPurchaseOrderCode();
                //需要计算子件用量
                final String materialCode = orderDetail.getMaterialCode();
                final String factoryCode = orderDetail.getFactoryCode();
                //设置最新的物料名称，如果物料名称有变化，则取最新的物料名称， 2024-08-07 邓京术
                ProductInfoDTO productInfoDTO = productClient.getByMaterialCodeAndFactoryCode(
                        orderDetail.getMaterialCode(), orderDetail.getFactoryCode());
                if (Objects.nonNull(productInfoDTO)) {
                    orderDetail.setMaterialName(productInfoDTO.getMaterialName());
                }

                final List<PurchaseOrderBom> list = purchaseOrderBomService.list(
                        new LambdaQueryWrapper<PurchaseOrderBom>().eq(PurchaseOrderBom::getMaterialCode, materialCode)
                                .eq(PurchaseOrderBom::getFactoryCode, factoryCode));
                final PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailService.getOne(
                        new LambdaQueryWrapper<PurchaseOrderDetail>().eq(PurchaseOrderDetail::getOrderCode,
                                        orderDetail.getPurchaseOrderCode())
                                .eq(PurchaseOrderDetail::getOrderRow, orderDetail.getPurchaseOrderRow()), false);
                final DeliveryOrderDetailPrintDTO detailPrintDTO = deliveryOrderDetailConvert.convert1(orderDetail);
                if (StrUtil.isNotEmpty(purchaseOrderDetail.getDefaultStock())) {
                    detailPrintDTO.setDefaultStock(purchaseOrderDetail.getDefaultStock());
                }
                detailPrintDTO.setNum(orderDetail.getNum().stripTrailingZeros().toPlainString());
                if (StrUtil.isNotEmpty(detailSupplierName)) {
                    detailPrintDTO.setSupplierName(StrUtil.AT + detailSupplierName);
                }
                final QualityManageClientDTO qualityManageClientDTO = qualityManageClient.getQmOrderByCode(
                        detailSupplierCode, orderDetail.getMaterialCode());
                if (Objects.nonNull(qualityManageClientDTO)) {
                    final String badReason = qualityManageClientDTO.getBadReason();
                    final String s1 = reasonsDict.get(badReason);
                    if (StrUtil.isNotEmpty(s1)) {
                        final String remark = detailPrintDTO.getRemark();
                        //财务，采购确认，不良原因去掉， 2024-09-04 邓京术
                        detailPrintDTO.setRemark(remark);
                    }
                }
                if (StrUtil.isNotEmpty(orderDetail.getShipmentNo())){
                    if (StrUtil.isNotEmpty(detailPrintDTO.getRemark())){
                        detailPrintDTO.setRemark(detailPrintDTO.getRemark()+"("+orderDetail.getShipmentNo()+"_"+orderDetail.getShipmentRowNo()+")");
                    }else {
                        detailPrintDTO.setRemark(orderDetail.getShipmentNo()+"_"+orderDetail.getShipmentRowNo());
                    }
                }
                if (StrUtil.isNotEmpty(deliveryOrder.getEntrustNo())){
                    if (StrUtil.isNotEmpty(detailPrintDTO.getRemark())){
                        detailPrintDTO.setRemark(detailPrintDTO.getRemark()+"("+deliveryOrder.getEntrustNo()+")");
                    }else {
                        detailPrintDTO.setRemark(deliveryOrder.getEntrustNo());
                    }
                }
                //如果是物流商5012或1001，送货单明细行才显示供应商，否则其他供应商，明细物料不需要显示供应商名称 2026-02-04
                if (!currentSupplierCode.equals("5012") && !currentSupplierCode.equals("1001")) {
                    detailPrintDTO.setSupplierName("");
                } else {
                    PurchaseOrder purchaseOrder = purchaseOrderService.getOne(
                            new LambdaQueryWrapper<PurchaseOrder>().eq(PurchaseOrder::getOrderCode,
                                    orderDetail.getPurchaseOrderCode()), false);
                    detailPrintDTO.setSupplierName(purchaseOrder.getSupplierName());
                }
                allDetails.add(detailPrintDTO);
                final BigDecimal num = orderDetail.getNum();
                for (PurchaseOrderBom purchaseOrderBom : list) {
                    DeliveryOrderDetailPrintDTO baseDTO = new DeliveryOrderDetailPrintDTO();
                    baseDTO.setMaterialCode(purchaseOrderBom.getComponentCode());
                    baseDTO.setMaterialName(purchaseOrderBom.getComponentName());
                    baseDTO.setUnitCode(purchaseOrderBom.getComponentUnit());
                    final BigDecimal divide = num.divide(purchaseOrderBom.getComponentNumber(), 3, RoundingMode.HALF_UP)
                            .multiply(new BigDecimal(purchaseOrderBom.getComponentDosage()));
                    baseDTO.setNum(divide.stripTrailingZeros().toPlainString());
                    baseDTO.setPurchaseOrderCode("子件");
                    baseDTO.setDefaultStock(purchaseOrderBom.getMesStorageLocation());
                    allDetails.add(baseDTO);
                }
            }
            deliveryOrderPrintDTO.setDetail(allDetails);
            //需要去取工厂的联系人和收货联系电话
            //需要增加逻辑处理如果是 "深圳市福田区车公庙泰然九路海松大厦B座8楼" 这个地址需要做单独处理
            //联系人直接取订单的创建人
            final PurchaseOrder purchaseOrder = purchaseOrderService.getOne(
                    new LambdaQueryWrapper<>(PurchaseOrder.class).eq(PurchaseOrder::getOrderCode, purchaseOrderNo),
                    false);
             FactoryDTO factoryDTO=null;
            if (deliveryOrder.getReceiverAddress().equals("深圳市福田区车公庙泰然九路海松大厦B座8楼")) {

                 factoryDTO = factoryClient.getByCode(deliveryOrder.getFactoryCode());
                deliveryOrderPrintDTO.setContacts(purchaseOrder.getCreateName());
                final UserDTO byAccount = userClient.getByAccount(purchaseOrder.getCreateWorkNo());
                deliveryOrderPrintDTO.setReceivingPhone(byAccount.getPhone());
                deliveryOrderPrintDTO.setQualityer(factoryDTO.getQualityer());
                deliveryOrderPrintDTO.setApprovaler(factoryDTO.getApprovaler());
            } else {
                 factoryDTO = factoryClient.getByCode(deliveryOrder.getFactoryCode());
                deliveryOrderPrintDTO.setContacts(
                        factoryDTO.getContacts() + "(采购员:" + deliveryOrder.getPurchaseGroupName() + ")");
                deliveryOrderPrintDTO.setReceivingPhone(factoryDTO.getReceivingPhone());
                deliveryOrderPrintDTO.setQualityer(factoryDTO.getQualityer());
                deliveryOrderPrintDTO.setApprovaler(factoryDTO.getApprovaler());
            }
            //
            if("601".equals(deliveryOrder.getPurchaseGroupCode())||"602".equals(deliveryOrder.getPurchaseGroupCode())){
                deliveryOrderPrintDTO.setReceivingPhone("15820901090(吴广伟)");
                deliveryOrderPrintDTO.setContacts(
                        "吴广伟"+ "(采购员:" + deliveryOrder.getPurchaseGroupName() + ")");

            }
            deliveryOrderPrintDTO.setAddress(deliveryOrder.getReceiverAddress());
            printDTOS.getData().add(deliveryOrderPrintDTO);
        }
        //需要发送质量邮件
        this.pushSqeEmail(emailDTOS);
        return printDTOS;
    }

    private void pushSqeEmail(List<DeliveryPrintSendEmailDTO> list) {
        final Map<String, List<DeliveryPrintSendEmailDTO>> codeMap = list.stream()
                .collect(Collectors.groupingBy(DeliveryPrintSendEmailDTO::getDeliverCode));
        final Map<String, String> problemSourceDict = dictClient.getDicMapByType(DictCode.PROBLEM_SOURCE.getCode());
        final Map<String, String> reasonsDict = dictClient.getDicMapByType(
                DictCode.REASONS_FOR_NONCONFORMITY.getCode());
        for (String s : codeMap.keySet()) {
            //一个送货单发送一次邮件
            List<Map<String, String>> itm = Lists.newArrayList();
            final List<DeliveryPrintSendEmailDTO> emailDTOS = codeMap.get(s);
            String datetime = StrUtil.EMPTY;
            for (DeliveryPrintSendEmailDTO emailDTO : emailDTOS) {
                datetime = emailDTO.getDate();
                final QualityManageClientDTO dto = qualityManageClient.getQmOrderByCode(
                        emailDTO.getSupplierCode(), emailDTO.getMaterialCode());
                if (Objects.nonNull(dto)) {
                    Map<String, String> it = Maps.newHashMap();
                    it.put("supplierName", dto.getSupplierName());
                    it.put("materialCode", dto.getMaterialCode());
                    it.put("materialName", dto.getMaterialName());
                    final String badReason = dto.getBadReason();
                    final String s1 = reasonsDict.get(badReason);
                    if (StrUtil.isNotEmpty(s1)) {
                        it.put("badReason", s1);
                    } else {
                        it.put("badReason", "");
                    }
                    it.put("createName", dto.getCreateUserName());
                    it.put("createTime", DateUtils.formatYYYYMMDDDash(dto.getCreateTime()));
                    final String problemSource = String.valueOf(dto.getProblemSource());
                    final String s2 = problemSourceDict.get(problemSource);
                    if (StrUtil.isNotEmpty(s2)) {
                        it.put("badType", s2);
                    } else {
                        it.put("badType", "");
                    }
                    itm.add(it);
                }
            }
            if (CollUtil.isNotEmpty(itm)) {
                //需要发送邮件
                final EmailTmpSendDTO emailTxtSingleSendDTO = new EmailTmpSendDTO();
                emailTxtSingleSendDTO.setTemplateCode("JW_POST_120");
                Map<String, Object> params = Maps.newHashMap();
                params.put("code", s);
                params.put("datetime", datetime);
                params.put("it", itm);
                emailTxtSingleSendDTO.setParams(params);
                List<String> receiver = Lists.newArrayList("iqc@jwele.com.cn", "sqe@jwele.com.cn");
                emailTxtSingleSendDTO.setReceiver(receiver);
                emailTxtSingleSendDTO.setSender(LoginUtil.getUserId());
                emailSendClient.async(emailTxtSingleSendDTO);
            }
        }
    }

    @Override
    public void saveAttachment(List<DeliveryOrderFileDTO> fileDTOS) {
        List<DeliveryOrderFile> fileList = deliveryOrderFileConvert.dtos2Entities(fileDTOS);
        deliveryOrderFileService.saveBatch(fileList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void complateDelivery(Set<String> devOrderCodes) {
        if (CollUtil.isNotEmpty(devOrderCodes)) {
            final List<DeliveryOrder> list = deliveryOrderService.list(
                    new LambdaQueryWrapper<>(DeliveryOrder.class).in(DeliveryOrder::getOrderCode, devOrderCodes));
            if (CollUtil.isNotEmpty(list)) {
                //更新送货单的状态
                final Set<Long> orderIds = list.stream()
                        .filter(a -> a.getState().equals(DeliveryStatus.SHIPPED.getStatus())).map(DeliveryOrder::getId)
                        .collect(Collectors.toSet());
                if (CollUtil.isNotEmpty(orderIds)) {
                    deliveryOrderService.update(
                            new LambdaUpdateWrapper<>(DeliveryOrder.class).set(DeliveryOrder::getState,
                                    DeliveryStatus.COMPLETED.getStatus()).in(DeliveryOrder::getId, orderIds));
                    deliveryOrderDetailService.update(
                            new LambdaUpdateWrapper<>(DeliveryOrderDetail.class).set(DeliveryOrderDetail::getState,
                                            DeliveryStatus.COMPLETED.getStatus())
                                    .in(DeliveryOrderDetail::getOrderId, orderIds));
                }

                final Set<String> appointmentCodes = list.stream()
                        .filter(a -> StrUtil.isNotEmpty(a.getAppointmentCode()) &&
                                a.getState().equals(DeliveryStatus.SHIPPED.getStatus()))
                        .map(DeliveryOrder::getAppointmentCode).collect(Collectors.toSet());
                if (CollUtil.isNotEmpty(appointmentCodes)) {
                    //更新预约单的处理状态
                    appointmentRecordService.update(
                            new LambdaUpdateWrapper<>(AppointmentRecord.class).set(AppointmentRecord::getUrgencyFlag,
                                    FlagConst.Y.getCode()).in(AppointmentRecord::getAppointmentCode, appointmentCodes));
                }
            }
        }
    }

    @Override
    @DS(SLAVE)
    @Transactional(rollbackFor = Exception.class)
    public void update(DeliveryOrderSaveDTO deliveryOrderSaveDTO) {
        DeliveryOrder deliveryOrder = deliveryOrderConvert.dto2Entity(deliveryOrderSaveDTO);
        deliveryOrder.setUpdateId(LoginUtil.getUserId());
        deliveryOrder.setUpdateTime(LocalDateTime.now());
        final String fileIds = deliveryOrderSaveDTO.getFileIds();
        final Long deliveryOrderId = deliveryOrder.getId();
        deliveryOrderFileService.remove(
                new LambdaQueryWrapper<>(DeliveryOrderFile.class).eq(DeliveryOrderFile::getMasterId,
                        deliveryOrderId));
        if (StrUtil.isNotEmpty(fileIds)) {
            List<DeliveryOrderFile> fileList = Lists.newArrayList();
            final List<String> files = StrUtil.split(fileIds, StrUtil.COMMA);
            for (String file : files) {
                DeliveryOrderFile deliveryOrderFile = new DeliveryOrderFile();
                deliveryOrderFile.setFileId(Long.valueOf(file));
                deliveryOrderFile.setMasterId(deliveryOrderId);
                fileList.add(deliveryOrderFile);
            }
            deliveryOrderFileService.saveBatch(fileList);
        }
        deliveryOrderService.updateById(deliveryOrder);
        final List<DeliveryOrderDetailBaseDTO> item = deliveryOrderSaveDTO.getItem();
        if (CollUtil.isNotEmpty(item)) {
            final Set<Long> ids = item.stream().map(DeliveryOrderDetailBaseDTO::getId).collect(Collectors.toSet());
            final Map<Long, BigDecimal> numCache = item.stream()
                    .collect(Collectors.toMap(DeliveryOrderDetailBaseDTO::getId, DeliveryOrderDetailBaseDTO::getNum));
            final Map<Long, String> remarkCache = item.stream()
                    .collect(
                            Collectors.toMap(DeliveryOrderDetailBaseDTO::getId, DeliveryOrderDetailBaseDTO::getRemark));
            final List<DeliveryOrderDetail> deliveryOrderDetails = deliveryOrderDetailService.listByIds(ids);
            //需要判断修改订单数量是否大于之前的数量
            Set<String> tipMsg = Sets.newHashSet();
            List<DeliveryOrderDetail> updateLists = Lists.newArrayList();
            //增加送货管控校验：根据供应商编码和物料编码，查询管控表数量是否（1、管控表数量应 >= 本次送货数量 + 以往累计已送货数量 2025-02-12 邓京术
            //key : supplierCode + materialCode
            Map<String,BigDecimal> curSendNumMap = Maps.newHashMap();//当前单送货数量
            Map<String,BigDecimal> controlNumMap = Maps.newHashMap();//管控的总数量
            Map<String,BigDecimal> lastSendNumMap = Maps.newHashMap();//之前已经送货的总数量
            Map<String,BigDecimal> chayiNumMap = Maps.newHashMap();//当前与以往送货的差异总数量
            for (DeliveryOrderDetail deliveryOrderDetail : deliveryOrderDetails) {
                final Long id = deliveryOrderDetail.getId();
                final BigDecimal num = deliveryOrderDetail.getNum();
                final BigDecimal editNum = numCache.get(id);
                final String remark = remarkCache.get(id);
                DeliveryOrderDetail up = new DeliveryOrderDetail();
                up.setId(id);
                up.setNum(editNum);
                if (StrUtil.isEmpty(remark)) {
                    up.setRemark("");
                } else {
                    up.setRemark(remark);
                }
                updateLists.add(up);
                if (editNum.compareTo(num) > 0) {
                    tipMsg.add(deliveryOrderDetail.getOrderRow());
                }

                //增加供应商物料送货管控检验 2025-02-13 邓京术
                String supplierCode = deliveryOrderDetail.getSupplierCode();
                String key = deliveryOrderDetail.getSupplierCode() + "@@" + deliveryOrderDetail.getMaterialCode();
                BigDecimal sendNum = numCache.get(id);
                if (curSendNumMap.keySet().contains(key)) {
                    curSendNumMap.put(key, sendNum.add(curSendNumMap.get(key)));
                    BigDecimal chaYiNum = editNum.subtract(num);
                    chayiNumMap.put(key, chaYiNum.add(chayiNumMap.get(key)));
                } else {
                    controlNumMap.put(key,BigDecimal.ZERO);
                    lastSendNumMap.put(key, BigDecimal.ZERO);
                    curSendNumMap.put(key, sendNum);
                    //当前供应商，物料 送货数量原数量与现数量的差异量
                    BigDecimal chaYiNum = editNum.subtract(num);
                    chayiNumMap.put(key, chaYiNum);
                    //查询管控数量
                    DeliveryOrderControl deliveryOrderControl = deliveryOrderControlLogic.getControlNum(supplierCode, deliveryOrderDetail.getMaterialCode());
                    if (Objects.nonNull(deliveryOrderControl) && deliveryOrderControl.getControlNum().floatValue() >= 0) {
                        if (DateUtils.formatYYYYMMDDDash(deliveryOrderControl.getEffectiveDate()).isAfter(LocalDateTime.now())) {
                            controlNumMap.put(key,BigDecimal.ZERO);
                        } else {
                            controlNumMap.put(key, deliveryOrderControl.getControlNum());
                            //查询该供应商物料已送货数量
                            BigDecimal lastSendNum = deliveryOrderDetailService.findSendNumBySuplierCodeAndMaterialCode(deliveryOrderControl.getEffectiveDate(), supplierCode, deliveryOrderDetail.getMaterialCode(), 0);
                            lastSendNumMap.put(key, lastSendNum);
                        }
                    }
                }
            }
            if (CollUtil.isNotEmpty(tipMsg)) {
                throw new DaoException(
                        tipMsg.stream().collect(Collectors.joining(",")) + "行，送货数量大于之前的送货数量");
            }
            //查询该供应商该物料在该订单中原总送货数量 邓京术 2025-02-13号
            //进行送货数量管控的判断 2025-02-12 邓京术
            for (String key : curSendNumMap.keySet()) {
                if (controlNumMap.get(key).floatValue() > 0) {
                    BigDecimal sendNum = curSendNumMap.get(key);
                    BigDecimal lastSendNum = lastSendNumMap.get(key);
                    BigDecimal chaYiNum = chayiNumMap.get(key);
                    BigDecimal comNum = controlNumMap.get(key).subtract(chaYiNum.add(lastSendNum));
                    //如果管控数量 < 当前送货数量 + 以往已送货数量
                    if (comNum.floatValue() < 0) {
                        throw new DaoException(StrUtil.format("创建失败:供应商：{},物料编号：{}，已完成送货数量：{}, 当次送货数量:{}, 大于送货管控数量:{}", key.split("@@")[0],key.split("@@")[1],
                                lastSendNum, sendNum, controlNumMap.get(key)));
                    }
                }
            }
            deliveryOrderDetailService.updateBatchById(updateLists);
            //需要推送mes
            final List<DeliveryOrderDetail> details = deliveryOrderDetailService.list(new LambdaQueryWrapper<>(
                    DeliveryOrderDetail.class).eq(DeliveryOrderDetail::getOrderId, deliveryOrderId)
                    .eq(DeliveryOrderDetail::getDelFlag, DelFlag.NORMAL.getStatus()));
            final Long orderId = details.get(0).getOrderId();
            final DeliveryOrder order = deliveryOrderService.getById(orderId);
            deliveryOrderPushMesLogic.processor(details, Lists.newArrayList(order), "U");//标识修改
        }

        //忽略异常报错
        try {
            //需要推送sap
            deliveryOrderPushSapLogic.pushDeliveryToSap(deliveryOrder.getId(), "M");
        }catch (Exception ignored){}
    }

    @Override
    public PageView getAttachmentList(Long id) {
        final List<DeliveryOrderFile> list = deliveryOrderFileService.list(
                new LambdaQueryWrapper<>(DeliveryOrderFile.class).eq(DeliveryOrderFile::getMasterId, id));
        List<DeliveryOrderFileDTO> attachmentDTOS = deliveryOrderFileConvert.entities2Dtos(list);
        modelAggregationService.processRelationAggregation(attachmentDTOS);
        return PageUtil.getPV(attachmentDTOS, attachmentDTOS.size());
    }

    @Override
    public void removeAttachment(String ids, String remark) {
        final List<String> split = StrUtil.split(ids, StrUtil.COMMA);
        if (CollUtil.isEmpty(split)) {
            return;
        }
        deliveryOrderFileService.update(new LambdaUpdateWrapper<>(DeliveryOrderFile.class)
                .set(DeliveryOrderFile::getDelFlag, DelFlag.DELETE.getStatus())
                .set(DeliveryOrderFile::getRemark, remark)
                .in(DeliveryOrderFile::getId, split)
        );
    }

    @Override
    public void submitRemark(String ids, String remark) {
        final List<String> split = StrUtil.split(ids, StrUtil.COMMA);
        if (CollUtil.isEmpty(split)) {
            return;
        }
        deliveryOrderFileService.update(new LambdaUpdateWrapper<>(DeliveryOrderFile.class)
                .set(DeliveryOrderFile::getRemark, remark)
                .in(DeliveryOrderFile::getId, split)
        );
    }

    @Override
    public List<ImportCreateDeliveryOrderDetailDTO> getImportData(List<Map<String, String>> dataList) {
        List<ImportCreateDeliveryOrderDetailDTO> result = Lists.newArrayList();
        final Set<String> orderCodes = dataList.stream().map(a -> a.get("orderCode")).collect(Collectors.toSet());
        final List<PurchaseOrder> purchaseOrders = purchaseOrderService.list(
                new LambdaQueryWrapper<>(PurchaseOrder.class).in(PurchaseOrder::getOrderCode, orderCodes));
        final Map<String, PurchaseOrder> cache = purchaseOrders.stream()
                .collect(Collectors.toMap(PurchaseOrder::getOrderCode, a -> a));

//        final Map<String, PurchaseOrder> currencyCache = purchaseOrders.stream()
//                .collect(Collectors.toMap(PurchaseOrder::getCurrencyCode, a -> a));
//        if (currencyCache != null && currencyCache.keySet().contains("USD")) {
//            throw new DaoException("币种是USD的采购订单，由物流供应商创建送货单。");
//        }

        //增加校验是否有重复的
        Map<String, Integer> checkMap = new HashMap<>();
        for (Map<String, String> stringStringMap : dataList) {
            final String orderCode = stringStringMap.get("orderCode");
            final String orderRow = stringStringMap.get("orderRow");
            String key = orderCode+":"+orderRow;
            if( checkMap.get(key) == null){
                checkMap.put(key,1);
            }else{
                checkMap.put(key,checkMap.get(key) + 1);
            }
        }
        for (Map<String, String> stringStringMap : dataList) {
            final String orderCode = stringStringMap.get("orderCode");
            final String orderRow = stringStringMap.get("orderRow");
            String key = orderCode+":"+orderRow;
           if(checkMap.get(key) > 1){
               final String format = StrUtil.format("导入失败:{}-{},订单和订单行号重复", orderCode,
                       orderRow);
               throw new DaoException(format);
           }
        }
        for (Map<String, String> stringStringMap : dataList) {
            final String orderCode = stringStringMap.get("orderCode");
            final String orderRow = stringStringMap.get("orderRow");
            final String remark = stringStringMap.get("remark");
            final String num = stringStringMap.get("num");
            final String deliveryNum = stringStringMap.get("deliveryNum");
            stringStringMap.remove("orderCode");
            stringStringMap.remove("orderRow");
            final PurchaseOrderDetail one = purchaseOrderDetailService.getOne(
                    new LambdaQueryWrapper<>(PurchaseOrderDetail.class)
                            .eq(PurchaseOrderDetail::getOrderCode, orderCode)
                            .eq(PurchaseOrderDetail::getOrderRow, orderRow));

            final ImportCreateDeliveryOrderDetailDTO baseDTO = BeanUtil.mapToBean(stringStringMap,
                    ImportCreateDeliveryOrderDetailDTO.class, false);
            final String requireDate = stringStringMap.get("requireDate");
            if (StrUtil.isNotEmpty(requireDate)) {
                final LocalDateTime localDateTime = DateUtil.parseLocalDateTime(requireDate, DateUtils.yyyyMMddDash);
                baseDTO.setRequireDate(localDateTime);
            }
            ImportCreateDeliveryOrderDetailDTO baseDTO1 = deliveryOrderDetailConvert.fillData(one, baseDTO);
            //如果是解锁需要把解锁的数量放到可送数量里面
            if (Objects.nonNull(one) && null != one.getUnlockFlag() &&
                    one.getUnlockFlag().equals(FlagConst.Y.getCode())) {
                baseDTO1.setEnableNum(one.getUnlockNum());
            }
            final PurchaseOrder purchaseOrder = cache.get(orderCode);
            final String markFlag = purchaseOrder.getMarkFlag();
            final DeliveryType deliveryType = DeliveryType.forCode(markFlag);
            if (deliveryType.equals(DeliveryType.ORDER)) {
                final BigDecimal noClearNum = baseDTO1.getNoClearNum();
                //需要比较下这个未清-在途是否大于等于送货数量
                BigDecimal count = deliveryOrderDetailService.findCountByPurchaseDetail(baseDTO1.getOrderCode(),
                        baseDTO1.getOrderRow(), DeliveryStatus.SHIPPED.getStatus(), DelFlag.NORMAL.getStatus());
                final BigDecimal enableNum = noClearNum.subtract(count);
                if (enableNum.compareTo(new BigDecimal(deliveryNum)) < 0) {
                    final String format = StrUtil.format("导入失败:{}-{},可送货数量不足", baseDTO1.getOrderCode(),
                            baseDTO1.getOrderRow());
                    throw new DaoException(format);
                }
                baseDTO1.setEnableNum(enableNum);
            }
            baseDTO1.setOrderState(purchaseOrder.getState());
            baseDTO1.setCompanyCode(purchaseOrder.getCompanyCode());
            baseDTO1.setCompanyName(purchaseOrder.getCompanyName());
            baseDTO1.setPurchaseOrderRow(orderRow);
            baseDTO1.setPurchaseOrderCode(orderCode);
            baseDTO1.setPurchaseOrderNum(new BigDecimal(num));
            baseDTO1.setRemark(remark);
            baseDTO1.setNum(new BigDecimal(deliveryNum));
            baseDTO1.setId(null);
            result.add(baseDTO1);
        }
        //导入判断工厂必须要相同

        if (result == null || result.size() > 1) {
            String firstFactoryCode = result.get(0).getFactoryCode();
            final boolean match = result.stream()
                    .map(ImportCreateDeliveryOrderDetailDTO::getFactoryCode)
                    .allMatch(factoryCode -> factoryCode.equals(firstFactoryCode));
            if (!match) {
                throw new DaoException("工厂不一致无法导入!");
            }
        }
        return result;
    }

    @Override
    public List<ImportCreateDeliveryOrderDetailDTO> overseasImport(MultipartFile file,String factoryCode) {
        List<OverseasDeliveryImportDTO> cachedDataList = ListUtils.newArrayList();
        try {
            EasyExcel.read(file.getInputStream(), OverseasDeliveryImportDTO.class,
                    new ReadListener<OverseasDeliveryImportDTO>() {
                        @Override
                        public void invoke(OverseasDeliveryImportDTO data, AnalysisContext context) {
                            if (Strings.isNullOrEmpty(data.getEntrustNo())) {
                                throw new DaoException("委托单号不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getCodeDateStr())) {
                                throw new DaoException("单据日期不能为空!");
                            }
                            String codeDateStr = data.getCodeDateStr();
                            try {
                                codeDateStr = codeDateStr.replaceAll("/", "-");
                                Date codeDate = DateUtil.parse(codeDateStr, "yyyy-MM-dd");
                                data.setCodeDate(LocalDateTimeUtil.parse(DateUtil.format(codeDate,"yyyy-MM-dd"), "yyyy-MM-dd"));
                            } catch (Exception e) {
                                throw new DaoException("请输入正确的单据日期；如：2025-11-11");
                            }
                            if (Strings.isNullOrEmpty(data.getPoCode())) {
                                throw new DaoException("采购订单编码不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getMaterialCode())) {
                                throw new DaoException("物料编码不能为空!");
                            }

//                            if (Strings.isNullOrEmpty(data.getModel())) {
//                                throw new DaoException("产品型号不能为空!");
//                            }
//                            if (Strings.isNullOrEmpty(data.getCurrencyCode())) {
//                                throw new DaoException("报关币种不能为空!");
//                            }
                            if (null==data.getNum()) {
                                throw new DaoException("数量不能为空!");
                            }
                            if (null==data.getPrice()) {
                                throw new DaoException("进口单价不能为空!");
                            }
//                            if (null==data.getCaseNum()) {
//                                throw new DaoException("箱数不能为空!");
//                            }
                            cachedDataList.add(data);
                        }
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new DaoException("导入失败！");
        }
        List<ImportCreateDeliveryOrderDetailDTO> resultList = Lists.newArrayList();
        BigDecimal totalCaseNum = BigDecimal.ZERO;
        String entrustNo = "";
        boolean existPushSap = false;
        boolean notExistPushSap = false;
        if (CollUtil.isNotEmpty(cachedDataList)){
            //判断委托单号是否一致，如果不一致则报错
            final String itemEntrustNo = cachedDataList.get(0).getEntrustNo();
            final boolean match = cachedDataList.stream()
                    .map(OverseasDeliveryImportDTO::getEntrustNo)
                    .allMatch(entrustNo1 -> entrustNo1.equals(itemEntrustNo));
            if (!match) {
                throw new DaoException("委托单号不一致无法导入!");
            }
            for (OverseasDeliveryImportDTO data : cachedDataList){
                totalCaseNum = totalCaseNum.add(data.getCaseNum()==null?BigDecimal.ZERO:data.getCaseNum());
                entrustNo = data.getEntrustNo();
                List<PurchaseOrderDetail> purchaseOrderDetails = purchaseOrderDetailService.list(
                        new LambdaQueryWrapper<>(PurchaseOrderDetail.class)
                                .eq(PurchaseOrderDetail::getMaterialCode, data.getMaterialCode())
                                .eq(PurchaseOrderDetail::getPrice, data.getPrice())
                                .eq(PurchaseOrderDetail::getOrderCode, data.getPoCode())
                                .eq(PurchaseOrderDetail::getDelFlag, 0)

                );
                if (ObjectUtil.isNotNull(data.getTariff())){
                    //判断purchaseOrderDetails中的关税是否存在空的
                    for (PurchaseOrderDetail purchaseOrderDetail : purchaseOrderDetails){
                        if (ObjectUtil.isNull(purchaseOrderDetail.getTariff())){
                            //物流公司上传送货单：模板增加“关税”，如果有关税，供应商填关税比率（比如0.13）。当关税非空时，如果采购订单行的关税等于0或为空，则弹窗提醒（下单时不确定是否有关税，报关的时候才能确定），确定后关闭窗口。
                            throw new DaoException(StrUtil.format("根据“采购订单编码:{}”、“物料编码:{}”、“报关价格:{}”找到的订单行{}关税为空!",data.getPoCode(),data.getMaterialCode(),data.getTariff().stripTrailingZeros().toPlainString(),purchaseOrderDetail.getOrderRow()));
                        }
                        if (new BigDecimal(purchaseOrderDetail.getTariff()).compareTo(BigDecimal.ZERO)==0){
                            //物流公司上传送货单：模板增加“关税”，如果有关税，供应商填关税比率（比如0.13）。当关税非空时，如果采购订单行的关税等于0或为空，则弹窗提醒（下单时不确定是否有关税，报关的时候才能确定），确定后关闭窗口。
                            throw new DaoException(StrUtil.format("根据“采购订单编码:{}”、“物料编码:{}”、“报关价格:{}”找到的订单行{}关税为0!",data.getPoCode(),data.getMaterialCode(),data.getTariff().stripTrailingZeros().toPlainString(),purchaseOrderDetail.getOrderRow()));
                        }
                    }

                }
                //如果purchaseOrderDetails中需求日期一样则按照订单行号从小到大排序，不一样按照需求日期从大到小排序
                purchaseOrderDetails.sort(Comparator.comparing(PurchaseOrderDetail::getRequireDate, Comparator.nullsLast(Comparator.reverseOrder())).thenComparing(PurchaseOrderDetail::getOrderRow));

                if (CollUtil.isEmpty(purchaseOrderDetails)){
                    throw new DaoException(StrUtil.format("根据“采购订单编码:{}”、“物料编码:{}”、“进口单价:{}”未找到可分配的订单行!",data.getPoCode(),data.getMaterialCode(),data.getPrice()));
                }
                final PurchaseOrder purchaseOrder = purchaseOrderService.getOne(new LambdaQueryWrapper<>(PurchaseOrder.class)
                        .eq(PurchaseOrder::getOrderCode, data.getPoCode()).eq(PurchaseOrder::getDelFlag, 0));

                //种是USD的采购订单，由物流供应商创建送货单。2026-01-02 邓京术
//                if (StringUtils.isNotEmpty(purchaseOrder.getCurrencyCode()) && "USD".equals(purchaseOrder.getCurrencyCode())) {
//                    throw new DaoException("币种是USD的采购订单，由物流供应商创建送货单。");
//                }

                if ((purchaseOrder.getOrderTypeCode().equals("Z009")||purchaseOrder.getOrderTypeCode().equals("Z004"))&&purchaseOrder.getCurrencyCode().equals("USD")){
                    existPushSap = true;
                }else {
                    notExistPushSap = true;
                }

                //汇总订单明细的noClearNum未清数量
                BigDecimal allTransitNum = BigDecimal.ZERO;
                BigDecimal allNoClearNum = BigDecimal.ZERO;

                //已送货数量
                BigDecimal totalNum =  BigDecimal.ZERO;
                //剩余可送货数量
                BigDecimal plusTotalNum =  data.getNum();
                BigDecimal purchaseOrderNum = BigDecimal.ZERO;
                for (PurchaseOrderDetail baseDTO1 : purchaseOrderDetails) {
                    purchaseOrderNum = baseDTO1.getNum();
                    ImportCreateDeliveryOrderDetailDTO resultDTO = deliveryOrderDetailConvert.fillData(baseDTO1, new ImportCreateDeliveryOrderDetailDTO());
                    //在途数量
                    BigDecimal transitNum = deliveryOrderDetailService.findCountByPurchaseDetail(baseDTO1.getOrderCode(),
                            baseDTO1.getOrderRow(), DeliveryStatus.SHIPPED.getStatus(), DelFlag.NORMAL.getStatus());
                    resultDTO.setOnlineNum(transitNum);
                    allTransitNum = allTransitNum.add(transitNum);
                    allNoClearNum = allNoClearNum.add(baseDTO1.getNoClearNum());

                    resultDTO.setRequireDate(data.getCodeDate());

                    //如果是解锁需要把解锁的数量放到可送数量里面
                    if (null != baseDTO1.getUnlockFlag() && baseDTO1.getUnlockFlag().equals(FlagConst.Y.getCode())) {
                        baseDTO1.setEnableNum(baseDTO1.getUnlockNum());
                        baseDTO1.setNum(baseDTO1.getUnlockNum());
                    }
                    final String markFlag = purchaseOrder.getMarkFlag();
                    final DeliveryType deliveryType = DeliveryType.forCode(markFlag);
//                    if (deliveryType.equals(DeliveryType.ORDER)) {
                        //可清数量 = 未清数量 - 在途数量
                        final BigDecimal enableNum = baseDTO1.getNoClearNum().subtract(transitNum);
                        resultDTO.setEnableNum(enableNum);
                        totalNum = totalNum.add(enableNum);
                        //可送货数量

                    if (plusTotalNum.compareTo(BigDecimal.ZERO)<=0){
                        continue;
                    }
                        //如果送货数量大于本次送货数量，则添加
                        if (plusTotalNum.subtract(enableNum).compareTo(BigDecimal.ZERO) >= 0){
                            plusTotalNum =  plusTotalNum.subtract(enableNum);
                            resultDTO.setNum(enableNum);
                        }else {
                            //如果送货数量小于可送货数量，则添加可送货数
//                            resultDTO.setEnableNum(plusTotalNum);

                            resultDTO.setNum(plusTotalNum);
                            plusTotalNum = BigDecimal.ZERO;
                        }
//                    }else {
//                        resultDTO.setNum(data.getNum());
//                    }

                    resultDTO.setNoClearNum(baseDTO1.getNoClearNum());
                    resultDTO.setFactoryCode(baseDTO1.getFactoryCode());
                    resultDTO.setOrderState(purchaseOrder.getState());
                    resultDTO.setCompanyCode(purchaseOrder.getCompanyCode());
                    resultDTO.setCompanyName(purchaseOrder.getCompanyName());
                    resultDTO.setPurchaseOrderRow(baseDTO1.getOrderRow());
                    resultDTO.setPurchaseOrderCode(baseDTO1.getOrderCode());
                    resultDTO.setPurchaseOrderNum(purchaseOrderNum);
//                        resultDTO.setRemark(remark);

                    resultDTO.setId(null);
                    resultList.add(resultDTO);

                }
                //需要比较下这个未清-在途是否大于等于送货数量
                final BigDecimal enableNum = allNoClearNum.subtract(allTransitNum);

//                if (data.getNum().compareTo(enableNum) < 0) {
//                    final String format = StrUtil.format("导入失败:订单号{},物料号{},单价{},送货数量{},可送货数量{},送货数量小于可送货数量", purchaseOrder.getOrderCode(),
//                            data.getMaterialCode(),
//                            data.getNetPrice(),
//                            allTransitNum,
//                            enableNum
//                    );
//                    throw new DaoException(format);
//                }

                //需要比较下这个未清-在途是否大于等于送货数量
                if (enableNum.compareTo(data.getNum()) < 0) {
                    final String format = StrUtil.format("导入失败:订单号{},物料号{},单价{},可送货数量{},送货数量{},可送货数量不足", purchaseOrder.getOrderCode(),
                            data.getMaterialCode(),
                            data.getPrice(),
                            enableNum,
                            data.getNum()
                    );
                    throw new DaoException(format);
                }
            }


        }
        if (existPushSap&&notExistPushSap){
            throw new DaoException("关联方和非关联方不能一起创建");
        }

        if (CollUtil.isNotEmpty(resultList)){
            String firstFactoryCode = resultList.get(0).getFactoryCode();
            final boolean match = resultList.stream()
                    .map(ImportCreateDeliveryOrderDetailDTO::getFactoryCode)
                    .allMatch(factoryCode1 -> factoryCode.equals(firstFactoryCode));
            if (!match) {
                throw new DaoException("工厂不一致无法导入!");
            }

            String firstCompanyCode = resultList.get(0).getCompanyCode();
            final boolean match1 = resultList.stream()
                    .map(ImportCreateDeliveryOrderDetailDTO::getCompanyCode)
                    .allMatch(companyCode -> companyCode.equals(firstCompanyCode));
            if (!match1) {
                throw new DaoException("公司不一致无法导入!");
            }
            BigDecimal finalTotalCaseNum = totalCaseNum;
            String finalEntrustNo = entrustNo;
            resultList = resultList.stream()
                    .filter(dto -> dto.getEnableNum() != null
                            && dto.getEnableNum().compareTo(BigDecimal.ZERO) != 0)
                    .peek(dto -> {
                        dto.setTotalCaseNum(finalTotalCaseNum);
                        dto.setEntrustNo(finalEntrustNo);
                    })
                    .collect(Collectors.toList());
        }else {
            throw new DaoException("未找到可分配的订单行!");
        }
        return resultList;
    }

    @Override
    @DS(SLAVE)
    public List<String> findAccountStatementByOrderCode(Long id) {
        return deliveryOrderService.findAccountStatementByOrderCode(id);
    }

    @Override
    public void setEntrustNo(Long id, String entrustNo) {
        DeliveryOrder deliveryOrder = deliveryOrderService.getById(id);
        deliveryOrder.setEntrustNo(entrustNo);
        deliveryOrderService.updateById(deliveryOrder);
    }

    /**
     * 根据委托单号获取送货单号
     *
     * @param entrustNo 委托单号
     * @return 送货单号
     */
    @Override
    public List<String> getDevOrderCodesByEntrustNo(String entrustNo) {
        List<DeliveryOrder> list = deliveryOrderService.list(new LambdaQueryWrapper<DeliveryOrder>().eq(DeliveryOrder::getEntrustNo, entrustNo));
        return list.stream().map(DeliveryOrder::getOrderCode).collect(Collectors.toList());
    }

    /**
     * 根据委托单号获取工厂编号
     *
     * @param entrustNo 委托单号
     * @return 工厂编号
     */
    @Override
    public String getFactoryCodesByEntrustNo(String entrustNo) {
        // 1. 入参非空校验
        if (entrustNo == null || entrustNo.trim().isEmpty()) {
            return "";
        }
        try {
            // 2. 查询数据：第二个参数设为 false，查不到返回 null（不抛异常）
            DeliveryOrder deliveryOrder = deliveryOrderService.getOne(
                    new LambdaQueryWrapper<DeliveryOrder>().eq(DeliveryOrder::getEntrustNo, entrustNo.trim()),
                    false // 关键：避免查不到数据时抛 EmptyResultDataAccessException
            );
            return deliveryOrder.getFactoryCode().toString();
        } catch (Exception e) {
            return "";
        }
    }

    @Override
    public void pushDeliveryToSap(String ids) {
        final List<Long> idList = JSONArray.parseArray(ids, Long.class);
        for (Long id : idList){
            DeliveryOrder deliveryOrder = deliveryOrderService.getById(id);
            if (deliveryOrder.getShipmentSapStatus() == null|| deliveryOrder.getShipmentSapStatus() == 0){
                deliveryOrderPushSapLogic.pushDeliveryToSap(id,"C");
            }else {
                deliveryOrderPushSapLogic.pushDeliveryToSap(id,"M");
            }
        }

    }

    @Override
    public void updateReturnConfirmStatus(String ids) {
        final List<Long> idList = JSONArray.parseArray(ids, Long.class);
        for (Long id : idList){
            DeliveryOrder deliveryOrder = deliveryOrderService.getById(id);
            deliveryOrder.setReturnConfirmStatus(2);
            deliveryOrderService.updateById(deliveryOrder);
        }
    }

    @Override
    public void updateDeliveryReturnConfirmStatus(List<UpdateOrderDTO> updateOrderDTOS) {
        for (UpdateOrderDTO updateOrderDTO : updateOrderDTOS){
            if (StrUtil.isNotEmpty(updateOrderDTO.getOrderCode())){
                deliveryOrderService.update(new LambdaUpdateWrapper<>(DeliveryOrder.class)
                        .eq(DeliveryOrder::getOrderCode,updateOrderDTO.getOrderCode())
                        //.eq(DeliveryOrder::getReturnConfirmStatus,1)
                        .set(DeliveryOrder::getReturnConfirmStatus,updateOrderDTO.getReturnConfirmStatus())
                        .set(DeliveryOrder::getMvPostDate,updateOrderDTO.getMvPostDate())
                );
            }
        }
    }

    @Override
    public void getFtp(String startDate1, String endDate1) {
        // 尝试获取锁，防止重复执行（即使有多个 JobDetail 或手动触发）
        if (!lock.tryLock()) {
            log.warn("Job is already running. Skipping duplicate execution.");
            throw new DaoException("系统正在处理，请稍后");
        }

        try {
            // 检查是否被中断（支持 InterruptableJob）
            if (Thread.currentThread().isInterrupted()) {
                log.info("Job was interrupted before execution.");
                return;
            }
            log.info("****************FTP下载开始****************");
            long start = System.currentTimeMillis();
            StringBuilder stringBuilder = new StringBuilder();
            Date startDate = DateUtil.parse(startDate1 + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
            Date endDate = DateUtil.parse(endDate1 + " 23:59:59", "yyyy-MM-dd HH:mm:ss");

            // 自动计算线程数
            int threadCount = Math.max(10, Runtime.getRuntime().availableProcessors() * 2);

            // 格式化日期用于日志
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = sdf.format(startDate);

            // 本地临时文件夹
            String localTempFileDir = StrUtil.concat(false, LOCAL_TEMP_FILE_DIR, File.separator, dateStr);
            // FTP服务器文件夹
            SimpleDateFormat sdfFileY = new SimpleDateFormat("yy");
            SimpleDateFormat sdfFileM = new SimpleDateFormat("M");



            //举例：10月为25A,11月为25B，12月为25C
            String year = sdfFileY.format(startDate);
            String month = sdfFileM.format(startDate).equals("10")?"A":sdfFileM.format(startDate).equals("11")?"B":sdfFileM.format(startDate).equals("12")?"C":sdfFileM.format(startDate);
            String startDateSdf = StrUtil.format("{}{}", year, month);

            String year1 = sdfFileY.format(endDate);
            String month1 = sdfFileM.format(endDate).equals("10")?"A":sdfFileM.format(endDate).equals("11")?"B":sdfFileM.format(endDate).equals("12")?"C":sdfFileM.format(endDate);
            String endDateSdf = StrUtil.format("{}{}", year1, month1);

            List<String> remoteDirList = new ArrayList<>();
            remoteDirList.add(REMOTE_ROOT_DIR + "/C" + startDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
            remoteDirList.add(REMOTE_ROOT_DIR + "/H" + startDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
            remoteDirList.add(REMOTE_ROOT_DIR + "/Y" + startDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
            remoteDirList.add(REMOTE_ROOT_DIR + "/X" + startDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
            if (!startDateSdf.equals(endDateSdf)){
                remoteDirList.add(REMOTE_ROOT_DIR + "/C" + endDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
                remoteDirList.add(REMOTE_ROOT_DIR + "/H" + endDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
                remoteDirList.add(REMOTE_ROOT_DIR + "/Y" + endDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
                remoteDirList.add(REMOTE_ROOT_DIR + "/X" + endDateSdf);// 例：/rcvbill - 快捷方式/送货单扫描/C259
            }
            log.info(StrUtil.format("指定FTP目录列表：{}\n", Joiner.on(",").join(remoteDirList)));
            stringBuilder.append(StrUtil.format("指定FTP目录列表：{}\n", Joiner.on(",").join(remoteDirList)));
            stringBuilder.append(StrUtil.format("本地临时文件夹：{}\n", localTempFileDir));
            log.info(StrUtil.format("本地临时文件夹：{}\n", localTempFileDir));
//        for (String remoteDir : remoteDirList){
            log.info("开始下载前一天的送货单: {}, 远程目录: {}, 本地目录: {}", dateStr, remoteDirList, localTempFileDir);
            try {
                // 调用下载方法
                ftpUtils.threadDownloadFilesByDateRangeList(remoteDirList, localTempFileDir, this::processImage,
                        threadCount, startDate, endDate, stringBuilder);
            } catch (IOException e) {
                log.error("下载送货单失败", e);
                stringBuilder.append(StrUtil.format("下载送货单失败：{}\n", e));
                return;
            } catch (Exception e) {
                log.error("处理请求异常", e);
                stringBuilder.append(StrUtil.format("处理请求异常：{}\n", e));
                return;
            }
            // 2 上传文件，并绑定业务关系
            List<FtpResultDto> allFiles = getAllFiles(localTempFileDir);
            List<String> existNo = org.apache.commons.compress.utils.Lists.newArrayList();
            List<String> noExistNo = org.apache.commons.compress.utils.Lists.newArrayList();
            List<String> suNo = org.apache.commons.compress.utils.Lists.newArrayList();
            log.info(StrUtil.format("需要下载的文件信息：{}\n", Joiner.on(",").join(allFiles)));
            stringBuilder.append(StrUtil.format("需要下载的文件信息：{}\n", Joiner.on(",").join(allFiles)));
            LogThirdPartyCall logThirdPartyCall = new LogThirdPartyCall();
            logThirdPartyCall.setInfCode("ftp_down_order");
            logThirdPartyCall.setInfName("ftp下载送货单附件");
            logThirdPartyCall.setInfType(ThirdSysType.MES.getType());
            if (CollectionUtil.isNotEmpty(allFiles)) {
                log.info("开始上传到SRM文件服务器，并绑定送货单");
                try {
                    List<BusinessAttachment> businessAttachmentList = org.apache.commons.compress.utils.Lists.newArrayList();
                    for (FtpResultDto file : allFiles) {
                        File uploadFile = file.getFile();
                        // 2.1 获取送货单信息
                        String orderCode= file.getFileName().substring(0, 12);  // 送货单号
                        DeliveryOrder deliveryOrder = deliveryOrderService.getOne(new LambdaQueryWrapper<DeliveryOrder>().eq(DeliveryOrder::getOrderCode, orderCode));
                        if (Objects.isNull(deliveryOrder)) {
                            // 不存在的情况跳过
                            noExistNo.add(orderCode);
//                            fileLogic.safeDeleteTemplate(uploadFile);
                            continue;
                        }
                        existNo.add(orderCode);
                        if (uploadFile == null || !uploadFile.exists() || uploadFile.length() == 0) {
                            continue;
                        }
                        // 2.2 推送到SRM文件服务器，返回文件信息
                        Attachment Attachment = fileLogic.uploadFile(uploadFile);
                        // 2.3 推送完删除临时文件
//                        fileLogic.safeDeleteTemplate(uploadFile);
                        // 2.4 创建业务附件关系
                        BusinessAttachment oldBusinessAttachment = businessAttachmentService.getOne(new LambdaQueryWrapper<BusinessAttachment>()
                                .eq(BusinessAttachment::getBusinessCode, orderCode)
                                .eq(BusinessAttachment::getBusinessTypeCode, "delivery_order")
                                .eq(BusinessAttachment::getFileName, Attachment.getFileName())
                        );
                        if (oldBusinessAttachment != null){
                            continue;
                        }
                        BusinessAttachment insertData = new BusinessAttachment();
                        insertData.setFileId(Attachment.getId());
                        insertData.setFileName(Attachment.getFileName());
                        //如果开头为T，也是退货单
                        insertData.setType(file.getFileName().contains("TH")||file.getFileName().startsWith("T") ? "return_order" : "delivery_order");
                        insertData.setBusinessId(deliveryOrder.getId());
                        insertData.setBusinessCode(orderCode);
                        insertData.setBusinessTypeCode("delivery_order");
                        insertData.setCreateTime(LocalDateTime.now());
                        insertData.setCreateUser(1L);
                        insertData.setUpdateTime(LocalDateTime.now());
                        insertData.setUpdateUser(1L);
                        businessAttachmentList.add(insertData);
//                        businessAttachmentService.save(insertData);
                        suNo.add(orderCode);
                    }
                    businessAttachmentService.saveOrUpdateBatch(businessAttachmentList);

                } catch (Exception e) {
                    stringBuilder.append(StrUtil.format("文件上传失败：{}\n", e));
                    log.error("文件上传失败", e);
                } finally {
                    log.info("结束上传");
                }
                stringBuilder.append(StrUtil.format("系统存在的送货单：{}\n", CollUtil.isEmpty(existNo) ? "无" : Joiner.on(",").join(existNo)));
                stringBuilder.append(StrUtil.format("系统不存在的送货单：{}\n", CollUtil.isEmpty(noExistNo) ? "无" : Joiner.on(",").join(noExistNo)));
                stringBuilder.append(StrUtil.format("处理成功的送货单：{}\n", CollUtil.isEmpty(suNo) ? "无" : Joiner.on(",").join(suNo)));

                long end = System.currentTimeMillis();



                logThirdPartyCall.setInfRequestParams(stringBuilder.toString());
                logThirdPartyCall.setInfResponse("ok");
                logThirdPartyCall.setInfInfo(StrUtil.format("请求耗时：{}秒\n", (end - start) / 1000));
                logThirdPartyCall.setInfResult(1);
                logThirdPartyCall.setInfCallTime(LocalDateTime.now());
                logThirdPartyCallService.save(logThirdPartyCall);
                log.info("****************FTP下载结束****************");
                // 3 最后删除整个文件夹
                fileLogic.safeDeleteTemplate(new File(localTempFileDir));
            } else {
                log.info("远程目录: {},前一天暂无新增送货单", remoteDirList);
                long end = System.currentTimeMillis();
                logThirdPartyCall.setInfRequestParams(stringBuilder.toString());
                logThirdPartyCall.setInfResponse("没有需要下载的附件");
                logThirdPartyCall.setInfInfo(StrUtil.format("请求耗时：{}秒\n", (end - start) / 1000));
                logThirdPartyCall.setInfResult(0);
                logThirdPartyCall.setInfCallTime(LocalDateTime.now());
                logThirdPartyCallService.save(logThirdPartyCall);
            }

        } finally {
            lock.unlock(); // 确保释放锁
        }
    }

    private void processImage(File imageFile) {}

    private List<FtpResultDto> getAllFiles(String dir) {
        List<FtpResultDto> fileList = new ArrayList<>();
        File directory = new File(dir);

        if (!directory.exists() || !directory.isDirectory()) {
            log.error("目录不存在或不是有效目录: {}", dir);
            return fileList;
        }

        File[] files = directory.listFiles();
        if (files == null) return null;
        for (File file : files) {
            FtpResultDto ftpResultDto = new FtpResultDto();
            ftpResultDto.setFile(file);
            ftpResultDto.setFileName(file.getName());
            fileList.add(ftpResultDto);
        }
        return fileList;
    }
}