package com.jwipc.order.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
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.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.jwipc.aggregation.ModelAggregationService;
import com.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.ESignFileResposeDTO;
import com.jwipc.api.dto.SapResposeBody;
import com.jwipc.constant.DelFlag;
import com.jwipc.constant.DictCode;
import com.jwipc.constant.FlagConst;
import com.jwipc.db.DbUtil;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.logic.IPaymentApiService;
import com.jwipc.finance.model.po.CreatePaaDetailPO;
import com.jwipc.finance.model.query.PaymentApplyItemQuery;
import com.jwipc.finance.service.IPaymentCodApplyDetailService;
import com.jwipc.order.constant.OrderAttachmentType;
import com.jwipc.order.constant.PoSapClient;
import com.jwipc.order.constant.PurchaseOrderStatus;
import com.jwipc.order.constant.SequenceConst;
import com.jwipc.order.convert.OrderAttachmentConvert;
import com.jwipc.order.convert.PurchaseOrderConvert;
import com.jwipc.order.convert.PurchaseOrderDetailConvert;
import com.jwipc.order.convert.PurchaseOrderDevPlanConvert;
import com.jwipc.order.dto.*;
import com.jwipc.order.entity.*;
import com.jwipc.order.logic.PurchaseOrderLogic;
import com.jwipc.order.model.po.OrderAttachmentPO;
import com.jwipc.order.model.po.PurchaseOrderPO;
import com.jwipc.order.model.query.OrderBatchPrintQuery;
import com.jwipc.order.model.query.PurchaseOrderQuery;
import com.jwipc.order.service.*;
import com.jwipc.order.util.PrintOrderCreatePdfUtil;
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.SupplierContactsDTO;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.clent.dto.SupplierPurchaseCategoryDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.*;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.ProductInfoDTO;
import com.jwipc.sys.client.dto.UserDTO;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.entity.StatementPaymentSetting;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.sys.service.IBusinessAttachmentService;
import com.jwipc.sys.service.IStatementPaymentSettingService;
import com.jwipc.util.DateUtils;
import com.jwipc.util.PDFUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;
import static com.jwipc.util.DateUtils.yyyyMMdd;

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


    private final IPurchaseOrderService purchaseOrderService;
    private final PurchaseOrderConvert purchaseOrderConvert;
    private final IOrderAttachmentService orderAttachmentService;
    private final OrderAttachmentConvert orderAttachmentConvert;
    private final ModelAggregationService modelAggregationService;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final PurchaseOrderDetailConvert purchaseOrderDetailConvert;
    private final DictClient dictClient;
    private final UserClient userClient;
    private final PoSapClient sapClient;
    private final FileLogic fileLogic;
    private final ProductClient productClient;
    private final PurchaseOrderDevPlanConvert purchaseOrderDevPlanConvert;
    private final IPurchaseOrderDevPlanService purchaseOrderDevPlanService;
    private final SupplierClient supplierClient;
    private final SequenceClient sequenceClient;
    private final IPurchaseOrderSummaryService purchaseOrderSummaryService;
    private final UserPurchaseGroupClient userPurchaseGroupClient;
    private final SysProp sysProp;
    private final Configuration freemarkerConfig;
    private final FileClient fileClient;
    private final IPurchaseOrderModifyService purchaseOrderModifyService;
    private final ESignClient eSignClient;
    private final IStatementPaymentSettingService statementPaymentSettingService;
    private final IPaymentApiService paymentCodApplyDetailService;
    private final StringRedisTemplate stringRedisTemplate;
    private final IStatementPaymentSettingService iStatementPaymentSettingService;

    private final IOrderPrintPersonService iOrderPrintPersonService;
    private final IPurchaseOrderModifyService iPurchaseOrderModifyService;
    private final IBusinessAttachmentService businessAttachmentService;


    @Override
    @DS(SLAVE)
    public PageView getList(PurchaseOrderQuery query) {
        Page<PurchaseOrderPO> page = PageUtil.toPage(query);
        final List<PurchaseOrderPO> list = getPurchaseOrders(query, page);
        List<PurchaseOrderListDTO> listDTOS = purchaseOrderConvert.Po2Dtos(list);
        if (CollUtil.isNotEmpty(listDTOS)) {
            final Set<Long> ids = listDTOS.stream().map(dto -> dto.getId()).collect(Collectors.toSet());
            final List<OrderAttachment> orderAttachments = orderAttachmentService.list(
                    new LambdaQueryWrapper<OrderAttachment>().in(OrderAttachment::getMasterId, ids)
                            .eq(OrderAttachment::getType, OrderAttachmentType.PURCHASE_ORDER_ATTACHMENT.getType()));
            Map<Long, Integer> countMap = orderAttachments.stream()
                    .collect(Collectors.groupingBy(OrderAttachment::getMasterId, Collectors.summingInt(e -> 1)));

            final List<BusinessAttachment> businessAttachmentList = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>()
                    .in(BusinessAttachment::getBusinessId, ids).eq(BusinessAttachment::getBusinessTypeCode, "purchase_order"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (PurchaseOrderListDTO listDTO : listDTOS) {
                if (Objects.nonNull(countMap.get(listDTO.getId()))) {
                    listDTO.setFileSize(countMap.get(listDTO.getId()));
                }
                final Long id = listDTO.getId();
                if (Objects.nonNull(businessAttachmentMap.get(id))) {
                    listDTO.setAttachmentFiles("1");
                }
            }

        }
        modelAggregationService.processRelationAggregation(listDTOS);
        return PageUtil.getPV(listDTOS, page.getTotal());
    }

    private List<PurchaseOrderPO> getPurchaseOrders(PurchaseOrderQuery query, Page<PurchaseOrderPO> page) {
        final LambdaQueryWrapper<PurchaseOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.apply(StrUtil.isNotEmpty(query.getOrderCode()), " order_code REGEXP {0}",
                DbUtil.toRegexp(query.getOrderCode()));
        if (LoginUtil.isSupplier()) {
            queryWrapper.apply("(tpo.supplier_erp_code = {0} OR tpo.supplier_code1={0})", LoginUtil.getSupplierCode());
            queryWrapper.eq(PurchaseOrder::getSupplierVisible, FlagConst.Y.getCode());
        }
        if (StrUtil.isNotEmpty(query.getMaterialCode())) {
            queryWrapper.apply(
                    "tpo.id IN (SELECT dod.order_id FROM t_purchase_order_detail dod WHERE (dod.material_code REGEXP " +
                            "{0} " +
                            "OR" + " " + "dod.material_name REGEXP {0}))", DbUtil.toRegexp(query.getMaterialCode()));
        }
        queryWrapper.exists(
                "select 1 from t_purchase_order_detail a where a.order_id=tpo.id and a.del_flag =0");
        queryWrapper.in(StrUtil.isNotEmpty(query.getState()), PurchaseOrder::getState, query.getStateList());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getCreateName()), PurchaseOrder::getCreateName, query.getCreateName());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getFinConf()), PurchaseOrder::getFinConf, query.getFinConf());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getMarkFlag()), PurchaseOrder::getMarkFlag, query.getMarkFlag());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getFactory()), PurchaseOrder::getFactoryCode, query.getFactory());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getPurchaseGroupCode()), PurchaseOrder::getPurchaseGroupCode,
                query.getPurchaseGroupCode());
//        queryWrapper.apply(StrUtil.isNotEmpty(query.getSupplierErpCode()), " supplier_erp_code REGEXP {0}",
//                DbUtil.toRegexp(query.getSupplierErpCode()));
        //供应商编码查询改为精确查询 2024-08-16 邓京术， 采购与财务的需求  导出也是一样
        queryWrapper.eq(StrUtil.isNotEmpty(query.getSupplierErpCode()), PurchaseOrder::getSupplierErpCode, query.getSupplierErpCode());
        queryWrapper.eq(StrUtil.isNotEmpty(query.getOrderTypeCode()), PurchaseOrder::getOrderTypeCode,
                query.getOrderTypeCode());
        queryWrapper.apply(StrUtil.isNotEmpty(query.getCompanyName()), " company_name REGEXP {0}",
                DbUtil.toRegexp(query.getCompanyName()));
        queryWrapper.apply(StrUtil.isNotEmpty(query.getFinUserName()), " su.username REGEXP {0}",
                DbUtil.toRegexp(query.getFinUserName()));

        queryWrapper.apply(StrUtil.isNotEmpty(query.getStartCreateDate()), " tpo.create_time>= {0}",
                query.getStartCreateDate());
        queryWrapper.apply(StrUtil.isNotEmpty(query.getEndCreateDate()), " tpo.create_time<= {0}",
                query.getEndCreateDate());
        if (StrUtil.isNotEmpty(query.getBatchNo())) {
            queryWrapper.exists(
                    "select 1 from t_purchase_order_summary a where a.order_id=tpo.id and a.code =" +
                            " {0}", query.getBatchNo());
        }
        queryWrapper.eq(StrUtil.isNotEmpty(query.getOrderTypeCode()), PurchaseOrder::getOrderTypeCode,
                query.getOrderTypeCode());
        //如果签署状态不为空 2024-08-26 邓京术 -1查空的。 传null查所有的
        if (null != query.getSignStatus() && -1 == query.getSignStatus() ) {
            queryWrapper.notExists(" SELECT 1 " +
                    "        FROM basis_digital_seal_business_detail AS sub" +
                    "        WHERE sub.business_id = tpo.id" +
                    "        AND sub.business_type_code = 'purchase_order' and sign_status is not null ");
        } else if (null != query.getSignStatus() && query.getSignStatus().equals(2)) {
            queryWrapper.apply(true, " bdsbd.sign_status = {0}" , query.getSignStatus());
            queryWrapper.exists(" SELECT 1 " +
                    "        FROM basis_digital_seal_business_detail AS sub" +
                    "        WHERE sub.business_id = tpo.id" +
                    "        AND sub.business_type_code = 'purchase_order' and sign_status = {0} ",  query.getSignStatus());
        //1 签署中 2 完成
        } else if (null != query.getSignStatus() && query.getSignStatus().equals(1)) {
            queryWrapper.apply(true, " bdsbd.sign_status = {0}" , query.getSignStatus());
            queryWrapper.exists(" SELECT 1" +
                    "            FROM basis_digital_seal_business_detail AS sub" +
                    "            WHERE sub.business_id = tpo.id" +
                    "            AND sub.sign_status = 1" +
                    "            AND sub.business_type_code = 'purchase_order' ");

        }
        if (null != query.getFileState()) {
            queryWrapper.apply(true, "  tpo.file_state = {0}" , query.getFileState());
        }

        if (!LoginUtil.isSupplier()) {
            final Set<String> userPurchaseGroupCode = userPurchaseGroupClient.getUserPurchaseGroupCode(
                    LoginUtil.getUserId());
            //增加用户采购组权限
            queryWrapper.in(true, PurchaseOrder::getPurchaseGroupCode, userPurchaseGroupCode);
        }
