package com.jwipc.order.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
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.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.fastjson2.JSON;
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.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.SapResposeBody;
import com.jwipc.constant.FlagConst;
import com.jwipc.dto.ExportDataDTO;
import com.jwipc.exception.DaoException;
import com.jwipc.order.constant.PoSapClient;
import com.jwipc.order.constant.ShortageDataType;
import com.jwipc.order.constant.ShortagePlanStatus;
import com.jwipc.order.constants.CargoPlanConst;
import com.jwipc.order.convert.ShortageDataConvert;
import com.jwipc.order.convert.ShortageDetailConvert;
import com.jwipc.order.convert.ShortagePlanConvert;
import com.jwipc.order.dto.*;
import com.jwipc.order.entity.ShortageData;
import com.jwipc.order.entity.ShortageDetail;
import com.jwipc.order.entity.ShortagePlan;
import com.jwipc.order.logic.FileLogLogic;
import com.jwipc.order.logic.ShortagePlanLogic;
import com.jwipc.order.logic.ShortagePlanLogicAsn;
import com.jwipc.order.model.po.FileLogDTO;
import com.jwipc.order.model.po.ShortagePlanReleasePO;
import com.jwipc.order.model.po.ShortagePlanReplyPO;
import com.jwipc.order.model.query.BasicForeignQuotaQuery;
import com.jwipc.order.model.query.BasicPlanQuery;
import com.jwipc.order.service.IShortageDataService;
import com.jwipc.order.service.IShortageDetailService;
import com.jwipc.order.service.IShortagePlanService;
import com.jwipc.order.utils.DataCheckUtils;
import com.jwipc.order.utils.DownloadUtils;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.prop.SysProp;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.QuotaManagementClient;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.*;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.FileResposeCDTO;
import com.jwipc.sys.client.dto.ProductInfoDTO;
import com.jwipc.sys.client.dto.PurchaseGroupDTO;
import com.jwipc.tender.client.dto.QuotaManagementClientDTO;
import com.jwipc.util.EasyExcelUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;