//        if (StrUtil.isNotEmpty(query.getSort())) {
//            queryWrapper.orderBy(query.getSort().equals("supplierErpCode"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getSupplierErpCode);
//            queryWrapper.orderBy(query.getSort().equals("supplierName"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getSupplierName);
//            queryWrapper.orderBy(query.getSort().equals("companyName"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getCompanyCode);
//            queryWrapper.orderBy(query.getSort().equals("finConf"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getFinConf);
//            queryWrapper.orderBy(query.getSort().equals("state"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getState);
//            queryWrapper.orderBy(query.getSort().equals("fileState"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getFileState);
//            queryWrapper.orderBy(query.getSort().equals("orderDate"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getOrderDate);
//            queryWrapper.orderBy(query.getSort().equals("batchNo"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getBatchNo);
//            queryWrapper.orderBy(query.getSort().equals("orderTypeName"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getOrderTypeCode);
//            queryWrapper.orderBy(query.getSort().equals("remark"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getRemark);
//            queryWrapper.orderBy(query.getSort().equals("orderCode"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getOrderCode);
//            queryWrapper.orderBy(query.getSort().equals("confirmTime"), query.getOrder().equals("asc"),
//                    PurchaseOrder::getConfirmTime);
//        } else {
//            queryWrapper.orderByDesc(true, PurchaseOrder::getOrderDate);
//        }
        final List<PurchaseOrderPO> list;
        if (Objects.nonNull(page)) {
            list = purchaseOrderService.findByPage(page, queryWrapper, query);
        } else {
            list = purchaseOrderService.findAll(queryWrapper, query);
        }
        final Set<String> orderCodes = list.stream().map(PurchaseOrderPO::getOrderCode).collect(Collectors.toSet());
        Map<String, String> rowTypeCodeCache = Maps.newHashMap();
        if (CollUtil.isNotEmpty(orderCodes)) {
            final List<PurchaseOrderDetail> purchaseOrderDetails = purchaseOrderDetailService.list(
                    new QueryWrapper<>(PurchaseOrderDetail.class).select("DISTINCT order_code, row_type_code")
                            .in("order_code",
                                    orderCodes));
            if (CollUtil.isNotEmpty(purchaseOrderDetails)) {
                rowTypeCodeCache = purchaseOrderDetails.stream().collect(
                        Collectors.toMap(PurchaseOrderDetail::getOrderCode, PurchaseOrderDetail::getRowTypeCode,(oldValue,newValue)->newValue));

            }
        }

        if (StrUtil.isNotEmpty(query.getBatchNo())) {
            for (PurchaseOrderPO purchaseOrder : list) {
                purchaseOrder.setBatchNo(query.getBatchNo());
            }
        }
        for (PurchaseOrderPO purchaseOrderPO : list) {
            final String rowTypeCode = rowTypeCodeCache.get(purchaseOrderPO.getOrderCode());
            if (StrUtil.isNotEmpty(rowTypeCode)) {
                purchaseOrderPO.setRowTypeCode(rowTypeCode);
            }
        }
        return list;
    }

    @Override
    public PurchaseOrderBaseDTO getDetail(Long id) {
        final PurchaseOrder purchaseOrder = purchaseOrderService.getById(id);
        if (Objects.isNull(purchaseOrder)) {
            throw new DaoException("采购订单不存在");
        }

        return purchaseOrderConvert.entity2Dto(purchaseOrder);
    }

    @Override
    public PageView getAttachmentList(String ids) {
        final Set<String> idSet = StrUtil.split(ids, StrUtil.COMMA).stream().collect(Collectors.toSet());
        final List<OrderAttachmentDTO> list = getOrderAttachments(idSet);
//        List<OrderAttachmentDTO> attachmentDTOS = orderAttachmentConvert.entities2Dtos(list);
        modelAggregationService.processRelationAggregation(list);
        return PageUtil.getPV(list, list.size());
    }

    private List<OrderAttachmentDTO> getOrderAttachments(Set<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
//        final LambdaQueryWrapper<OrderAttachment> queryWrapper = new LambdaQueryWrapper<OrderAttachment>().in(
//                        OrderAttachment::getMasterId, ids)
//                .eq(OrderAttachment::getType, OrderAttachmentType.PURCHASE_ORDER_ATTACHMENT.getType());
         final List<OrderAttachmentPO> list = orderAttachmentService.findPageByIds(ids);
          List<OrderAttachmentDTO> attachmentDTOS = orderAttachmentConvert.po2Dtos(list);
        return attachmentDTOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAttachment(List<OrderAttachmentDTO> files) {
        List<OrderAttachment> list = orderAttachmentConvert.dtos2Entities(files);
        list.forEach(a -> {
            a.setCreateTime(LocalDateTime.now());
            a.setCreateUser(LoginUtil.getUserId());
            a.setType(OrderAttachmentType.PURCHASE_ORDER_ATTACHMENT.getType());
        });
        //如果是上传需要把订单中的附件状态修改成已上传
        final OrderAttachment orderAttachment = list.get(0);
        final PurchaseOrder purchaseOrder = purchaseOrderService.getById(orderAttachment.getMasterId());
        if (Objects.isNull(purchaseOrder)) {
            throw new DaoException("采购订单不存在");
        }
        if(StringUtils.isNotEmpty(purchaseOrder.getBatchNo())){
            List<PurchaseOrder> purchaseOrderList = purchaseOrderService.list(new LambdaQueryWrapper<>(PurchaseOrder.class).eq(PurchaseOrder::getBatchNo, purchaseOrder.getBatchNo()));
            if(CollUtil.isNotEmpty(purchaseOrderList)){
                Set<Long> collectId = purchaseOrderList.stream().map(PurchaseOrder::getId).collect(Collectors.toSet());
               //添加订单附件
                Set<Long> collectIdNew = new HashSet<>();
                collectIdNew.addAll(collectId);
                List<OrderAttachment> newOrderAttachmentList = new ArrayList<>();
                if(list.size()>1){
                    for (OrderAttachment attachment : list) {
                            OrderAttachment newOrderAttachment = new OrderAttachment();
                            BeanUtils.copyProperties(attachment,newOrderAttachment);
                            newOrderAttachment.setMasterId(attachment.getMasterId());
                            newOrderAttachment.setId(null);
                            newOrderAttachmentList.add(newOrderAttachment);
                    }
                }else{
                    for (OrderAttachment attachment : list) {
                        for (Long id : collectIdNew) {
                            OrderAttachment newOrderAttachment = new OrderAttachment();
                            BeanUtils.copyProperties(attachment,newOrderAttachment);
                            newOrderAttachment.setMasterId(id);
                            newOrderAttachment.setId(null);
                            newOrderAttachmentList.add(newOrderAttachment);
                        }
                    }
                }

                if(CollUtil.isNotEmpty(newOrderAttachmentList)){
                    orderAttachmentService.saveBatch(newOrderAttachmentList);
                }
                purchaseOrderService.update(
                        new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getFileState, FlagConst.Y.getCode())
                                .set(PurchaseOrder::getFinConf,FlagConst.N.getCode())
                                .in(PurchaseOrder::getId, collectId)
                                .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                );
            }
        }else{
            orderAttachmentService.saveBatch(list);

            final Set<Long> orderIds = list.stream().map(OrderAttachment::getMasterId).collect(Collectors.toSet());
            if (CollUtil.isNotEmpty(orderIds)) {
                purchaseOrderService.update(
                        new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getFileState, FlagConst.Y.getCode())
                                //2024-08-18 新增逻辑，重新上传回签附件，需要把财务确认状态改为为确认，财务确认人修改为空，确认时间修改为空
                                .set(PurchaseOrder::getFinConf,FlagConst.N.getCode())
                                .in(PurchaseOrder::getId, orderIds)
                                .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                );
            }

        }
    }

    @Override
    public void removeAttachment(String ids, String remark) {
        final List<String> split = StrUtil.split(ids, StrUtil.COMMA);
        if (CollUtil.isEmpty(split)) {
            return;
        }

        //2024-08-16 电子双签没有附件回签，电子单签有附件回传，删除时要更新财务确认状态为未确认，回签状态改为否
        OrderAttachment orderAttachmentbyId = orderAttachmentService.getById(split.get(0));
        if(orderAttachmentbyId != null){
          if(Objects.nonNull(orderAttachmentbyId.getFileId())){
              final LambdaUpdateWrapper<OrderAttachment> updateWrapper =
                      new LambdaUpdateWrapper<OrderAttachment>()
                              .eq(OrderAttachment::getFileId,orderAttachmentbyId.getFileId())
                              .set(StrUtil.isNotEmpty(remark), OrderAttachment::getRemark, remark)
                              .set(OrderAttachment::getDeleteUser, LoginUtil.getUserId())
                              .set(OrderAttachment::getDeleteTime, LocalDateTime.now())
                              .set(OrderAttachment::getDeleteFlag, DelFlag.DELETE.getStatus());
              orderAttachmentService.update(updateWrapper);
          }
          if(orderAttachmentbyId != null && Objects.nonNull(orderAttachmentbyId.getFileId())){
              List<OrderAttachment> attachmentList = orderAttachmentService.list(new LambdaQueryWrapper<OrderAttachment>().eq(OrderAttachment::getFileId,orderAttachmentbyId.getFileId()));
              if(CollUtil.isNotEmpty(attachmentList)){
                  //2024-08-18 判断该批次附件文件是否都为删除状态
                  List<Long> orderIdList = attachmentList.stream().map(OrderAttachment::getMasterId).collect(Collectors.toList());
                  //通过订单号ID查询它关联的附件是否都被删除
                  List<OrderAttachment> attachmentLists = orderAttachmentService.list(new LambdaQueryWrapper<OrderAttachment>().in(OrderAttachment::getMasterId, orderIdList));
                  if(CollUtil.isNotEmpty(attachmentLists)){
                      boolean allDeleted = attachmentLists.stream()
                              .allMatch(entity -> entity.getDeleteFlag() ==  DelFlag.DELETE.getStatus());
                      if(allDeleted){
                          purchaseOrderService.update(new LambdaUpdateWrapper<PurchaseOrder>()
                                  .in(PurchaseOrder::getId, orderIdList)
                                  .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                                  .set(PurchaseOrder::getFinConf, FlagConst.N.getCode())
                                  .set(PurchaseOrder::getFileState, FlagConst.N.getCode())
                          );
                      }
                  }
              }
          }

        }
       /* final LambdaUpdateWrapper<OrderAttachment> updateWrapper =
                new LambdaUpdateWrapper<OrderAttachment>()
                        .in(OrderAttachment::getId, split)
                        .set(StrUtil.isNotEmpty(remark), OrderAttachment::getRemark, remark)
                        .set(OrderAttachment::getDeleteFlag, DelFlag.DELETE.getStatus());
        orderAttachmentService.update(updateWrapper);*/
    }

    @Override
    public void sumbitReply(List<PurchaseOrderDetailReplyDTO> replyDTOList) {
        if (replyDTOList.size() <= 0) {
            throw new DaoException("回复行数据不存在");
        }
        final Long orderId = replyDTOList.get(0).getOrderId();
        final PurchaseOrder purchaseOrder = purchaseOrderService.getById(orderId);
//        if (Objects.isNull(purchaseOrder.getFileState()) ||
//                !purchaseOrder.getFileState().equals(FlagConst.Y.getCode())) {
//            throw new DaoException("请先上传订单盖章附件，才能确认订单");
//        }
        if (purchaseOrder.getState() != PurchaseOrderStatus.AWAITING_SUPPLIER_CONFIRMATION.getStatus()) {
            throw new DaoException("不是待供应商确认状态，无法进行订单确认操作");
        }
        List<PurchaseOrderDetail> updateLists = Lists.newArrayList();
        final Set<Long> ids = replyDTOList.stream().map(reply -> reply.getId()).collect(Collectors.toSet());
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        for (PurchaseOrderDetailReplyDTO detail : replyDTOList) {
            PurchaseOrderDetail updateBean = new PurchaseOrderDetail();
            updateBean.setId(detail.getId());
            //回复数量
            if (detail.getReplayNum() != null) {
                updateBean.setReplayNum(detail.getReplayNum());
            }
            // 回复交期
            if (Objects.nonNull(detail.getReplayRequireDate())) {
                updateBean.setReplayRequireDate(detail.getReplayRequireDate());
            }
            // 回复内容
            updateBean.setReplayRemark(detail.getReplayRemark());
            //需要判断是否告警，
            //1 日期在比计划日期之后
            updateBean.setWarningFlag(FlagConst.N.getCode());
            if (Objects.nonNull(detail.getReplayRequireDate()) &&
                    Objects.nonNull(detail.getRequireDate()) &&
                    detail.getRequireDate().isBefore(detail.getReplayRequireDate())) {
                updateBean.setWarningFlag(FlagConst.Y.getCode());
            }
            updateBean.setState(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus());
            updateLists.add(updateBean);
        }
        if (CollUtil.isNotEmpty(updateLists)) {
            purchaseOrderDetailService.updateBatchById(updateLists);
        }
        //需要把订单头状态改成确认完成   增加供应商确认时间 2024-08-21号 邓京术  getConfirmTime
        purchaseOrderService.update(new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getState,
                        PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus()).set(PurchaseOrder::getConfirmTime, LocalDateTime.now())
                .eq(PurchaseOrder::getId, purchaseOrder.getId()));
    }

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

    @Override
    public void updateFinConf(String ids, Integer confirmFlag,Integer attachmentType) {
        final List<String> split = StrUtil.split(ids, StrUtil.COMMA);
        if (CollUtil.isNotEmpty(split)) {
            PurchaseOrder purchaseOrder = purchaseOrderService.getById(split.get(0));
            if(StringUtils.isNotEmpty(purchaseOrder.getBatchNo())){
                LambdaUpdateWrapper<PurchaseOrder> wrapper = new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getFinConf, confirmFlag)
                        .set(PurchaseOrder::getFinUserId, LoginUtil.getUserId())
                        .set(PurchaseOrder::getFinTime, LocalDateTime.now())
                        .set(PurchaseOrder :: getFileState,FlagConst.Y.getCode())
                        .eq(PurchaseOrder::getBatchNo, purchaseOrder.getBatchNo());
                if(!Objects.isNull(attachmentType)){//进行确认
                    wrapper.set(PurchaseOrder::getAttachmentType, attachmentType);
                    if(confirmFlag == 1 && attachmentType == 0){
                        wrapper.set(PurchaseOrder :: getFileState,FlagConst.Y.getCode());
                    }
                }else{//取消确认
                    if(confirmFlag == 0 && !Objects.isNull(purchaseOrder.getAttachmentType())){
                        if(purchaseOrder.getAttachmentType() == 0){
                            wrapper.set(PurchaseOrder :: getFileState,FlagConst.N.getCode());
                            wrapper.notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"));
                        }
                    }
                }
                purchaseOrderService.update(wrapper);
            }else{
                LambdaUpdateWrapper<PurchaseOrder> updateWrapper = new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getFinConf, confirmFlag)
                        .set(PurchaseOrder::getFinUserId, LoginUtil.getUserId())
                        .set(PurchaseOrder::getFinTime, LocalDateTime.now())
                        .in(PurchaseOrder::getId, split);
                if(!Objects.isNull(attachmentType)){//进行确认
                    updateWrapper.set(PurchaseOrder::getAttachmentType, attachmentType);
                    if(confirmFlag == 1 && attachmentType == 0){
                        updateWrapper.set(PurchaseOrder :: getFileState,FlagConst.Y.getCode());
                    }
                }else{//取消确认
                    if(confirmFlag == 0 && !Objects.isNull(purchaseOrder.getAttachmentType())){
                        if(purchaseOrder.getAttachmentType() == 0){
                            updateWrapper.set(PurchaseOrder :: getFileState,FlagConst.N.getCode());
                            updateWrapper.notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"));
                        }
                    }
                }

                purchaseOrderService.update(updateWrapper);
            }

        }

    }

    @Override
    public List<PurchaseOrderPrintDTO> getPrintData(String orderId) {
        final PurchaseOrder purchaseOrder = purchaseOrderService.getById(orderId);
        PurchaseOrderPrintDTO purchaseOrderPrintDTO = purchaseOrderConvert.entity2Dto1(purchaseOrder);
        //优化1：将字符串拼接改为StringBuilder拼接，提高字符串拼接效率
        purchaseOrderPrintDTO.setSupplierNameAndCode(
                purchaseOrder.getSupplierErpCode() + purchaseOrder.getSupplierName());
        purchaseOrderPrintDTO.setSupplierCode(purchaseOrder.getSupplierErpCode());
        final SupplierDTO supplierByCode = supplierClient.getSupplierByCode(purchaseOrder.getSupplierErpCode());
        SupplierContactsDTO defaultContact = supplierClient.getDefaultContact(purchaseOrder.getSupplierErpCode(), "12");
        purchaseOrderPrintDTO.setMonthFlag(supplierByCode.getMonthFlag());
        purchaseOrderPrintDTO.setSupplierEnName(supplierByCode.getSupplierNameEn());
        String taxName = StrUtil.EMPTY;
        //结款款方式进行处理月结60天（A类型）
        if (purchaseOrder.getPaymentMethodName() != null) {
            if (purchaseOrder.getPaymentMethodName().contains("（")) {
                String sub = "（";
                String payName = StringUtils.substringBefore(purchaseOrder.getPaymentMethodName(), sub);
                purchaseOrderPrintDTO.setPaymentMethodName(payName);
            }
        }
        //付款方式
        //逻辑修改，2025-05-27， 邓京术， 把采购订单的付款条件 ，+ 公司 + 工厂
        Pair<String, SupplierPurchaseCategoryDTO> calist = supplierClient.getSupplierPurchaseCategory(
                purchaseOrder.getSupplierErpCode(), purchaseOrder.getCompanyCode(),purchaseOrder.getPaymentMethod());
        if (calist == null || Objects.isNull(calist.getValue())) {
            calist = supplierClient.getSupplierPurchaseCategory(
                    purchaseOrder.getSupplierErpCode(), purchaseOrder.getCompanyCode());
        }
        if (calist != null) {
            //付款方式
            if (Objects.isNull(calist.getValue())) {
                throw new DaoException(StrUtil.format("{}公司的付款方式不存在!", purchaseOrder.getCompanyCode()));
            }
            final DictDTO paymentWay = dictClient.getDictByTypeAndCode(DictCode.PAYMENT_WAY.getCode(),
                    calist.getValue().getPaymentMethod());
            if (Objects.nonNull(paymentWay)) {
                purchaseOrderPrintDTO.setPayWay(paymentWay.getName());
            }
        }
        List<DictDTO> dicByType = dictClient.getDicByType(DictCode.ZIYUAN_PURCHASE.getCode());
        Set<String> collect = dicByType.stream().map(DictDTO::getCode).collect(Collectors.toSet());
        //判断是否资源整合
        if(collect.contains(purchaseOrder.getPurchaseGroupCode())){
            //
            purchaseOrderPrintDTO.setTongChuangFlag("02");
        }else{
            purchaseOrderPrintDTO.setTongChuangFlag("01");
        }
        //根据订单有效时间判断
        List<PurchaseOrderModify> ps = iPurchaseOrderModifyService.list(new LambdaQueryWrapper<PurchaseOrderModify>()
                .eq(PurchaseOrderModify::getOrderId, orderId).orderByDesc(PurchaseOrderModify::getCreateTime)
        );
        List<OrderPrintPerson> orderPrintPersonList = iOrderPrintPersonService.list(
                new LambdaQueryWrapper<OrderPrintPerson>()
                        .eq(OrderPrintPerson::getCompany, purchaseOrderPrintDTO.getCompanyCode())
                        .eq(OrderPrintPerson::getType, purchaseOrderPrintDTO.getTongChuangFlag())
                        .ge(OrderPrintPerson::getEndDate, ps.get(0).getCreateTime().toLocalDate())
                        .le(OrderPrintPerson::getStartDate, ps.get(0).getCreateTime().toLocalDate())
        );
        if(!CollectionUtils.isEmpty(orderPrintPersonList)){
            purchaseOrderPrintDTO.setName(orderPrintPersonList.get(0).getName());
        }
//东莞方珍梅提的单独判断
        if("601".equals(purchaseOrderPrintDTO.getPurchaseGroupCode())||"602".equals(purchaseOrderPrintDTO.getPurchaseGroupCode())){
            purchaseOrderPrintDTO.setName("程啸");
        }
//        String byPurchaseGroupCode = iStatementPaymentSettingService.findByPurchaseGroupCode(purchaseOrder.getPurchaseGroupCode());
        final LambdaQueryWrapper<PurchaseOrderDetail> queryWrapper = new LambdaQueryWrapper<PurchaseOrderDetail>().eq(
                PurchaseOrderDetail::getOrderId, orderId);
        queryWrapper.eq(PurchaseOrderDetail::getDelFlag, DelFlag.NORMAL.getStatus());
        final List<PurchaseOrderDetail> list = purchaseOrderDetailService.list(
                queryWrapper);
        List<PurchaseOrderItemPrintDTO> items = new ArrayList<>(list.size());
        //优化2：使用迭代器代替for循环，提高遍历集合效率
        Iterator<PurchaseOrderDetail> iterator = list.iterator();
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal taxAmount = BigDecimal.ZERO;
        BigDecimal taxMoney = BigDecimal.ZERO;
        Map<String,String> materiaNameMap = new HashMap<>();
        while (iterator.hasNext()) {
            PurchaseOrderDetail purchaseOrderDetail = iterator.next();
            taxName = purchaseOrderDetail.getTaxName();
            PurchaseOrderItemPrintDTO a = purchaseOrderDetailConvert.entity2Dto(purchaseOrderDetail);
            a.setPrice(purchaseOrderDetail.getPrice().stripTrailingZeros().toPlainString());
            a.setNum(purchaseOrderDetail.getNum().stripTrailingZeros().toPlainString());
            a.setTaxAmount(purchaseOrderDetail.getTaxAmount().stripTrailingZeros().toPlainString());
            taxAmount = taxAmount.add(purchaseOrderDetail.getTaxAmount());
            BigDecimal detailAmount = purchaseOrderDetail.getAmount();
            detailAmount = detailAmount.setScale(2, RoundingMode.HALF_DOWN);
            a.setAmount(detailAmount.stripTrailingZeros().toPlainString());
            amount = amount.add(detailAmount);
            BigDecimal detailTaxMoney = purchaseOrderDetail.getTaxAmount()
                    .subtract(detailAmount);
            detailTaxMoney = detailTaxMoney.setScale(2, RoundingMode.HALF_DOWN);
            a.setTaxMoney(
                    detailTaxMoney.stripTrailingZeros()
                            .toPlainString());
            taxMoney = taxMoney.add(detailTaxMoney);
            //需要判断是否是交货完成
            String remark = purchaseOrderDetail.getRemark();
            if (purchaseOrderDetail.getFinishFlag().equals(FlagConst.Y.getLabel())) {
                if (StrUtil.isNotEmpty(remark)) {
                    remark = remark + "已结案";
                } else {
                    remark = "已结案";
                }
            }
            //设置最新的物料名称，如果物料名称有变化，则取最新的物料名称， 2024-08-07 邓京术
            initMaterialName(a,purchaseOrderDetail, materiaNameMap);
            a.setRemark(remark);
            items.add(a);
        }
        //判断供应商属性是否为 attr  1战略联盟供应商  6协同供需供应商 如果是，则打印页面条件有5项不需要， 邓京术2024-09-14
        //2024-10-10叶平平调整，如果是以下3家公司，则不显示，其他全部显示 4249	锐捷网络股份有限公司 4844	紫光计算机科技有限公司 4459    重庆紫光华智科技有限公司
        purchaseOrderPrintDTO.setSupplierAttr("0");
        SupplierDTO supplierDTO = supplierClient.getSupplierById(purchaseOrder.getSupplierId());
//        if (null != supplierDTO && StringUtils.isNotEmpty(supplierDTO.getAttr()) && (supplierDTO.getAttr().equals("1") || supplierDTO.getAttr().equals("6"))) {
        if (supplierDTO.getSupplierCode().equals("4249") || supplierDTO.getSupplierCode().equals("4844") || supplierDTO.getSupplierCode().equals("4459")) {
//            purchaseOrderPrintDTO.setSupplierAttr("1");
        }
        purchaseOrderPrintDTO.setTaxMoney(taxMoney.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setOrderAmount(amount.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setTaxAmount(taxAmount.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setTaxName(taxName);
        purchaseOrderPrintDTO.setOrderDetailList(items);
        //解决汇总打印时，生成PDF有空白页的问题 邓京术 2024-11-20号
        if (items.size() == 8 || items.size() == 30 || ((items.size() - 30)  % 21 == 0)) {
            purchaseOrderPrintDTO.setPageFlag("1");
        } else {
            purchaseOrderPrintDTO.setPageFlag("0");
        }
        purchaseOrderPrintDTO.setUserInfo("");
        if(defaultContact != null && StringUtils.isNotEmpty(defaultContact.getContactsName())){
            purchaseOrderPrintDTO.setUserInfo(defaultContact.getContactsName());
        }

        //优化3：将查询操作提前，避免多次查询数据库
        if (purchaseOrder.getCreateId() != null) {
            final UserDTO spUser = userClient.getByUserId(purchaseOrder.getCreateId());
            if (Objects.nonNull(spUser)) {
                final String phone = spUser.getPhone();
                purchaseOrderPrintDTO.setUserPhone(phone);
            }
        }
        // 增加供应商是否小批量，选择对应模板 2025-10-10 陈天仕 新增
        Integer qualifiedSupplierAmount = purchaseOrderService.findQualifiedSupplier(supplierDTO.getSupplierCode());
        if (qualifiedSupplierAmount > 0) {
            // 合格的供应商
            purchaseOrderPrintDTO.setSupplierState("1");
        } else {
            // 小批量供应商
            purchaseOrderPrintDTO.setSupplierState("0");
        }

        return Lists.newArrayList(purchaseOrderPrintDTO);
    }

    @Override
    public List<PurchaseOrderListDTO> listAll(PurchaseOrderQuery purchaseOrderQuery) {
        //需要单独查询分页总数
        purchaseOrderQuery.setRows(1);
        purchaseOrderQuery.setPage(1);
        Page<PurchaseOrderPO> orderDetailPOPage = PageUtil.toPage(purchaseOrderQuery);
        getPurchaseOrders(purchaseOrderQuery, orderDetailPOPage);
        if (orderDetailPOPage.getTotal() > sysProp.getExportMaxCount()) {
            throw new DaoException(StrUtil.format("导出数据超过{}条", sysProp.getExportMaxCount()));
        }
        final List<PurchaseOrderPO> list = getPurchaseOrders(purchaseOrderQuery, null);
        return purchaseOrderConvert.Po2Dtos(list);
    }

    @Override
    @DS(SLAVE)
    public PageView orderList(PurchaseOrderQuery query) {
        Page<PurchaseOrder> page = PageUtil.toPage(query);
        if (LoginUtil.isSupplier()) {
            query.setLoginUserId(LoginUtil.getUserId());
        }
        //增加一个配置判断 如果供应商在配置表中
        List<String> excludePurchaseGroupCodes = null;
        Long userId = LoginUtil.getUserId();
        List<StatementPaymentSetting> statementPaymentSettings = statementPaymentSettingService.findStatementPaymentSettingBySupplierCodeList(query.getSupplierCode());
        if(!CollectionUtils.isEmpty(statementPaymentSettings)){
            List<String> purchaseGroupCodes = statementPaymentSettings.stream()
                    .filter(setting -> setting.getUserId().equals(userId))
                    .map(StatementPaymentSetting::getPurchaseGroupCode)
                    .collect(Collectors.toList());

           excludePurchaseGroupCodes = statementPaymentSettings.stream()
                    .map(StatementPaymentSetting::getPurchaseGroupCode)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(purchaseGroupCodes)) {
                excludePurchaseGroupCodes.removeAll(purchaseGroupCodes);
            }

        }


//        final List<PurchaseOrderPO> list = purchaseOrderService.orderList(query, page);

        // 假设 dbPage 是 MyBatis Plus 的 Page 类型，且已执行过分页查询
        List<PurchaseOrderPO> list = purchaseOrderService.orderList(query, null);

        if(!CollectionUtils.isEmpty(excludePurchaseGroupCodes) && !CollectionUtils.isEmpty(list)){
            for (String remove : excludePurchaseGroupCodes){
                list.removeIf(statementItemDTO -> (statementItemDTO.getPurchaseGroupCode()).equals(remove));
            }
        }

        //去除已付款数据
        List<PurchaseOrderListDTO> listDTOS= new ArrayList<>();
        if(!CollectionUtils.isEmpty(list)){
          List<String> s= list.stream().map(ls -> ls.getOrderCode()).collect(Collectors.toList());
            PaymentApplyItemQuery pa=new PaymentApplyItemQuery();
            pa.setPoCodes(s);
            pa.setMorePoQuery(null);
            List<PurchaseOrderPO> listPo = new ArrayList<>();
            List<CreatePaaDetailPO> result = paymentCodApplyDetailService.readAdvancePaymentPoData(pa);
            if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(result)) {
                paymentCodApplyDetailService.findPoAdvanceApplySituation(result, null, 0L);
                //去除result中含税金额和已付款金额相同的数据,remove方法
                result.removeIf(item -> item.getItAmount().compareTo(item.getAlreadyApplyAmount()) == 0);
                result.removeIf(item -> item.getApplyAmount().compareTo(BigDecimal.ZERO) == 0);

                if (CollUtil.isNotEmpty(result)){
                    List<String> rs= result.stream().map(ls -> ls.getPoCode()).collect(Collectors.toList());
                    for (PurchaseOrderPO pp : list) {
                        if(rs.contains(pp.getOrderCode())){
                            listPo.add(pp);
                        }
                    }
                    List<PurchaseOrderPO> ss=  listPo.stream().collect(Collectors.collectingAndThen
                            (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                                    (PurchaseOrderPO::getOrderCode))), ArrayList::new));
                    listDTOS = purchaseOrderConvert.Po2Dtos(ss);
                }
            }else{
                listDTOS = purchaseOrderConvert.Po2Dtos(list);
            }
        }else{
             listDTOS = purchaseOrderConvert.Po2Dtos(list);
        }
        return PageUtil.getPV(listDTOS, page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DS(SLAVE)
    public void sumbitDevPlan(List<PurchaseOrderDevPlanBaseDTO> planBaseDTOS) {
        String go_published = stringRedisTemplate.opsForValue().get("devPlan_" + LoginUtil.getUserId());
        if (null != go_published && go_published.equals("Y")) {
            throw new DaoException("数据正在提交中，请勿重复操作！");
        }
        stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "Y", 30, TimeUnit.SECONDS);

        //需要对数据处理
        final Map<String, List<PurchaseOrderDevPlanBaseDTO>> listMap = planBaseDTOS.stream()
                .collect(Collectors.groupingBy(PurchaseOrderDevPlanBaseDTO::getLineItem));
        //需要对分组的数据处理
        final DevPlanToSapDTO devPlanToSapDTO = new DevPlanToSapDTO();
        final DevPlanToSapDTO.ItItem itItem = new DevPlanToSapDTO.ItItem();
        itItem.item = Lists.newArrayList();
        final DevPlanToSapDTO.ItHead itHead = new DevPlanToSapDTO.ItHead();
        itHead.item = Lists.newArrayList();
        for (List<PurchaseOrderDevPlanBaseDTO> value : listMap.values()) {
            if (CollUtil.isEmpty(value)) {
                continue;
            }
            String orderCode = value.get(0).getPurchaseOrder();
            String orderRowNo = value.get(0).getLineItem();
            final DevPlanToSapDTO.Item head = new DevPlanToSapDTO.Item();
            head.EBELN = orderCode;
            head.EBELP = orderRowNo;
            itHead.item.add(head);
            //如果有id的并且是删除的，打上删除标记
            Integer no = value.stream().filter(a -> Objects.nonNull(a.getId()))
                    .map(a -> Integer.valueOf(a.getScheduleLine()))
                    .max(Integer::compare).orElse(0);
            final List<PurchaseOrderDevPlanBaseDTO> purchaseOrderDevPlanBaseDTOStream = value.stream()
                    .filter(a -> Objects.isNull(a.getId()))
                    .filter(a -> Objects.isNull(a.getDelFlag()) || a.getDelFlag() == DelFlag.NORMAL.getStatus())
                    .toList();
            //需要重新编号
            for (PurchaseOrderDevPlanBaseDTO purchaseOrderDevPlanBaseDTO : purchaseOrderDevPlanBaseDTOStream) {
                no = no + 1;
                purchaseOrderDevPlanBaseDTO.setScheduleLine(String.valueOf(no));

            }
            for (PurchaseOrderDevPlanBaseDTO purchaseOrderDevPlanBaseDTO : value) {
                final DevPlanToSapDTO.Item item = new DevPlanToSapDTO.Item();
                item.EBELN = purchaseOrderDevPlanBaseDTO.getPurchaseOrder();
                item.EBELP = purchaseOrderDevPlanBaseDTO.getLineItem();
                item.ETENR = purchaseOrderDevPlanBaseDTO.getScheduleLine();
                item.ZSCBS = Objects.nonNull(purchaseOrderDevPlanBaseDTO.getDelFlag()) &&
                        purchaseOrderDevPlanBaseDTO.getDelFlag() == DelFlag.DELETE.getStatus() ? "X" : "";
                item.MENGE = purchaseOrderDevPlanBaseDTO.getScheduleDeliveryQuantity().toPlainString();
                item.EINDT = LocalDateTimeUtil.format(purchaseOrderDevPlanBaseDTO.getScheduleDeliveryDate(), yyyyMMdd);
                item.BANFN = purchaseOrderDevPlanBaseDTO.getPurchaseRequest();
                item.BNFPO = purchaseOrderDevPlanBaseDTO.getPurchaseRequestLine();
                itItem.item.add(item);
            }
        }
        devPlanToSapDTO.setIT_ITEM(itItem);
        devPlanToSapDTO.setIT_HEAD(itHead);
        List<PurchaseOrderDevPlan> purchaseOrderDevPlans = purchaseOrderDevPlanConvert.dtos2Entities(planBaseDTOS);
        //做日期合规性校验
        //判断输入的日期是否在当前日期3年之前
        final LocalDate now = LocalDate.now();
        final LocalDate localDate = now.plusDays(999) ;
        //取当前日期 和当前年份2025-05-26
        int currentYear = LocalDate.now().getYear();//当前年
        for (PurchaseOrderDevPlan purchaseOrderDevPlan : purchaseOrderDevPlans) {
            final String orderCode = purchaseOrderDevPlan.getPurchaseOrder();//
            final String orderRow = purchaseOrderDevPlan.getLineItem();
            final String scheduleLine = purchaseOrderDevPlan.getScheduleLine();
            final String s = "SAP订单号:" + orderCode + ",订单行号:" + orderRow + ",计划行号:" + scheduleLine;
            List<PurchaseOrderDevPlan> disList = purchaseOrderDevPlans.stream()
                    .filter(t -> t.getPurchaseOrder().equals(orderCode) && t.getLineItem().equals(orderRow) &&
                            t.getScheduleLine().equals(scheduleLine)).collect(Collectors.toList());
            if (disList != null && disList.size() > 1) {
                stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                throw new DaoException("不允许" + s + "三个值出现重复计划行号，请检查！");
            }
            if(purchaseOrderDevPlan.getDelFlag()  != DelFlag.DELETE.getStatus()){
                //回复交期不能大于当前日期+999天
                if (purchaseOrderDevPlan.getScheduleDeliveryDate().isAfter(localDate)) {
                    stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                    throw new DaoException(StrUtil.format("单号:{},行号:{},计划交货日期不能在当前日期3年之后",
                            purchaseOrderDevPlan.getPurchaseOrder(), purchaseOrderDevPlan.getLineItem()));
                }
                //回复交期不能小于今年
                if(purchaseOrderDevPlan.getScheduleDeliveryQuantity().subtract(purchaseOrderDevPlan.getReceivedQuantity()).compareTo(BigDecimal.ZERO) > 0) {

                    if (purchaseOrderDevPlan.getScheduleDeliveryDate().getYear() < currentYear) {
                        stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                        throw new DaoException(StrUtil.format("单号:{},行号:{},计划交货日期不能在当前日期之前",
                                purchaseOrderDevPlan.getPurchaseOrder(), purchaseOrderDevPlan.getLineItem()));
                    }
                }
                if(purchaseOrderDevPlan.getScheduleDeliveryQuantity().subtract(purchaseOrderDevPlan.getReceivedQuantity()).compareTo(BigDecimal.ZERO) > 0){
                    if(currentYear == purchaseOrderDevPlan.getScheduleDeliveryDate().getYear()){//答交日期等于今年
                        LocalDate specificDate = LocalDate.of(currentYear, 1, 2);
                        if(purchaseOrderDevPlan.getScheduleDeliveryDate().isBefore(LocalDate.now())){
                            if(!purchaseOrderDevPlan.getScheduleDeliveryDate().equals(specificDate)){
                                stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
                        throw new DaoException(StrUtil.format("单号:{},行号:{},计划交货日期不能在当前日期之前",
                               purchaseOrderDevPlan.getPurchaseOrder(), purchaseOrderDevPlan.getLineItem()));
                            }
                        }
                    }
                }
            }
        }
        //抛送至SAP的时机应该在SRM端都校验完成再抛送SAP
        final SapResposeBody o = sapClient.updateDevPlan(devPlanToSapDTO);
        if (o.getES_RET().getCODE().equals(RestCode.SAP_ERROR.getCode())) {
            stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
            throw new DaoException(o.getES_RET().getMSG());
        }
        try {
            purchaseOrderDevPlanService.saveOrUpdateBatch(purchaseOrderDevPlans);
        } catch (DuplicateKeyException e) {
            throw new DaoException("别的用户正在操作相同的订单交货计划，请重新打开明细再试！");
        }
        /**
         * 取计划行最晚的“计划交货日期”更新订单行里的“回复日期”
         */
        //2024-12-02 qzc 排除删除的计划交货行和完成交货的计划行
        for (String s : listMap.keySet()) {
            final List<PurchaseOrderDevPlanBaseDTO> purchaseOrderDevPlanBaseDTOS = listMap.get(s);
            final Optional<PurchaseOrderDevPlanBaseDTO> max = purchaseOrderDevPlanBaseDTOS.stream()
                    .filter(a -> (Objects.isNull(a.getDelFlag()) || a.getDelFlag() == DelFlag.NORMAL.getStatus()) &&(a.getScheduleDeliveryQuantity().compareTo(a.getReceivedQuantity()) != 0)).max(Comparator.comparing(PurchaseOrderDevPlanBaseDTO::getScheduleDeliveryDate));

            if (max.isPresent()) {
                final PurchaseOrderDevPlanBaseDTO planBaseDTO = max.get();
                final LocalDate scheduleDeliveryDate = planBaseDTO.getScheduleDeliveryDate();
                final String purchaseOrder = planBaseDTO.getPurchaseOrder();
                final String orderRow = planBaseDTO.getLineItem();
                purchaseOrderDetailService.update(new LambdaUpdateWrapper<>(PurchaseOrderDetail.class)
                        .set(PurchaseOrderDetail::getReplayRequireDate, scheduleDeliveryDate)
                        .eq(PurchaseOrderDetail::getOrderCode, purchaseOrder)
                        .eq(PurchaseOrderDetail::getOrderRow, orderRow));
            }

        }
        stringRedisTemplate.opsForValue().set("devPlan_" + LoginUtil.getUserId(), "N", 30, TimeUnit.SECONDS);
    }

    @Override
    public void refusal(Long id, String remark) {
        final PurchaseOrder purchaseOrder = purchaseOrderService.getById(id);
        if (Objects.isNull(purchaseOrder)) {
            throw new DaoException("采购订单不存在");
        }
        if(StringUtils.isNotEmpty(purchaseOrder.getBatchNo())){
            purchaseOrderService.update(new LambdaUpdateWrapper<PurchaseOrder>()
                    .eq(PurchaseOrder::getBatchNo, purchaseOrder.getBatchNo())
                    .set(PurchaseOrder::getRefusalRemark, remark)
                    .set(PurchaseOrder::getFinConf, FlagConst.N.getCode())
                    .set(PurchaseOrder::getFileState, FlagConst.N.getCode())
                    .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
            );
        }else{
            purchaseOrderService.update(new LambdaUpdateWrapper<PurchaseOrder>()
                    .eq(PurchaseOrder::getId, id)
                    .set(PurchaseOrder::getRefusalRemark, remark)
                    .set(PurchaseOrder::getFinConf, FlagConst.N.getCode())
                    .set(PurchaseOrder::getFileState, FlagConst.N.getCode())
                    .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
            );
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @DS(SLAVE)
    public PurchaseOrderPrintDTO getBatchPrintData(String orderIds, String range, String batchNo, String supplierCode) {

        //需要在打印的时候把汇总单号设置下
//        final String sequenceNo = sequenceClient.createSequenceNo(SequenceConst.PURCHASE_ORDER_BATCH.getCode());
        final List<PurchaseOrder> purchaseOrders;
        //有batch是补打
        if (StrUtil.isNotEmpty(batchNo)) {
            final List<PurchaseOrderSummary> list = purchaseOrderSummaryService.list(
                    new LambdaQueryWrapper<PurchaseOrderSummary>().eq(PurchaseOrderSummary::getCode, batchNo));
            purchaseOrders = purchaseOrderService.listByIds(list.stream().map(PurchaseOrderSummary::getOrderId).collect(
                    Collectors.toSet()));
        } else {
            final String sequenceNo = sequenceClient.getBarCodeSequenceNo(SequenceConst.PURCHASE_ORDER_BATCH.getCode(), 5, false);
            final List<String> orderIdList = Arrays.asList(orderIds.split(","));
            purchaseOrderService.update(
                    new LambdaUpdateWrapper<PurchaseOrder>()
                            .set(PurchaseOrder::getSumSignFlag,0)
                            .set(PurchaseOrder::getBatchNo, sequenceNo)
                            .set(PurchaseOrder::getPrintFlag, FlagConst.Y.getCode())
                            .in(PurchaseOrder::getId, orderIdList));
            purchaseOrders = purchaseOrderService.listByIds(orderIdList);
            List<PurchaseOrderModify> purchaseOrderModifies = purchaseOrderModifyService.list(new LambdaUpdateWrapper<PurchaseOrderModify>().in(PurchaseOrderModify::getOrderId, orderIdList));
            Map<Long, PurchaseOrderModify> purchaseOrderModifieMap = purchaseOrderModifies.stream().collect(Collectors.toMap(PurchaseOrderModify::getOrderId, Function.identity(), (existing, replacement) -> replacement));
            List<PurchaseOrderSummary> saveList = new ArrayList<>(purchaseOrders.size());
            for (PurchaseOrder it : purchaseOrders) {
                PurchaseOrderSummary purchaseOrderSummary = new PurchaseOrderSummary();
                purchaseOrderSummary.setCode(sequenceNo);
                purchaseOrderSummary.setOrderId(it.getId());
                purchaseOrderSummary.setCreateTime(it.getCreateTime());
                purchaseOrderSummary.setCreateId(LoginUtil.getUserId());
                if(Objects.nonNull(purchaseOrderModifieMap.get(it.getId()))){
                    PurchaseOrderModify purchaseOrderModify = purchaseOrderModifieMap.get(it.getId());
                    purchaseOrderSummary.setOrderCreateTime(purchaseOrderModify.getCreateTime());
                }
                saveList.add(purchaseOrderSummary);
            }
            purchaseOrderSummaryService.saveBatch(saveList);
        }
        //2024-09-10 订单号日期缓存
        Map<String, LocalDateTime> orderCraeteTimeMap = purchaseOrders.stream()
                .collect(Collectors.toMap(
                        PurchaseOrder::getOrderCode,
                        PurchaseOrder::getCreateTime,
                        (existing, replacement) -> replacement // 这里选择保留新的create_time
                ));
        PurchaseOrder purchaseOrder = purchaseOrders.get(0);
        for (PurchaseOrder purchaseOrder1 : purchaseOrders) {
            SupplierDTO supplierDTO = supplierClient.getSupplierById(purchaseOrder1.getSupplierId());
            if (StringUtils.equals(supplierCode, supplierDTO.getSupplierCode())) {
                purchaseOrder = purchaseOrder1;
            }
        }
        PurchaseOrderPrintDTO purchaseOrderPrintDTO = purchaseOrderConvert.entity2Dto1(purchaseOrder);
        SupplierContactsDTO defaultContact = supplierClient.getDefaultContact(purchaseOrder.getSupplierErpCode(), "12");

        //优化1：将字符串拼接改为StringBuilder拼接，提高字符串拼接效率
        purchaseOrderPrintDTO.setSupplierNameAndCode(
                purchaseOrder.getSupplierErpCode() + purchaseOrder.getSupplierName());
        purchaseOrderPrintDTO.setSupplierCode(purchaseOrder.getSupplierErpCode());
        //结款款方式进行处理月结60天（A类型）
        if (purchaseOrder.getPaymentMethodName() != null) {
            if (purchaseOrder.getPaymentMethodName().contains("（")) {
                String sub = "（";
                String payName = StringUtils.substringBefore(purchaseOrder.getPaymentMethodName(), sub);
                purchaseOrderPrintDTO.setPaymentMethodName(payName);
            }
        }
        //付款方式
        Pair<String, SupplierPurchaseCategoryDTO> calist = supplierClient.getSupplierPurchaseCategory(
                purchaseOrder.getSupplierErpCode(), purchaseOrder.getCompanyCode());
        if (calist != null) {
            //付款方式
            final DictDTO paymentWay = dictClient.getDictByTypeAndCode(DictCode.PAYMENT_WAY.getCode(),
                    calist.getValue().getPaymentMethod());
            if (Objects.nonNull(paymentWay)) {
                purchaseOrderPrintDTO.setPayWay(paymentWay.getName());//gong
            }
        }

        List<DictDTO> dicByType = dictClient.getDicByType(DictCode.ZIYUAN_PURCHASE.getCode());
        Set<String> collect = dicByType.stream().map(DictDTO::getCode).collect(Collectors.toSet());
        //判断是否资源整合
        if(collect.contains(purchaseOrder.getPurchaseGroupCode())){
            //
            purchaseOrderPrintDTO.setTongChuangFlag("02");
        }else{
            purchaseOrderPrintDTO.setTongChuangFlag("01");
        }
        //根据汇总订单创建时间判断
        String bn = purchaseOrderPrintDTO.getBatchNo().substring(0,8);
        DateTimeFormatter fm = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate date = LocalDate.parse(bn, fm);
        List<OrderPrintPerson> orderPrintPersonList = iOrderPrintPersonService.list(
                new LambdaQueryWrapper<OrderPrintPerson>()
                        .eq(OrderPrintPerson::getCompany, purchaseOrderPrintDTO.getCompanyCode())
                        .eq(OrderPrintPerson::getType, purchaseOrderPrintDTO.getTongChuangFlag())
                        .ge(OrderPrintPerson::getEndDate, date)
                        .le(OrderPrintPerson::getStartDate, date)
        );
        if(!CollectionUtils.isEmpty(orderPrintPersonList)){
            purchaseOrderPrintDTO.setName(orderPrintPersonList.get(0).getName());
        }
        //判断供应商属性是否为 attr  1战略联盟供应商  6协同供需供应商 如果是，则打印页面条件有5项不需要， 邓京术2024-09-14
        //2024-10-10叶平平调整，如果是以下3家公司，则不显示，其他全部显示 4249	锐捷网络股份有限公司 4844	紫光计算机科技有限公司 4459    重庆紫光华智科技有限公司
        purchaseOrderPrintDTO.setSupplierAttr("0");
        SupplierDTO supplierDTO = supplierClient.getSupplierById(purchaseOrder.getSupplierId());
//        if (StringUtils.isNotEmpty(supplierDTO.getAttr()) && (supplierDTO.getAttr().equals("1") || supplierDTO.getAttr().equals("6"))) {
        if (supplierDTO.getSupplierCode().equals("4249") || supplierDTO.getSupplierCode().equals("4844") || supplierDTO.getSupplierCode().equals("4459")) {
//            purchaseOrderPrintDTO.setSupplierAttr("1");
        }

        //生成明细的序列号 2024-08-14打印的时候取
        List<PurchaseOrderDetail> updateBatchList = new ArrayList<>();
        final List<PurchaseOrderDetail> list = purchaseOrderDetailService.list(
                new LambdaQueryWrapper<PurchaseOrderDetail>().in(PurchaseOrderDetail::getOrderId,
                                purchaseOrders.stream().map(PurchaseOrder::getId).collect(Collectors.toSet()))
                        .eq(PurchaseOrderDetail::getDelFlag, DelFlag.NORMAL.getStatus())
                        .orderByDesc(PurchaseOrderDetail::getOrderCode)
                        .orderByAsc(PurchaseOrderDetail::getOrderRow));
        List<PurchaseOrderItemPrintDTO> items = new ArrayList<>(list.size());
        //排序，先按订单明细的创建日期， 再按订单号， 相同订单号在按行号排序
        Collections.sort(list, new Comparator<PurchaseOrderDetail>() {
            @Override
            public int compare(PurchaseOrderDetail s1, PurchaseOrderDetail s2) {
                if (s1.getCreateTime().equals(s2.getCreateTime())) {
                    if (s1.getOrderCode().equals(s2.getOrderCode())) {
                        int no1 = Integer.parseInt(s1.getOrderRow());
                        int no2 = Integer.parseInt(s2.getOrderRow());
                        return no1 - no2;
                    } else {
                        s1.getOrderCode().compareTo(s2.getOrderCode());
                    }
                } else {
                    return s1.getCreateTime().compareTo(s2.getCreateTime());
                }
                return 0;
            }
        });

//需要获取当前月份的第一天和最后一天
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.yyyyMMDash);
        final DateTime localDate = DateUtil.parse(range, formatter);
        final Pair<LocalDateTime, LocalDateTime> startAndEndDate = DateUtils.getStartAndEndDate(localDate.year(),
                localDate.monthBaseOne());
        purchaseOrderPrintDTO.setRangTime(DateUtils.formatYYYYMMDDSlash(startAndEndDate.getKey()) + "-" +
                DateUtils.formatYYYYMMDDSlash(startAndEndDate.getValue()));
        purchaseOrderPrintDTO.setMonth(range.replace(StrUtil.DASHED, "年") + "月");
        //优化2：使用迭代器代替for循环，提高遍历集合效率
        Iterator<PurchaseOrderDetail> iterator = list.iterator();
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal taxAmount = BigDecimal.ZERO;
        BigDecimal taxMoney = BigDecimal.ZERO;
        Map<String, String> materiaNameMap = new HashMap<>();
        int i = 0;
        while (iterator.hasNext()) {
            i ++ ;
            PurchaseOrderDetail purchaseOrderDetail = iterator.next();
            PurchaseOrderItemPrintDTO a = purchaseOrderDetailConvert.entity2Dto(purchaseOrderDetail);
            if(Objects.nonNull(orderCraeteTimeMap.get(a.getOrderCode()))){
                a.setCreateTime(orderCraeteTimeMap.get(a.getOrderCode()));
            }
            a.setPrice(purchaseOrderDetail.getPrice().stripTrailingZeros().toPlainString());
            a.setNum(purchaseOrderDetail.getNum().stripTrailingZeros().toPlainString());
            a.setTaxAmount(purchaseOrderDetail.getTaxAmount().stripTrailingZeros().toPlainString());
            BigDecimal detailAmount = purchaseOrderDetail.getAmount();
            detailAmount = detailAmount.setScale(2, RoundingMode.HALF_DOWN);
            a.setAmount(detailAmount.stripTrailingZeros().toPlainString());
            BigDecimal detailTaxMoney = purchaseOrderDetail.getTaxAmount().subtract(detailAmount);
            detailTaxMoney = detailTaxMoney.setScale(2, RoundingMode.HALF_DOWN);
            a.setTaxMoney(
                    detailTaxMoney.stripTrailingZeros()
                            .toPlainString());
            purchaseOrderPrintDTO.setTaxName(purchaseOrderDetail.getTaxName());
            items.add(a);
            taxAmount = taxAmount.add(purchaseOrderDetail.getTaxAmount());
            amount = amount.add(detailAmount);
            taxMoney = taxMoney.add(detailTaxMoney);
            //兼容以前补打时没有生成打印序列号 batchNo为空时方便重新生成序列号，  序列号为空兼容未生成的打印号。
            if (StrUtil.isEmpty(batchNo)) {
                purchaseOrderDetail.setPrintSequence(i);
                a.setPrintSequence(i);
                PurchaseOrderDetail tempDetail = new PurchaseOrderDetail();
                tempDetail.setId(purchaseOrderDetail.getId());
                tempDetail.setPrintSequence(i);
                updateBatchList.add(tempDetail);
            }

            //设置最新的物料名称，如果物料名称有变化，则取最新的物料名称， 2024-08-07 邓京术
            initMaterialName(a,purchaseOrderDetail, materiaNameMap);
        }
        purchaseOrderPrintDTO.setTaxMoney(taxMoney.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setOrderAmount(amount.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setTaxAmount(taxAmount.stripTrailingZeros().toPlainString());
        purchaseOrderPrintDTO.setOrderDetailList(items);
        //解决汇总打印时，生成PDF有空白页的问题 邓京术 2024-11-20号
        if (items.size() == 8 || items.size() == 30 || ((items.size() - 30)  % 21 == 0)) {
            purchaseOrderPrintDTO.setPageFlag("1");
        } else {
            purchaseOrderPrintDTO.setPageFlag("0");
        }
        purchaseOrderPrintDTO.setUserInfo("");
        if(defaultContact != null && StringUtils.isNotEmpty(defaultContact.getContactsName())){
            purchaseOrderPrintDTO.setUserInfo(defaultContact.getContactsName());
        }

        //优化3：将查询操作提前，避免多次查询数据库
        if (purchaseOrder.getCreateId() != null) {
            final UserDTO spUser = userClient.getByUserId(purchaseOrder.getCreateId());
            if (Objects.nonNull(spUser)) {
                final String phone = spUser.getPhone();
                purchaseOrderPrintDTO.setUserPhone(phone);
            }
        }
        //把打印的序列号更新到数据库
        if (!CollectionUtils.isEmpty(updateBatchList)) {
            purchaseOrderDetailService.saveOrUpdateBatch(updateBatchList);
        }
        // 增加供应商是否小批量，选择对应模板 2025-10-10 陈天仕 新增
        Integer qualifiedSupplierAmount = purchaseOrderService.findQualifiedSupplier(supplierDTO.getSupplierCode());
        if (qualifiedSupplierAmount > 0) {
            // 合格的供应商
            purchaseOrderPrintDTO.setSupplierState("1");
        } else {
            // 小批量供应商
            purchaseOrderPrintDTO.setSupplierState("0");
        }

        return purchaseOrderPrintDTO;
    }

    private void initMaterialName(PurchaseOrderItemPrintDTO po , PurchaseOrderDetail purchaseOrderDetail, Map<String,String> materialNameMap) {
        if (materialNameMap.keySet().contains(po.getMaterialCode())) {
            po.setMaterialName(materialNameMap.get(po.getMaterialCode()));
        } else {
            ProductInfoDTO productInfoDTO = productClient.getByMaterialCodeAndFactoryCode(purchaseOrderDetail.getMaterialCode(), purchaseOrderDetail.getFactoryCode());
            if (Objects.nonNull(productInfoDTO)) {
                materialNameMap.put(po.getMaterialCode(), productInfoDTO.getMaterialName());
                po.setMaterialName(productInfoDTO.getMaterialName());
            }
        }
    }

    @Override
    public void batchPrintPdfCreate(PurchaseOrderPrintDTO batchPrintData, HttpServletResponse response) {
        //进行文件的生成操作
        String configValue = ResourceUtil.readUtf8Str("view/pc/order/purchaseOrder/batch_print_template_sum.ftl");
        configValue = configValue.replace("<#include \"../../base/base.ftl\">",
                "<#macro formatDateTime dateTime pattern><#if dateTime??><#assign formattedDateTime = " +
                        "dateTime?datetime(\"yyyy-MM-dd'T'HH:mm\")>${formattedDateTime?string(pattern)" +
                        "}</#if></#macro>");
        Template template = null;
        try {
            //需要多个
            template = new Template("emailTemplate", configValue, freemarkerConfig);
            final Map<String, Object> map = Maps.newHashMap();
            map.put("ctx", sysProp.getHostUrl());
            map.put("purchaseOrder", batchPrintData);
            //取朗华和久立的交货地址， 邓京术 2025-07-04
            List<DictDTO> dictDTOS = dictClient.getDicByType("delivery_address_usd");
            dictDTOS.stream().forEach(item ->{
                map.put("deliverAddress" + item.getName(), item.getCode());
            });
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);

            //创建pdf空文件
            File file2 = fileClient.createFile(
                    "采购汇总订单-" + batchPrintData.getOrderCode() + "-" + IdWorker.getIdStr() + ".pdf");
            log.info("file{}", file2.getPath());
//            PDFUtil.generatePdfFromHtml(html, file.getPath(), true, true);


            OutputStream outputStream = new FileOutputStream(file2);
            ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(html.getBytes());
            String fontPath =  "/static/font/msyh.ttc,1";
            PrintOrderCreatePdfUtil.convertToPdf(tInputStringStream, fontPath, outputStream);
            tInputStringStream.close();
            outputStream.close();
//            File file1 = new File(StrUtil.concat(false, fileLogic.genDatePath().getKey(), File.separator, "采购订单-" + purchaseOrderPrintDTO.getOrderCode() + "-" + IdWorker.getIdStr() + ".pdf"));
            File file1 = new File(StrUtil.concat(false, fileLogic.genDatePath().getKey(), File.separator, file2.getName()));
            // 再次打开文件并进行处理
            // 使用 PdfReader 和 PdfWriter 进行处理
            InputStream inputStream = new FileInputStream(file1);
            PdfReader reader = new PdfReader(inputStream);
            PdfWriter writer = new PdfWriter(file1);
            try (PdfDocument pdfDoc = new PdfDocument(reader, writer)) {
                int numberOfPages = pdfDoc.getNumberOfPages();
                for (int i = 1; i <= numberOfPages; i++) {
                    String footerText = "　　　　　　　　　　　　　　　　　　　　　　　第" + i + "页 共" + numberOfPages  + "页";
                    PdfPage page = pdfDoc.getPage(i);
                    PdfCanvas canvas = new PdfCanvas(page);
                    try {
                        PdfExtGState extGState = new PdfExtGState();
                        extGState.setFillOpacity(1f); // 设置填充透明度为0.05
                        double alpha = Math.toRadians(0); // 倾斜角度
                        double tanAlpha = Math.tan(alpha);
                        //可根据页面宽高设置水印
                        canvas.saveState()
                                .concatMatrix(1, tanAlpha, 0, 1, 0, 0)
                                .beginText()
                                .resetFillColorGray()
                                .setExtGState(extGState)
                                .moveText(195, 18)
                                //.setFontAndSize(PdfFontFactory.createFont("/static/font/simsun.ttf", "Identity-H"), 10)
                                .setFontAndSize(PdfFontFactory.createFont(fontPath, "Identity-H"), 10)
                                .showText(footerText)
                                .endText()
                                .restoreState();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    } finally {
                        inputStream.close();
                    }
                }
            }

            response.setContentType("application/pdf");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(file1.getName()));
            System.out.println("文件名："+file1.getName());

            // 使用OutputStream将文件的内容写入响应
            try (OutputStream outputStreamRes = response.getOutputStream();
                 FileInputStream inputStreamRes = new FileInputStream(file1)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStreamRes.read(buffer)) != -1) {
                    outputStreamRes.write(buffer, 0, bytesRead);
                }
                outputStreamRes.flush();
                outputStreamRes.close();
            }
            //进行文件签署上传操作
            if(StringUtils.isNotEmpty(batchPrintData.getBatchNo())) {
                //进行汇总文件保存
                //上传文件进行文件保存操作 -- 此时需要将汇总单号和文件进行关系绑定
                //    FileResposeCDTO fileResposeCDTO = fileClient.uploadFile(file);
                ESignFileResposeDTO eSignFileResposeDTO = fileClient.uploadESignFile(file1);
                String fileKey = eSignClient.sendFileClient(eSignFileResposeDTO, fileClient.file2MultipartFile(file1));
                purchaseOrderService.update(
                        new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getColumn1,eSignFileResposeDTO.getId())
                                .set(PurchaseOrder::getColumn2,fileKey)
                                .eq(PurchaseOrder:: getBatchNo,batchPrintData.getBatchNo()));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (TemplateException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean batchPrintPdfCreateNew(PurchaseOrderPrintDTO batchPrintData) {
        //进行文件的生成操作
        String configValue = ResourceUtil.readUtf8Str("view/pc/order/purchaseOrder/batch_print_template_sum.ftl");
        configValue = configValue.replace("<#include \"../../base/base.ftl\">",
                "<#macro formatDateTime dateTime pattern><#if dateTime??><#assign formattedDateTime = " +
                        "dateTime?datetime(\"yyyy-MM-dd'T'HH:mm\")>${formattedDateTime?string(pattern)" +
                        "}</#if></#macro>");
        Template template = null;
        try {
            //需要多个
            template = new Template("emailTemplate", configValue, freemarkerConfig);
            final Map<String, Object> map = Maps.newHashMap();
            map.put("ctx", sysProp.getHostUrl());
            map.put("purchaseOrder", batchPrintData);
            //取朗华的交货地址， 邓京术 2025-07-04
            List<DictDTO> dictDTOS = dictClient.getDicByType("delivery_address_usd");
            dictDTOS.stream().forEach(item ->{
                map.put("deliverAddress" + item.getName(), item.getCode());
            });
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            //创建pdf空文件
            File fileSource = fileClient.createFile(
                    "采购汇总订单-" + batchPrintData.getOrderCode() + "-" + IdWorker.getIdStr() + ".pdf");
            log.info("fileSource{}", fileSource.getPath());
//            PDFUtil.generatePdfFromHtml(html, file.getPath(), true, true);
            log.info("订单汇总生成文件开始");
            System.out.println("文件名："+fileSource.getName());

            OutputStream outputStream = new FileOutputStream(fileSource);
            ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(html.getBytes());
            String fontPath =  "/static/font/msyh.ttc,1";
            PrintOrderCreatePdfUtil.convertToPdf(tInputStringStream, fontPath, outputStream);
            tInputStringStream.close();
            outputStream.close();
//            File file1 = new File(StrUtil.concat(false, fileLogic.genDatePath().getKey(), File.separator, "采购订单-" + purchaseOrderPrintDTO.getOrderCode() + "-" + IdWorker.getIdStr() + ".pdf"));
            File fileReCreate = new File(StrUtil.concat(false, fileLogic.genDatePath().getKey(), File.separator, fileSource.getName()));
            // 再次打开文件并进行处理
            // 使用 PdfReader 和 PdfWriter 进行处理
            InputStream inputStream = new FileInputStream(fileReCreate);
            PdfReader reader = new PdfReader(inputStream);
            PdfWriter writer = new PdfWriter(fileReCreate);
            try (PdfDocument pdfDoc = new PdfDocument(reader, writer)) {
                int numberOfPages = pdfDoc.getNumberOfPages();
                for (int i = 1; i <= numberOfPages; i++) {
                    String footerText = "　　　　　　　　　　　　　　　　　　　　　　　第" + i + "页 共" + numberOfPages  + "页";
                    PdfPage page = pdfDoc.getPage(i);
                    PdfCanvas canvas = new PdfCanvas(page);
                    try {
                        PdfExtGState extGState = new PdfExtGState();
                        extGState.setFillOpacity(1f); // 设置填充透明度为0.05
                        double alpha = Math.toRadians(0); // 倾斜角度
                        double tanAlpha = Math.tan(alpha);
                        //可根据页面宽高设置水印
                        canvas.saveState()
                                .concatMatrix(1, tanAlpha, 0, 1, 0, 0)
                                .beginText()
                                .resetFillColorGray()
                                .setExtGState(extGState)
                                .moveText(195, 18)
                                //.setFontAndSize(PdfFontFactory.createFont("/static/font/simsun.ttf", "Identity-H"), 10)
                                .setFontAndSize(PdfFontFactory.createFont(fontPath, "Identity-H"), 10)
                                .showText(footerText)
                                .endText()
                                .restoreState();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    } finally {
                        inputStream.close();
                    }
                }
            }

            //进行文件签署上传操作
            if(StringUtils.isNotEmpty(batchPrintData.getBatchNo())){
                log.info("订单汇总生成文件数据库上传");
                ESignFileResposeDTO eSignFileResposeDTO = fileClient.uploadESignFile(fileReCreate);
                String fileKey = eSignClient.sendFileClient(eSignFileResposeDTO, fileClient.file2MultipartFile(fileReCreate));
                log.info("订单汇总生成文件key写入订单表");
                purchaseOrderService.update(
                        new LambdaUpdateWrapper<PurchaseOrder>().set(PurchaseOrder::getColumn1,eSignFileResposeDTO.getId())
                                .set(PurchaseOrder::getColumn2,fileKey)
                                .eq(PurchaseOrder:: getBatchNo,batchPrintData.getBatchNo()));
                log.info("订单汇总生成文件key写入订单表成功");
            }
        } catch (IOException e) {
            log.info("订单汇总生成文件失败信息"+e);
            return false;
        } catch (TemplateException e) {
            log.info("订单汇总生成文件失败"+e);
            return false;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    @Override
    public PageView batchPrintList(OrderBatchPrintQuery query) {
        //需要查询订单汇总数据逻辑
        /**
         * 1.订单未打印
         * 2.订单修改在当前的时间范围内
         * 3.订单的状态是待供应商确认、确认完成、收货完成
         * 4.订单的供应商是当前用户所属的供应商
         */
        final String month = query.getMonth();
        if (StrUtil.isNotEmpty(month)) {
            //需要获取当前月份的第一天和最后一天
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.yyyyMMDash);
            final DateTime localDate = DateUtil.parse(month, formatter);
            final Pair<LocalDateTime, LocalDateTime> startAndEndDate = DateUtils.getStartAndEndDate(localDate.year(),
                    localDate.monthBaseOne());
            query.setStart(startAndEndDate.getKey());
            query.setEnd(startAndEndDate.getValue());
        } else {
            //需要获取当前月份的第一天和最后一天
//            final DateTime localDate = new DateTime();
            Calendar cl = Calendar.getInstance();
            cl.add(Calendar.MONTH, -1);
            final DateTime localDate = new DateTime(cl.getTimeInMillis());
            final Pair<LocalDateTime, LocalDateTime> startAndEndDate = DateUtils.getStartAndEndDate(localDate.year(),
                    localDate.monthBaseOne());
            query.setStart(startAndEndDate.getKey());
            query.setEnd(startAndEndDate.getValue());
        }
        // 移至生成打印pdf校验时校验 2025-10-22 陈天仕 删除
//        query.setStatus(Lists.newArrayList(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus(),
//                PurchaseOrderStatus.RECEIPT_COMPLETED.getStatus()));
        if (LoginUtil.isSupplier()) {
            final Pair<Boolean, List<SupplierDTO>> agentList = supplierClient.getAgentList(LoginUtil.getSupplierCode());
            if (!agentList.getKey()) {
                query.setSupplierCode(LoginUtil.getSupplierCode());
            }
        //如果不是供应商默认不查询 2024-11-19 邓京术
        } else if (StrUtil.isEmpty(month)){
            return PageUtil.getPV(new ArrayList<PurchaseOrderBaseDTO>(), 0);
        }
        if (Objects.isNull(query.getPage())) {
            //需要把数据
            List<PurchaseOrder> list = purchaseOrderService.findBatchPrintList(null, query);
            if (StrUtil.isNotEmpty(query.getBatchNo())) {
                for (PurchaseOrder purchaseOrder : list) {
                    purchaseOrder.setBatchNo(query.getBatchNo());
                }
            }
            final List<PurchaseOrderBaseDTO> purchaseOrderListDTOS = purchaseOrderConvert.entities2Dtos1(list);
            return PageUtil.getPV(purchaseOrderListDTOS);
        } else {
            final Page<PurchaseOrder> page = PageUtil.toPage(query);
            //需要把数据
            List<PurchaseOrder> list = purchaseOrderService.findBatchPrintList(page, query);
            if (StrUtil.isNotEmpty(query.getBatchNo())) {
                for (PurchaseOrder purchaseOrder : list) {
                    purchaseOrder.setBatchNo(query.getBatchNo());
                }
            }
            final List<PurchaseOrderBaseDTO> purchaseOrderListDTOS = purchaseOrderConvert.entities2Dtos1(list);
            return PageUtil.getPV(purchaseOrderListDTOS, page.getTotal());
        }

    }

    @Override
    public Long gerPurchaseIdByCode(String purchaseGroupCode) {
        PurchaseOrder purchaseOrder = purchaseOrderService.getIdByCode(purchaseGroupCode);
        return purchaseOrder.getId();
    }

    @Override
    public String getDefaultSupplier() {
        String supplierCode = StrUtil.EMPTY;
        if (LoginUtil.isSupplier()) {
            boolean isAgent = false;
            final Pair<Boolean, List<SupplierDTO>> agentList = supplierClient.getAgentList(LoginUtil.getSupplierCode());
            if (agentList.getKey()) {
                if (CollUtil.isNotEmpty(agentList.getValue())) {
                    final List<SupplierDTO> value = agentList.getValue();
                    final Set<String> collect = value.stream().map(SupplierDTO::getSupplierCode)
                            .collect(Collectors.toSet());
                    if (CollUtil.isNotEmpty(collect)) {
                        isAgent = true;
                        supplierCode = collect.iterator().next();
                    }
                }
            }
            if (!isAgent) {
                supplierCode = LoginUtil.getSupplierCode();
            }
        }
        return supplierCode;
    }

    @Override
    public List<PurchaseOrderBaseDTO> batchPrintListCheck(String orderIds, String month) {
        //需要查询订单汇总数据逻辑
        /**
         * 1.订单未打印
         * 2.订单修改在当前的时间范围内
         * 3.订单的状态是待供应商确认、确认完成、收货完成
         * 4.订单的供应商是当前用户所属的供应商
         */
        OrderBatchPrintQuery query = new OrderBatchPrintQuery();
        final List<String> orderIdList = Arrays.asList(orderIds.split(","));
        query.setIds(orderIdList);
        if (StrUtil.isNotEmpty(month)) {
            //需要获取当前月份的第一天和最后一天
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateUtils.yyyyMMDash);
            final DateTime localDate = DateUtil.parse(month, formatter);
            final Pair<LocalDateTime, LocalDateTime> startAndEndDate = DateUtils.getStartAndEndDate(localDate.year(),
                    localDate.monthBaseOne());
            query.setStart(startAndEndDate.getKey());
            query.setEnd(startAndEndDate.getValue());
        } else {
            //需要获取当前月份的第一天和最后一天  不允许查当月订单，默认取上月的
//            final DateTime localDate = new DateTime();
            Calendar cl = Calendar.getInstance();
            cl.add(Calendar.MONTH, -1);
            final DateTime localDate = new DateTime(cl.getTimeInMillis());
            final Pair<LocalDateTime, LocalDateTime> startAndEndDate = DateUtils.getStartAndEndDate(localDate.year(),
                    localDate.monthBaseOne());
            query.setStart(startAndEndDate.getKey());
            query.setEnd(startAndEndDate.getValue());
        }
        // 移至生成打印pdf校验时校验 2025-10-22 陈天仕 删除
//        query.setStatus(Lists.newArrayList(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus(),
//                PurchaseOrderStatus.RECEIPT_COMPLETED.getStatus()));
        if (LoginUtil.isSupplier()) {
            final Pair<Boolean, List<SupplierDTO>> agentList = supplierClient.getAgentList(LoginUtil.getSupplierCode());
            if (!agentList.getKey()) {
                query.setSupplierCode(LoginUtil.getSupplierCode());
            }
        }

        //需要把数据
        List<PurchaseOrder> list = purchaseOrderService.findBatchPrintListCheck(query);
        if (StrUtil.isNotEmpty(query.getBatchNo())) {
            for (PurchaseOrder purchaseOrder : list) {
                purchaseOrder.setBatchNo(query.getBatchNo());
            }
        }
        List<Long> longOrderIdList = orderIdList.stream()
                .map(Long::parseLong)
                .collect(Collectors.toList());
        List<PurchaseOrder> checkList = purchaseOrderService.list(new LambdaQueryWrapper<PurchaseOrder>().in(PurchaseOrder::getId, longOrderIdList));
        // 未确认校验
        List<String> uncompletedList = Lists.newArrayList();
        for (PurchaseOrder purchaseOrder : checkList) {
            if (!purchaseOrder.getState().equals(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus())) {
                uncompletedList.add(purchaseOrder.getOrderCode());
            }
        }
        if (!CollectionUtils.isEmpty(uncompletedList)) {
            String errorMessage = "采购订单" + String.join(",", uncompletedList) + "，供应商未确认，请先确认后再打印!";
            throw new DaoException(errorMessage);
        }
        final List<PurchaseOrderBaseDTO> purchaseOrderListDTOS = purchaseOrderConvert.entities2Dtos1(list);
        return purchaseOrderListDTOS;
    }

    @Override
    public void clearBatchNo(String batchNo) {
        final List<PurchaseOrderSummary> list = purchaseOrderSummaryService.list(
                new LambdaQueryWrapper<>(PurchaseOrderSummary.class).eq(PurchaseOrderSummary::getCode, batchNo));
        final Set<Long> orderIds = list.stream().map(PurchaseOrderSummary::getOrderId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(orderIds)) {
            purchaseOrderService.update(
                    new LambdaUpdateWrapper<>(PurchaseOrder.class).in(PurchaseOrder::getId, orderIds)
                            .set(PurchaseOrder::getBatchNo, null)
                            .set(PurchaseOrder::getPrintFlag, FlagConst.N.getCode()));
        }
    }

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