/**
 * @Author: swq
 * @Date: 2024/4/29 14:26
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ShortagePlanLogicImpl implements ShortagePlanLogic {
    private final IShortagePlanService shortagePlanService;
    private final IShortageDetailService shortageDetailService;
    private final IShortageDataService shortageDataService;
    private final ShortageDataConvert shortageDataConvert;
    private final ShortagePlanConvert shortagePlanConvert;
    private final ProductClient productClient;
    private final ShortageDetailConvert shortageDetailConvert;
    private final QuotaManagementClient quotaManagementClient;
    private final FileClient fileClient;
    private final PurchaseGroupClient purchaseGroupClient;
    private final ModelAggregationService modelAggregationService;
    private final UserPurchaseGroupClient userPurchaseGroupClient;
    private final PoSapClient sapClient;
    private final DictClient dictClient;
    private final SysProp sysProp;
    private final SupplierClient supplierClient;
    private final RedisTemplate redisTemplate;
    private final StringRedisTemplate stringRedisTemplate;
    private final ShortagePlanLogicAsn shortagePlanLogicAsn;
    private final FileLogLogic fileLogLogic;


    @Override
    public void pushReplyImportToCash(List<ShortagePlanReplyDTO> result) {
        LocalTime nowTime = LocalTime.now();
        long secondsUntilMidnight = 86400 - nowTime.toSecondOfDay();
        redisTemplate.opsForValue().set("import_reply_" +String.valueOf(LoginUtil.getUserId()), com.alibaba.fastjson2.JSON.toJSONString(result), secondsUntilMidnight, TimeUnit.SECONDS);
    }

    @Override
    public PageView selectListByPage(BasicPlanQuery query) {
        final Page<ShortagePlan> dbPage = PageUtil.toPage(query);
        List<com.jwipc.order.model.po.ShortagePlanPO> poList = shortagePlanService.selectListByPage(dbPage, query);
        List<ShortagePlanListDTO> dtoList = shortagePlanConvert.POToDTOList(poList);
        return PageUtil.getPV(dtoList, dbPage.getTotal());
    }

    /**
     * 导入预测数据
     *
     * @param file      文件信息
     * @param startDate 开始时间
     * @param userId    操作人
     * @return 是否导入成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DS(SLAVE)
    public boolean importShortagePlan(MultipartFile file, String startDate, Long userId) {
        //导入逻辑
        List<ShortagePlanImportDTO> cachedDataList = Lists.newArrayList();
        Map<String, List<QuotaManagementClientDTO>> quotaCache = Maps.newHashMap();
        //需要处理供应商的配额数据
        final List<PurchaseGroupDTO> all = purchaseGroupClient.getAll();
        final Set<String> purchaseGroupCodes = all.stream().map(a -> a.getPurchaseGroupCode())
                .collect(Collectors.toSet());
        try {
            EasyExcel.read(file.getInputStream(), ShortagePlanImportDTO.class,
                    new ReadListener<ShortagePlanImportDTO>() {
                        @Override
                        public void invoke(ShortagePlanImportDTO data, AnalysisContext context) {
                            //需要查询物料
                            final String materialCode = data.getMaterialCode();
                            final String factoryCode = data.getFactoryCode();
                            if (StrUtil.isEmpty(materialCode)) {
                                throw new DaoException("物料不能为空");
                            }
                            if (StrUtil.isEmpty(factoryCode)) {
                                throw new DaoException("工厂不能为空");
                            }
                            final ProductInfoDTO productInfoDTO = productClient.getByMaterialCodeAndFactoryCode(
                                    materialCode, factoryCode);
                            if (Objects.isNull(productInfoDTO)) {
                                throw new DaoException("物料不存在");
                            }
                            if (StrUtil.isEmpty(data.getPurchaseGroup())) {
                                throw new DaoException("采购组不能为空");
                            }
                            if (!purchaseGroupCodes.contains(data.getPurchaseGroup())) {
                                throw new DaoException("采购组不存在");
                            }
                            if (Objects.isNull(data.getShortageQuantity())) {
                                throw new DaoException("缺料数量不能为空");
                            }
                            cachedDataList.add(data);
                            final List<QuotaManagementClientDTO> quotaManagementClientDTOS =
                                    quotaManagementClient.getByMaterialCodeAndFactoryCode(
                                            materialCode, factoryCode);
                            if (CollUtil.isNotEmpty(quotaManagementClientDTOS)) {
                                quotaCache.put(StrUtil.format("{}&{}", materialCode, factoryCode),
                                        quotaManagementClientDTOS);
                            }
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        final FileResposeCDTO multipartFile = fileClient.createMultipartFile(file);
        List<ShortageDetail> entities = shortageDetailConvert.importDtos2Entities(cachedDataList);
        final long maxVersion = shortagePlanService.findMaxVersion();
        final long nextVersion = maxVersion + 1;
        ShortagePlan shortagePlan = new ShortagePlan();
        shortagePlan.setStatus(ShortagePlanStatus.NEW.getCode());
        shortagePlan.setCreateTime(LocalDateTime.now());
        shortagePlan.setVersion(nextVersion);
        final String newSerialNumber = shortagePlanService.findNewSerialNumber(null);
        shortagePlan.setSerialNumber(genSerialNumber(DateTime.now(), newSerialNumber));
        shortagePlan.setCreateId(LoginUtil.getUserId());
        shortagePlan.setTitle(file.getOriginalFilename());
        shortagePlan.setStartTime(LocalDate.parse(startDate));
        shortagePlan.setEndTime(LocalDate.parse(startDate).plusDays(60));
        shortagePlan.setFilePath(multipartFile.getFilePath());
        shortagePlanService.update(new LambdaUpdateWrapper<ShortagePlan>().set(ShortagePlan::getStatus,
                        ShortagePlanStatus.INVALID.getCode())
                .ne(ShortagePlan::getStatus, ShortagePlanStatus.NEW.getCode()));
        shortagePlanService.save(shortagePlan);
        final Long planId = shortagePlan.getId();
        entities.forEach(a -> a.setPlanId(shortagePlan.getId()));
        shortageDetailService.saveBatch(entities);
        List<ShortageData> insertLists = Lists.newArrayList();
        for (ShortageDetail entity : entities) {
            final String materialCode = entity.getMaterialCode();
            final String factoryCode = entity.getFactoryCode();
            final String key = StrUtil.format("{}&{}", materialCode, factoryCode);
            final List<QuotaManagementClientDTO> quotaManagementClientDTOS = quotaCache.get(key);
            if (CollUtil.isNotEmpty(quotaManagementClientDTOS)) {
                for (QuotaManagementClientDTO quotaManagementClientDTO : quotaManagementClientDTOS) {
                    final String supplierCode = quotaManagementClientDTO.getSupplierCode();
                    final BigDecimal quota = quotaManagementClientDTO.getQuota();
                    ShortageData shortageData = new ShortageData();
                    shortageDetailConvert.fillData(shortageData, entity);
                    shortageData.setId(null);
                    shortageData.setPlanId(planId);
                    shortageData.setDetailId(entity.getId());
                    shortageData.setSupplierCode(supplierCode);
                    shortageData.setType(ShortageDataType.QUOTA.getCode());
                    shortageData.setQuota(quota);
                    final BigDecimal shortageQuantity = shortageData.getShortageQuantity();
                    final BigDecimal ddd = shortageQuantity.multiply(quota.divide(new BigDecimal("100")));
                    shortageData.setShortageQuantity(ddd);
                    insertLists.add(shortageData);
                }

            } else {
                ShortageData shortageData = new ShortageData();
                shortageDetailConvert.fillData(shortageData, entity);
                shortageData.setId(null);
                shortageData.setPlanId(planId);
                shortageData.setType(ShortageDataType.MANUAL.getCode());
                shortageData.setDetailId(entity.getId());
                insertLists.add(shortageData);
            }
        }
        shortageDataService.saveBatch(insertLists);
        return true;
    }


    @Override
    public ShortagePlan selectById(Long id) {
        ShortagePlan shortagePlan = shortagePlanService.getById(id);
        return shortagePlan;
    }

    @Override
    public List<ShortagePlan> selectPlanList() {
        List<ShortagePlan> list = shortagePlanService.list(
                new LambdaQueryWrapper<ShortagePlan>().ne(ShortagePlan::getStatus, 1)
                        .orderBy(true, false, ShortagePlan::getId));
        return list;
    }


    @Override
    public List<ShortageData> selectDataList(long planId) {
        List<ShortageData> dataList = Lists.newArrayList();
        return dataList;
    }

    @Override
    public void getExportReplyData(HttpServletResponse response, String exportFiled, BasicForeignQuotaQuery query) {
        hanlderQuery(query);
        //需要查询一下总数
        query.setRows(1);
        query.setPage(1);
        String go_published = stringRedisTemplate.opsForValue().get("export_reply_data_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在导出中，请勿重复操作！");
        }
        final Page<ShortagePlanReplyPO> page = PageUtil.toPage(query);
        shortageDataService.getSupplierReply(page, query);
        //需要变色的列
        Set<String> colorList = Set.of("mainMaterialReplyQuantity", "mainMaterialReplyDate", "mainMaterialReply","remark",
                "successorMaterialReplyQuantity", "successorMaterialDeliveryDateReply",
                "substituteMaterial1ReplyQuantity", "substituteMaterial1DeliveryDate",
                "substituteMaterial2ReplyQuantity", "substituteMaterial2DeliveryDate",
                "substituteMaterial3ReplyQuantity", "substituteMaterial3DeliveryDate");
        // 查询数据列表，直接调用列表的查询，无需特殊改动
        List<ExportDataDTO> exportDataDTOS = JSON.parseArray(exportFiled, ExportDataDTO.class);
        //如果供应商导出欠料回复，代码控制不给导出如下3列，之前是通过浏览器缓存处理的 2024-11-13，邓京术
        if (LoginUtil.isSupplier()) {
            Iterator it = exportDataDTOS.iterator();
            while (it.hasNext()) {
                ExportDataDTO exportDataDTO = (ExportDataDTO) it.next();
                if (exportDataDTO.getField().equals("currentQuantity") || exportDataDTO.getField().equals("frozenInventory")
                        || exportDataDTO.getField().equals("productLongName")) {
                    it.remove();
                }
            }
        }
        final ExportDataDTO exportDataDTO = ExportDataDTO.builder().field("id").title("").build();
        exportDataDTOS.add(0, exportDataDTO);
        for (ExportDataDTO dataDTO : exportDataDTOS) {
            if (colorList.contains(dataDTO.getField())) {
                dataDTO.setColor(IndexedColors.YELLOW.getIndex());
            }
        }

        final long total = page.getTotal();
        if (total > sysProp.getExportMaxCount()) {
            //从字典查询配置文件，最大允许导出的数据条数， 邓京术 2025-05-26
            List<DictDTO> dictDTOS = dictClient.getDicByType("excel_export_data_count");
            String exportCount = dictDTOS.get(0).getCode();
            //异步执行导出
            if (total > Integer.parseInt(exportCount)) {
                stringRedisTemplate.opsForValue().set("export_reply_data_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                throw new DaoException(StrUtil.format("导出数据超过{}条", exportCount));
            } else {
                stringRedisTemplate.opsForValue().set("export_reply_data_" + LoginUtil.getUserId(), "Y", 2, TimeUnit.HOURS);
                Long userId = LoginUtil.getUserId();
                FileLogDTO fileLogDTO = new FileLogDTO();
                fileLogDTO.setCreateTime(LocalDateTime.now());
                fileLogDTO.setCreateUser(userId);
                fileLogDTO.setFileType(3);
                fileLogDTO.setStatus("1");
                fileLogDTO.setMsg("数据导出中");
                fileLogDTO.setDeleteFlag(0);
                Long id = fileLogLogic.createFile(fileLogDTO);
                shortagePlanLogicAsn.exportToReplyData(query, exportDataDTOS,userId, id);
                throw new DaoException(StrUtil.format("执行成功，请稍候在导出文件列表查看."));
            }
        } else {
            stringRedisTemplate.opsForValue().set("export_reply_data_" + LoginUtil.getUserId(), "Y", 30, TimeUnit.SECONDS);
            List<ShortagePlanReplyPO> replyPOS = shortageDataService.getSupplierReply(null, query);
            final List<ShortagePlanReplyDTO> shortagePlanReplyDTOS = shortageDataConvert.pos2Dtos(replyPOS);
            modelAggregationService.processRelationAggregation(shortagePlanReplyDTOS);
            //隐藏的第二行修改为不隐藏，采购说排序后会导致行不存在了，导致导入失败。 2024-09-10 邓京术
//            EasyExcelUtils.trendsModelWriteTow(response,
//                    "欠料明细回复数据-" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN), "sheet", shortagePlanReplyDTOS,
//                    exportDataDTOS);
            //同步执行
            try {
                EasyExcelUtils.trendsModelWriteTow(response,
                        "欠料明细数据-" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN), "sheet", shortagePlanReplyDTOS,
                        exportDataDTOS);
            } catch (IOException e) {
                stringRedisTemplate.opsForValue().set("export_reply_data_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                throw new RuntimeException("导出excel文档失败.");
            }
            stringRedisTemplate.opsForValue().set("export_reply_data_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
        }
    }


    private void hanlderQuery(BasicForeignQuotaQuery query) {
        if (LoginUtil.isSupplier()) {
            query.setSupplier(LoginUtil.getSupplierCode());
            //如果是供应商登录 ，只能查询出已发布给供应商的数据 邓京术 2025-03-12
            query.setDeployToSupplier(1);
        } else {
            //增加采购组权限
            final Set<String> userPurchaseGroupCode = userPurchaseGroupClient.getUserPurchaseGroupCode(
                    LoginUtil.getUserId());
            query.setUserPurchaseGroupCodes(userPurchaseGroupCode);
        }
        if (Objects.isNull(query.getStatus())) {
            query.setStatus(1);
        }
    }

    @Override
    public PageView getReplyData(BasicForeignQuotaQuery query) {
        hanlderQuery(query);
        final Page<ShortagePlanReplyPO> page = PageUtil.toPage(query);
        List<ShortagePlanReplyPO> replyPOS = shortageDataService.getSupplierReply(page, query);
        final List<ShortagePlanReplyDTO> shortagePlanReplyDTOS = shortageDataConvert.pos2Dtos(replyPOS);
        modelAggregationService.processRelationAggregation(shortagePlanReplyDTOS);
        return PageUtil.getPV(shortagePlanReplyDTOS, page.getTotal());
    }


    @Override
    public String downloadPlanFileByTypeAndPlanId(Long planId,
                                                  @RequestParam(value = "type", defaultValue = "") String type,
                                                  HttpServletRequest request,
                                                  HttpServletResponse response,
                                                  @RequestParam(value = "downFileName", defaultValue = "") String downFileName,
                                                  @RequestParam(value = "downFilePath", defaultValue = "") String downFilePath)
    {
        final String filePath;
        final String fileName;
        switch (type) {
            //标准预测
            case "basic":
                final ShortagePlan basicPlan = shortagePlanService.getById(planId);
                filePath = basicPlan.getFilePath();
                fileName = basicPlan.getTitle();
                break;
            default:
                if (StrUtil.isNotEmpty(downFilePath)) {
                    filePath = downFilePath;
                    fileName = StrUtil.isEmpty(downFileName) ? new File(filePath).getName() : downFileName;
                } else {
                    throw new RuntimeException("File does not exist!");
                }
        }
        final String finalFilePath = fileClient.getRootPath() + filePath;
        if (StrUtil.isEmpty(finalFilePath)) {
            throw new RuntimeException("File does not exist!");
        }
        final File file = new File(finalFilePath);
        if (!file.exists()) {
            throw new RuntimeException("File does not exist!");
        }
        try {
            DownloadUtils.downloadFile(fileName, finalFilePath, request, response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("File download failed!");
        }
        return null;
    }


    private void pushToSap(List<ShortageData> shortageData) {
//        final List<ShortageData> shortageData = shortageDataService.listByIds(ids);
        //需要查询明细数据
        final Set<Long> detailIds = shortageData.stream().map(ShortageData::getDetailId).collect(Collectors.toSet());
        final List<ShortageDetail> shortageDetails = shortageDetailService.listByIds(detailIds);
        final Map<Long, ShortageDetail> detailMap = shortageDetails.stream()
                .collect(Collectors.toMap(ShortageDetail::getId, a -> a));
        UpdateShortagePlanSapDTO.ITData data = new UpdateShortagePlanSapDTO.ITData();
        List<UpdateShortagePlanSapDTO.ITData.Item> items = Lists.newArrayList();
        for (ShortageData shortageDatum : shortageData) {
            final Long detailId = shortageDatum.getDetailId();
            final ShortageDetail shortageDetail = detailMap.get(detailId);
            UpdateShortagePlanSapDTO.ITData.Item item = new UpdateShortagePlanSapDTO.ITData.Item();
            item.MATNR = shortageDetail.getMaterialCode();
            item.WERKS = shortageDetail.getFactoryCode();
            item.MATNR1 = shortageDetail.getSubstituteMaterial1();
            item.MATNR2 = shortageDetail.getSubstituteMaterial2();
            item.MATNR3 = shortageDetail.getSubstituteMaterial3();
            item.AUFNR = shortageDetail.getWorkOrderNumber();
            item.Z_VER = shortageDetail.getShortageVersion();
            item.Z_XQRQ = shortageDetail.getDemandDate();
            item.Z_QLSL = shortageDetail.getShortageQuantity();
            shortageDataConvert.fillItem(item, shortageDatum);
            items.add(item);
        }
        data.setItem(items);
        UpdateShortagePlanSapDTO shortagePlanSapDTO = new UpdateShortagePlanSapDTO();
        shortagePlanSapDTO.setIT_DATA(data);
        final SapResposeBody sapResposeBody = sapClient.updateShortagePlan(shortagePlanSapDTO);
        if (!sapResposeBody.getES_RET().getCODE().equals(RestCode.SAP_SUCCESS.getCode())) {
            throw new DaoException(StrUtil.format("推送SAP错误:{}", sapResposeBody.getES_RET().getMSG()));
        }
    }


    @Override
    public void remove(String id) {
        //删除数据
        shortagePlanService.removeById(id);
        final List<ShortageDetail> shortageDetails = shortageDetailService.list(
                new LambdaQueryWrapper<>(ShortageDetail.class).eq(ShortageDetail::getPlanId, id));
        if (CollUtil.isNotEmpty(shortageDetails)) {
            final Set<Long> detailIds = shortageDetails.stream().map(ShortageDetail::getId).collect(Collectors.toSet());
            shortageDataService.remove(
                    new LambdaQueryWrapper<>(ShortageData.class).in(ShortageData::getDetailId, detailIds));
            shortageDetailService.removeByIds(detailIds);
        }
    }

    /**
     * 发布页面，查询功能
     * @param basicPlanQuery
     * @return
     */
    @Override
    public PageView getToPublishedData(BasicPlanQuery basicPlanQuery) {
        final Page<ShortagePlanReleasePO> page = PageUtil.toPage(basicPlanQuery);
        List<ShortagePlanReleasePO> list = shortagePlanService.findWaitReleaseData(page, basicPlanQuery);
        List<ShortagePlanReleaseDTO> result = shortageDetailConvert.pos2Dtos(list);
        modelAggregationService.processRelationAggregation(result);
        return PageUtil.getPV(result, page.getTotal());
    }

    /**
     * 发布页面，数据导出按钮
     * @param basicPlanQuery
     * @return
     */
    @Override
    public void exportToPublishedData(HttpServletResponse response, String exportFiled, BasicPlanQuery basicPlanQuery) {
        //需要查询一下总数
        basicPlanQuery.setRows(1);
        basicPlanQuery.setPage(1);
        String go_published = stringRedisTemplate.opsForValue().get("export_published_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在导出中，请勿重复操作！");
        }
        final Page<ShortagePlanReleasePO> page = PageUtil.toPage(basicPlanQuery);
        shortagePlanService.findWaitReleaseData(page, basicPlanQuery);
        final long total = page.getTotal();
//        if (total > sysProp.getExportMaxCount()) {
////            throw new DaoException(StrUtil.format("导出数据超过{}条", sysProp.getExportMaxCount()));
//        }
        Set<String> colorList = Set.of("supplierCode", "launchDate", "launchDateRemark");
        // 查询数据列表，直接调用列表的查询，无需特殊改动
        List<ExportDataDTO> exportDataDTOS = JSON.parseArray(exportFiled, ExportDataDTO.class);
        final ExportDataDTO exportDataDTO = ExportDataDTO.builder().field("id").title("").build();
        exportDataDTOS.add(0, exportDataDTO);
        for (ExportDataDTO dataDTO : exportDataDTOS) {
            if (colorList.contains(dataDTO.getField())) {
                dataDTO.setColor(IndexedColors.YELLOW.getIndex());
            }
        }
        if (total > sysProp.getExportMaxCount()) {
            //从字典查询配置文件，最大允许导出的数据条数， 邓京术 2025-05-26
            List<DictDTO> dictDTOS = dictClient.getDicByType("excel_export_data_count");
            String exportCount = dictDTOS.get(0).getCode();
            //异步执行导出
            if (total > Integer.parseInt(exportCount)) {
                stringRedisTemplate.opsForValue().set("export_published_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                throw new DaoException(StrUtil.format("导出数据超过{}条", exportCount));
//                List<ShortagePlanReleaseDTO> listExport = list.stream().limit(100000).collect(Collectors.toList());
//                shortagePlanLogicAsn.exportToPublishedData(listExport, exportDataDTOS);
            } else {
                stringRedisTemplate.opsForValue().set("export_published_" + LoginUtil.getUserId(), "Y", 3600, TimeUnit.SECONDS);
                Long userId = LoginUtil.getUserId();
                FileLogDTO fileLogDTO = new FileLogDTO();
                fileLogDTO.setCreateTime(LocalDateTime.now());
                fileLogDTO.setCreateUser(userId);
                fileLogDTO.setFileType(1);
                fileLogDTO.setStatus("1");
                fileLogDTO.setMsg("数据导出中");
                fileLogDTO.setDeleteFlag(0);
                Long id = fileLogLogic.createFile(fileLogDTO);
                shortagePlanLogicAsn.exportToPublishedData(basicPlanQuery, exportDataDTOS,userId, id);
                throw new DaoException(StrUtil.format("执行成功，请稍候在导出文件列表查看."));
            }
//            throw new DaoException(StrUtil.format("执行成功，请稍候在导出文件列表查看."));
//            return ResponseEntity.ok("执行成功，请稍候在导出文件列表查看.");
        } else {
            stringRedisTemplate.opsForValue().set("published_" + LoginUtil.getUserId(), "Y", 30, TimeUnit.SECONDS);
            List<ShortagePlanReleasePO> list = shortagePlanService.findWaitReleaseData(null, basicPlanQuery);
            List<ShortagePlanReleaseDTO> result = shortageDetailConvert.pos2Dtos(list);
            modelAggregationService.processRelationAggregation(result);
            //同步执行
            try {
                EasyExcelUtils.trendsModelWriteTow(response,
                        "欠料明细数据-" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN), "sheet", result,
                        exportDataDTOS);
            } catch (IOException e) {
                throw new RuntimeException("导出excel文档失败.");
            }
            stringRedisTemplate.opsForValue().set("export_published_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
        }
//        return result;
    }

    @Override
    public List<ShortagePlanReleaseDTO> fildToPublishedData(BasicPlanQuery basicPlanQuery) {

        //需要查询一下总数
        basicPlanQuery.setRows(1);
        basicPlanQuery.setPage(1);
        final Page<ShortagePlanReleasePO> page = PageUtil.toPage(basicPlanQuery);
        shortagePlanService.findWaitReleaseData(page, basicPlanQuery);
        final long total = page.getTotal();
        if (total > sysProp.getExportMaxCount()) {
//            throw new DaoException(StrUtil.format("发布数据超过{}条", sysProp.getExportMaxCount()));
        }
        List<ShortagePlanReleasePO> list = shortagePlanService.findWaitReleaseData(null, basicPlanQuery);
        List<ShortagePlanReleaseDTO> result = shortageDetailConvert.pos2Dtos(list);
        return result;
    }

    @Override
    public void savePublished(List<ShortagePlanReleaseDTO> list) {
        List<ShortageData> dataList = shortageDataConvert.dtos2entities(list);

        List<ShortageDetail> entities = new ArrayList<>();
        list.forEach(item -> {
            ShortageDetail shortageDetail = new ShortageDetail();
            shortageDetail.setId(item.getDetailId());
            shortageDetail.setDemandDate(item.getDemandDate());
            entities.add(shortageDetail);
        });

//        dataList.forEach(a -> a.setStatus(FlagConst.N.getCode()));
//        final Long id = dataList.get(0).getId();
//        final ShortageData byId = shortageDataService.getById(id);
//        final Long planId = byId.getPlanId();
//        shortagePlanService.update(new LambdaUpdateWrapper<ShortagePlan>()
//                .set(ShortagePlan::getStatus, ShortagePlanStatus.RELEASE.getCode())
//                .eq(ShortagePlan::getId, planId));
        shortageDetailService.updateBatchById(entities);
        shortageDataService.updateBatchById(dataList);
    }

    /**
     * 发布页面，点击发布按钮事件，保存发布明细数据
     * @param list
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void published(List<ShortagePlanReleaseDTO> list, Integer deployToSupplier) {
        if(CollUtil.isEmpty(list)) {
            throw new DaoException("没有要发布的数据!");
        }
        String go_published = stringRedisTemplate.opsForValue().get("published_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在发布中，请勿重复操作！");
        }
        stringRedisTemplate.opsForValue().set("published_" + LoginUtil.getUserId(), "Y", 2, TimeUnit.HOURS);
        List<ShortageData> dataList = new ArrayList<ShortageData>(list.size());
        for (ShortagePlanReleaseDTO shortagePlanReleaseDTO : list) {
            ShortageData shortageData = new ShortageData();
            shortageData.setId(shortagePlanReleaseDTO.getId());
            shortageData.setStatus(FlagConst.N.getCode());
            //增加是否发布供应商字段，发布后，更新字段值为是 邓京术 2025-03-12
            if (null == deployToSupplier || deployToSupplier == 2) {
                shortageData.setDeployToSupplier(2);
            } else {
                shortageData.setDeployToSupplier(1);
            }
            dataList.add(shortageData);
        }
        final Long id = dataList.get(0).getId();
        final ShortageData byId = shortageDataService.getById(id);
        final Long planId = byId.getPlanId();
        shortagePlanService.update(new LambdaUpdateWrapper<ShortagePlan>()
                .set(ShortagePlan::getStatus, ShortagePlanStatus.RELEASE.getCode())
                .eq(ShortagePlan::getId, planId));
        shortageDataService.updateBatchById(dataList);
        stringRedisTemplate.opsForValue().set("published_" + LoginUtil.getUserId(), "N", 2, TimeUnit.HOURS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveReply(List<ShortagePlanReplyDTO> list) {
        Long userId = LoginUtil.getUserId();
        //数据格式校验
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (ShortagePlanReplyDTO shortagePlanReplyDTO : list) {
            i ++;
            //分批交货交期回复校验 yyyy-MM-dd*数量;yyyy-MM-dd*数量
            sb.append(DataCheckUtils.checkIsDateTwo(shortagePlanReplyDTO.getMainMaterialReply(), i));
        }
        if(CollUtil.isEmpty(list)) {
            throw new DaoException("没有要保存的数据!");
        }
        ShortageData shortageDataTemp = shortageDataService.getById(list.get(0).getId());
        if (shortageDataTemp == null) {
            sb.append("回复版本不是当天的版本,请检查。\n\r");
        } else {
            ShortagePlan shortagePlan = shortagePlanService.getById(shortageDataTemp.getPlanId());
            sb.append(DataCheckUtils.checkIsVersion(shortagePlan.getSerialNumber()));
        }

        //如果数据校验不通过，则抛给前端显示。
        if (sb.toString().length() > 0) {
            throw new DaoException(sb.toString());
        }
        String go_published = stringRedisTemplate.opsForValue().get("saveReply_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在保存中，请勿重复操作！");
        }
        stringRedisTemplate.opsForValue().set("saveReply_" + LoginUtil.getUserId(), "Y", 2,TimeUnit.HOURS);
        //2025-02-18新增保存时增加内容为空判断
//        List<ShortagePlanReplyDTO> shortagePlanReplyDTOList = list.stream()
//                .filter(data -> data.getMainMaterialReplyDate() != null ||
//                        data.getMainMaterialReply() != null && !data.getMainMaterialReply().isEmpty() ||
//                        data.getRemark() != null && !data.getRemark().isEmpty())
//                .collect(Collectors.toList());
//        List<ShortagePlanReplyDTO> shortagePlanReplyDTOList = list.stream()
//                .filter(data -> data.getMainMaterialReplyDate() != null ||
//                                StringUtils.isNotEmpty(data.getMainMaterialReply()) ||
//                                StringUtils.isNotEmpty(data.getRemark())
////                        || null != data.getMainMaterialReplyQuantity()
//                                || null != data.getSuccessorMaterialReplyQuantity() || null != data.getSuccessorMaterialDeliveryDateReply()
//                                || null != data.getSubstituteMaterial1ReplyQuantity() || null != data.getSubstituteMaterial1DeliveryDate()
//                                || null != data.getSubstituteMaterial2ReplyQuantity() || null != data.getSubstituteMaterial2DeliveryDate()
//                                || null != data.getSubstituteMaterial3ReplyQuantity() || null != data.getSubstituteMaterial3DeliveryDate()
//                )
//                .collect(Collectors.toList());
        //保存时，所有的数据都要覆盖, 陈敏提出的问题， 2025-03-26 邓京术
        if(CollUtil.isNotEmpty(list)) {
            List<ShortageData> dataList = shortageDataConvert.dtos2entities1(list);
            for (ShortageData shortageData : dataList) {
                shortageDataService.update(shortageData, new UpdateWrapper<ShortageData>().lambda().set(
                                ShortageData::getMainMaterialReplyDate, shortageData.getMainMaterialReplyDate() == null ? null : shortageData.getMainMaterialReplyDate())
                        .set(ShortageData::getMainMaterialReply, shortageData.getMainMaterialReply() == null ? null : shortageData.getMainMaterialReply())
                        .set(ShortageData::getRemark, shortageData.getRemark() == null ? null : shortageData.getRemark())
                        .set(ShortageData::getSuccessorMaterialReplyQuantity, shortageData.getSuccessorMaterialReplyQuantity() == null ? null : shortageData.getSuccessorMaterialReplyQuantity())
                        .set(ShortageData::getSuccessorMaterialDeliveryDateReply, shortageData.getSuccessorMaterialDeliveryDateReply() == null ? null : shortageData.getSuccessorMaterialDeliveryDateReply())
                        .set(ShortageData::getSubstituteMaterial1ReplyQuantity, shortageData.getSubstituteMaterial1ReplyQuantity() == null ? null : shortageData.getSubstituteMaterial1ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial1DeliveryDate, shortageData.getSubstituteMaterial1DeliveryDate() == null ? null : shortageData.getSubstituteMaterial1DeliveryDate())
                        .set(ShortageData::getSubstituteMaterial2ReplyQuantity, shortageData.getSubstituteMaterial2ReplyQuantity() == null ? null : shortageData.getSubstituteMaterial2ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial2DeliveryDate, shortageData.getSubstituteMaterial2DeliveryDate() == null ? null : shortageData.getSubstituteMaterial2DeliveryDate())
                        .set(ShortageData::getSubstituteMaterial3ReplyQuantity, shortageData.getSubstituteMaterial3ReplyQuantity() == null ? null : shortageData.getSubstituteMaterial3ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial3DeliveryDate, shortageData.getSubstituteMaterial3DeliveryDate() == null ? null : shortageData.getSubstituteMaterial3DeliveryDate())
                        .set(ShortageData::getCreateUser, userId)
                        .set(ShortageData::getUpdateTime, LocalDateTime.now())
                        .eq(ShortageData::getId, shortageData.getId())
                );
//            dataList.forEach(a -> {a.setCreateUser(userId);a.setUpdateTime(LocalDateTime.now()); });
//                shortageDataService.updateBatchById(dataList);
            }
        }
        stringRedisTemplate.opsForValue().set("saveReply_" + LoginUtil.getUserId(), "N", 30,TimeUnit.SECONDS);
    }

    @Override
    @Transactional
    public void confirmReply(BasicForeignQuotaQuery query) {
        Long userId = LoginUtil.getUserId();
        hanlderQuery(query);
        List<ShortagePlanReplyPO> replyPOS = shortageDataService.getSupplierReply(null,query);
        final List<ShortagePlanReplyDTO> shortagePlanReplyDTOS = shortageDataConvert.pos2Dtos(replyPOS);
        List<ShortageData> dataList = shortageDataConvert.dtos2entities1(shortagePlanReplyDTOS);
        if (dataList.size() > sysProp.getExportMaxCount()) {
            throw new DaoException(StrUtil.format("回复数据超过{}条", sysProp.getExportMaxCount()));
        }
        String go_published = stringRedisTemplate.opsForValue().get("confirmReply_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在提交中，请勿重复操作！");
        }
        stringRedisTemplate.opsForValue().set("confirmReply_" + LoginUtil.getUserId(), "Y", 30,TimeUnit.SECONDS);
       // 提交时，排除“主料回复日期” mainMaterialReplyDate 、“分批交货交期回复”mainMaterialReply、“备注” remark 都是空时，不提交SAP。不提交的数据状态不更新
        // 推送SAP时，黄色栏位（11个栏位）都为空时不推送SAP，不更新状态； 2025-03-12 邓京术
        // 使用 Stream API 筛选数据
        List<ShortageData> filteredDataList = dataList.stream()
                .filter(data -> data.getMainMaterialReplyDate() != null ||
                        StringUtils.isNotEmpty(data.getMainMaterialReply()) ||
                        StringUtils.isNotEmpty(data.getRemark())
//                        || null != data.getMainMaterialReplyQuantity()
                        || null != data.getSuccessorMaterialReplyQuantity() || null != data.getSuccessorMaterialDeliveryDateReply()
                        || null != data.getSubstituteMaterial1ReplyQuantity() || null != data.getSubstituteMaterial1DeliveryDate()
                        || null != data.getSubstituteMaterial2ReplyQuantity() || null != data.getSubstituteMaterial2DeliveryDate()
                        || null != data.getSubstituteMaterial3ReplyQuantity() || null != data.getSubstituteMaterial3DeliveryDate()
                )
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(filteredDataList)){
//            filteredDataList.forEach(a -> {a.setStatus(FlagConst.Y.getCode());a.setCreateUser(userId);a.setUpdateTime(LocalDateTime.now());});
            for (ShortageData shortageData : filteredDataList) {
                shortageDataService.update(shortageData, new UpdateWrapper<ShortageData>().lambda().set(
                                ShortageData::getMainMaterialReplyDate,shortageData.getMainMaterialReplyDate()==null?null:shortageData.getMainMaterialReplyDate())
                        .set(ShortageData::getMainMaterialReply,shortageData.getMainMaterialReply()==null?null:shortageData.getMainMaterialReply())
                        .set(ShortageData::getRemark,shortageData.getRemark()==null?null:shortageData.getRemark())
                        .set(ShortageData::getSuccessorMaterialReplyQuantity,shortageData.getSuccessorMaterialReplyQuantity()==null?null:shortageData.getSuccessorMaterialReplyQuantity())
                        .set(ShortageData::getSuccessorMaterialDeliveryDateReply,shortageData.getSuccessorMaterialDeliveryDateReply()==null?null:shortageData.getSuccessorMaterialDeliveryDateReply())
                        .set(ShortageData::getSubstituteMaterial1ReplyQuantity,shortageData.getSubstituteMaterial1ReplyQuantity()==null?null:shortageData.getSubstituteMaterial1ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial1DeliveryDate,shortageData.getSubstituteMaterial1DeliveryDate()==null?null:shortageData.getSubstituteMaterial1DeliveryDate())
                        .set(ShortageData::getSubstituteMaterial2ReplyQuantity,shortageData.getSubstituteMaterial2ReplyQuantity()==null?null:shortageData.getSubstituteMaterial2ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial2DeliveryDate,shortageData.getSubstituteMaterial2DeliveryDate()==null?null:shortageData.getSubstituteMaterial2DeliveryDate())
                        .set(ShortageData::getSubstituteMaterial3ReplyQuantity,shortageData.getSubstituteMaterial3ReplyQuantity()==null?null:shortageData.getSubstituteMaterial3ReplyQuantity())
                        .set(ShortageData::getSubstituteMaterial3DeliveryDate,shortageData.getSubstituteMaterial3DeliveryDate()==null?null:shortageData.getSubstituteMaterial3DeliveryDate())
                        .set(ShortageData::getStatus,FlagConst.Y.getCode())
                        .set(ShortageData::getCreateUser,userId)
                        .set(ShortageData::getUpdateTime, LocalDateTime.now())
                        .eq(ShortageData::getId, shortageData.getId())
                );
                //用这种方法无法更新为NULL值 ，并且会报错
//                shortageDetailService.updateBatchById(entities);
            }
//            shortageDataService.updateBatchById(filteredDataList);
//        final Set<Long> dataIds = dataList.stream().map(ShortageData::getId).collect(Collectors.toSet());
            pushToSap(filteredDataList);
        }
        stringRedisTemplate.opsForValue().set("confirmReply_" + LoginUtil.getUserId(), "N", 30,TimeUnit.SECONDS);
    }

    //从缓存中取出需要发布给Sap的数据
    @Override
    public void confirmReply() {
        Long userId = LoginUtil.getUserId();
        Object dataobj = redisTemplate.opsForValue().get("import_reply_" + String.valueOf(userId));
        if (null == dataobj) {
            log.info("没有要推送sap的数据");
            return;
        }
        List<ShortagePlanReplyDTO> shortagePlanReplyDTOS = com.alibaba.fastjson2.JSON.parseArray(dataobj.toString(), ShortagePlanReplyDTO.class);
//        List<ShortageData> dataList = shortageDataConvert.dtos2entities1(shortagePlanReplyDTOS);

        final Set<Long> ids = shortagePlanReplyDTOS.stream().map(ShortagePlanReleaseDTO::getId).collect(Collectors.toSet());
        final List<ShortageData> dataList = shortageDataService.listByIds(ids);
//        if (dataList.size() > sysProp.getExportMaxCount()) {
//            throw new DaoException(StrUtil.format("回复数据超过{}条", sysProp.getExportMaxCount()));
//        }
        // 提交时，排除“主料回复日期” mainMaterialReplyDate 、“分批交货交期回复”mainMaterialReply、“备注” remark 都是空时，不提交SAP。不提交的数据状态不更新
        // 推送SAP时，黄色栏位（11个栏位）都为空时不推送SAP，不更新状态； 2025-03-12 邓京术
        // 使用 Stream API 筛选数据
        List<ShortageData> filteredDataList = dataList.stream()
                .filter(data -> data.getMainMaterialReplyDate() != null ||
                                StringUtils.isNotEmpty(data.getMainMaterialReply()) ||
                                StringUtils.isNotEmpty(data.getRemark())
//                        || null != data.getMainMaterialReplyQuantity()
                                || null != data.getSuccessorMaterialReplyQuantity() || null != data.getSuccessorMaterialDeliveryDateReply()
                                || null != data.getSubstituteMaterial1ReplyQuantity() || null != data.getSubstituteMaterial1DeliveryDate()
                                || null != data.getSubstituteMaterial2ReplyQuantity() || null != data.getSubstituteMaterial2DeliveryDate()
                                || null != data.getSubstituteMaterial3ReplyQuantity() || null != data.getSubstituteMaterial3DeliveryDate()
                )
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(filteredDataList)) {
            for (ShortageData shortageData : filteredDataList) {
                shortageDataService.update(shortageData, new UpdateWrapper<ShortageData>().lambda().set(
                        ShortageData::getStatus,FlagConst.Y.getCode())
                        .set(ShortageData::getCreateUser,userId)
                        .set(ShortageData::getUpdateTime, LocalDateTime.now())
                        .eq(ShortageData::getId, shortageData.getId())
                );
            }
            pushToSap(filteredDataList);
        }
    }

    @Override
    public void downloadSapData(Long planId, HttpServletRequest request, HttpServletResponse response) {
        final List<ShortageDetail> shortageDetails = shortageDetailService.list(
                new LambdaQueryWrapper<>(ShortageDetail.class).eq(ShortageDetail::getPlanId, planId));
        List<ShortagePlanImportDTO> importDTOS = shortageDetailConvert.entities2Dtos(shortageDetails);
        // 设置响应头信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = null;
        try {
            fileName = URLEncoder.encode("SAP原始数据", "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        // 使用EasyExcel导出Excel文件
        try {
            EasyExcel.write(response.getOutputStream()).head(ShortagePlanImportDTO.class)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .sheet("Sheet1").doWrite(importDTOS);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据当前生成新的版本号
     *
     * @param now          当前时间
     * @param serialNumber 当前版本号
     * @return 生成的版本号
     */
    @Override
    public String genSerialNumber(DateTime now, String serialNumber) {
        if (StrUtil.isEmpty(serialNumber)) {
            // 本月第一个
            return now.toString("yyyyMM") + CargoPlanConst.serial.list.get(0);
        } else {
            if (serialNumber.length() == 7) {
                // 获取版本号尾号对应的索引
                final String ser = serialNumber.substring(6);
                int indexOf = CargoPlanConst.serial.list.indexOf(ser);

                // 获取本次生成的版本号与历史版本号的月数差值
                final String dateStr = serialNumber.substring(0, 6);

                int nowMonth = DateUtil.month(now.toJdkDate()) + 1;
                int snMonth = DateUtil.month(DateUtil.parse(dateStr, "yyyyMM")) + 1;

                if (indexOf >= 0) {
                    if (indexOf == 55) {
                        throw new DaoException("版本号已到上限");
                    } else {
                        if (nowMonth > snMonth) {
                            return now.toString("yyyyMM") + CargoPlanConst.serial.list.get(0);
                        }
                        return now.toString("yyyyMM") + CargoPlanConst.serial.list.get(indexOf + 1);
                    }
                } else {
                    throw new DaoException("生成版本号出现错误");
                }
            }
        }
        throw new DaoException("生成版本号出现错误");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void fillSupplier(List<ShortagePlanReleaseDTO> result) {
        final Set<Long> ids = result.stream().filter(a -> StrUtil.isNotEmpty(a.getSupplierName()))
                .map(ShortagePlanReleaseDTO::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(ids)) {
            final List<ShortageData> shortageDetails = shortageDataService.listByIds(ids);
            final Map<Long, String> supplierCodes = result.stream()
                    .collect(Collectors.toMap(ShortagePlanReleaseDTO::getId, ShortagePlanReleaseDTO::getSupplierName));
            Set<String> existingCodes = Sets.newHashSet();
            List<ShortageData> update = Lists.newArrayList();
            List<ShortageDetail> shortageDetails2 = Lists.newArrayList();
            for (ShortageData shortageDetail : shortageDetails) {
                if (shortageDetail.getType().equals(ShortageDataType.MANUAL.getCode())) {
                    final String supplierCode = supplierCodes.get(shortageDetail.getId());
                    if (StrUtil.isNotEmpty(supplierCode)) {
                        if (!existingCodes.contains(supplierCode)) {
                            final SupplierDTO supplierByCode = supplierClient.getSupplierByCode(supplierCode);
                            if (Objects.isNull(supplierByCode)) {
                                throw new DaoException(StrUtil.format("供应商编码:{},不存在", supplierCode));
                            }
                            existingCodes.add(supplierCode);
                        }
                        shortageDetail.setSupplierCode(supplierCode);
                        final ShortageData shortageData = new ShortageData();
                        shortageData.setId(shortageDetail.getId());
                        shortageData.setSupplierCode(supplierCode);
                        shortageData.setQuota(BigDecimal.valueOf(100));
                        shortageData.setStatus(null);
                        update.add(shortageData);
                        //更新上线日期
                        ShortageDetail shortageDetail1 = shortageDetailService.getById(shortageDetail.getDetailId());
                        for (ShortagePlanReleaseDTO shortagePlanReleaseDTO : result) {
                            if (shortagePlanReleaseDTO.getId().equals(shortageDetail.getId())) {
                                shortageDetail1.setLaunchDate(shortagePlanReleaseDTO.getLaunchDate());
                                shortageDetail1.setLaunchDateRemark(shortagePlanReleaseDTO.getLaunchDateRemark());
                                shortageDetails2.add(shortageDetail1);
                                break;
                            }
                        }
                    }
                }
            }
            if (CollUtil.isNotEmpty(update)) {
//                shortageDataService.updateBatchById(update, 300);
                for (ShortageData shortageData : update) {
                    shortageDataService.update(shortageData, new UpdateWrapper<ShortageData>().lambda()
                            .set(ShortageData::getStatus, null)
                            .set(ShortageData::getSupplierCode,shortageData.getSupplierCode())
                            .set(ShortageData::getQuota,shortageData.getQuota())
                            .set(ShortageData::getUpdateTime, LocalDateTime.now())
                            .eq(ShortageData::getId, shortageData.getId())
                    );
                }
            }
            if (CollUtil.isNotEmpty(shortageDetails2)) {
                shortageDetailService.updateBatchById(shortageDetails2, 300);
            }
        }
    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void fillLaunchDate(List<ShortagePlanReleaseDTO> result) {
//        final List<Long> ids = result.stream().map(ShortagePlanReleaseDTO::getId).collect(Collectors.toList());
//        if (CollUtil.isNotEmpty(ids)) {
//            final List<ShortageData> shortageDatas = shortageDataService.listByIds(ids);
//            final List<Long> detailIds = shortageDatas.stream().map(ShortageData::getDetailId).collect(Collectors.toList());
//            final List<ShortageDetail> shortageDetails = shortageDetailService.listByIds(detailIds);
//            shortageDatas.stream().forEach(item ->{
//                for (ShortageDetail shortageDetail : shortageDetails) {
//                    boolean findFlag = false;
//                    //更新上线日期
//                    for (ShortagePlanReleaseDTO shortagePlanReleaseDTO : result) {
//                        if (shortagePlanReleaseDTO.getId().equals(item.getId()) && shortageDetail.getId().equals(item.getDetailId())) {
//                            shortageDetail.setLaunchDate(shortagePlanReleaseDTO.getLaunchDate());
//                            shortageDetail.setLaunchDateRemark(shortagePlanReleaseDTO.getLaunchDateRemark());
//                            findFlag = true;
//                            break;
//                        }
//                    }
//                    if (findFlag) {
//                        break;
//                    }
//                }
//            });
//            shortageDetailService.updateBatchById(shortageDetails, 300);
//        }
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importForPublished(List<ShortagePlanReleaseDTO> list) {
        //上传 更新 上线日期， 备注（上线日期）， 供应商 邓京术 2025-03-12
        List<ShortageDetail> entities = new ArrayList<>();
        List<ShortageData> updateLists = new ArrayList<>();
        final Set<Long> ids = list.stream().map(ShortagePlanReleaseDTO::getId).collect(Collectors.toSet());
        final List<ShortageData> shortageData1 = shortageDataService.listByIds(ids);
        final Map<Long, Long> idCache = shortageData1.stream()
                .collect(Collectors.toMap(ShortageData::getId, ShortageData::getDetailId));
        list.forEach(item -> {
            ShortageDetail shortageDetail = new ShortageDetail();
            shortageDetail.setId(idCache.get(item.getId()));
            //取消更新此字段 邓京术 2025-03-12
//            shortageDetail.setDemandDate(item.getDemandDate());
            //上线日期也可以修改 邓京术 2024-07-26
            shortageDetail.setLaunchDate(item.getLaunchDate()==null?null:item.getLaunchDate());
            shortageDetail.setLaunchDateRemark(item.getLaunchDateRemark()==null?"":item.getLaunchDateRemark());
            entities.add(shortageDetail);
            ShortageData shortageData = new ShortageData();
            shortageData.setSupplierCode(item.getSupplierCode());
            //取消更新此字段 邓京术 2025-03-12
//            shortageData.setShortageQuantity(item.getShortageQuantity());
            shortageData.setId(item.getId());
            updateLists.add(shortageData);
        });
        if (CollUtil.isNotEmpty(entities)) {
            for (ShortageDetail shortageDetail : entities) {
                shortageDetailService.update(shortageDetail, new UpdateWrapper<ShortageDetail>().lambda().set(
                        ShortageDetail::getLaunchDate,shortageDetail.getLaunchDate()==null?null:shortageDetail.getLaunchDate())
                        .set(ShortageDetail::getLaunchDateRemark,shortageDetail.getLaunchDateRemark()).eq(ShortageDetail::getId, shortageDetail.getId())
                );
                //用这种方法无法更新为NULL值 ，并且会报错
//                shortageDetailService.updateBatchById(entities);
            }
        }
        //重新上传的发布欠料数据，状态改为未回复状态 邓京术 2025-07-07
        if (CollUtil.isNotEmpty(updateLists)) {
            for (ShortageData shortageData : updateLists) {
                shortageDataService.update(shortageData, new UpdateWrapper<ShortageData>().lambda()
                        .set(ShortageData::getSupplierCode,shortageData.getSupplierCode()==null?null:shortageData.getSupplierCode())
                        .set(ShortageData::getStatus,null)
                        .eq(ShortageData::getId, shortageData.getId())
                );
                //用这种方法无法更新为NULL值 ，并且会报错
//                shortageDetailService.updateBatchById(entities);
            }
//            shortageDataService.updateBatchById(updateLists);
        }
    }

}
