package com.sw.mes.yb.production.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.gson.Gson;
import com.sw.mes.base.erp.entity.ErpOrder;
import com.sw.mes.base.erp.service.ErpOrderService;
import com.sw.mes.base.factory.init.service.CrystalMaterialRelationService;
import com.sw.mes.base.factory.inspect.entity.ReturnRecord;
import com.sw.mes.base.factory.material.entity.MaterialModel;
import com.sw.mes.base.factory.material.service.MaterialModelService;
import com.sw.mes.base.system.entity.DictionaryItem;
import com.sw.mes.base.system.entity.SysLog;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.base.system.service.SysLogService;
import com.sw.mes.core.annotation.Jinko;
import com.sw.mes.core.annotation.ServiceLogs;
import com.sw.mes.core.api.materialclean.MaterialCleanFeignClients;
import com.sw.mes.core.api.system.FbFeignClients;
import com.sw.mes.core.api.system.StoreFeignClients;
import com.sw.mes.core.base.BaseServiceImpl;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.DictionaryItemDto;
import com.sw.mes.core.dto.MaterialModelDto;
import com.sw.mes.core.dto.ProductionOrderDto;
import com.sw.mes.core.dto.WarehouseModelDto;
import com.sw.mes.core.dto.erp.ErpAddResultDto;
import com.sw.mes.core.dto.erp.ErpRequestDto;
import com.sw.mes.core.dto.materialCleanDto.MaterialStoreSignBoxDto;
import com.sw.mes.core.dto.mes.pc.fb.FbProductionOrderDto;
import com.sw.mes.core.dto.sap.ReportSapChargItemDto;
import com.sw.mes.core.dto.sap.ReportSapGoodsmvtDto;
import com.sw.mes.core.dto.store.*;
import com.sw.mes.core.dto.wms.*;
import com.sw.mes.core.entity.MesToErpCcpEntity;
import com.sw.mes.core.entity.SearchFilter;
import com.sw.mes.core.enums.*;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultCode;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.response.ResultWms;
import com.sw.mes.core.utils.*;
import com.sw.mes.enumvalue.RecycleTypeEnum;
import com.sw.mes.enumvalue.StockStateEnum;
import com.sw.mes.gread.utils.FormulaUtils;
import com.sw.mes.inspect.service.YbInspectDataService;
import com.sw.mes.rabbitmq.constants.RoutingKey;
import com.sw.mes.rabbitmq.enums.ExchangeEnum;
import com.sw.mes.rabbitmq.enums.QueueEnum;
import com.sw.mes.rabbitmq.service.RabbitMqService;
import com.sw.mes.sap.entity.RecycledReportSapRecord;
import com.sw.mes.sap.entity.ReportSapGoodsmvt;
import com.sw.mes.sap.entity.ReportSapWorkinghours;
import com.sw.mes.sap.service.RecycledReportSapRecordService;
import com.sw.mes.sap.service.ReportSapGoodsmvtService;
import com.sw.mes.sap.service.ReportSapWorkinghoursService;
import com.sw.mes.third.utils.ErpRequestUtil;
import com.sw.mes.utils.ExcelUtil;
import com.sw.mes.wms.service.WMSOutputService;
import com.sw.mes.yb.accessory.dto.EquipmentAccessoryExportDto;
import com.sw.mes.yb.accessory.dto.RecycledMaterialInDto;
import com.sw.mes.yb.plan.entity.ProductionOrder;
import com.sw.mes.yb.plan.entity.ProductionSchedule;
import com.sw.mes.yb.plan.service.ProductionOrderService;
import com.sw.mes.yb.plan.service.ProductionScheduleService;
import com.sw.mes.yb.production.dao.RecycledMaterialManageDao;
import com.sw.mes.yb.production.dto.RecycledMaterialManageDetailDto;
import com.sw.mes.yb.production.dto.RecycledMaterialManageDetailExportDto;
import com.sw.mes.yb.production.dto.RecycledMaterialManageDto;
import com.sw.mes.yb.production.entity.LongCrystal;
import com.sw.mes.yb.production.entity.RecycledMaterialManage;
import com.sw.mes.yb.production.entity.RecycledMaterialManageDetail;
import com.sw.mes.yb.production.service.*;
import com.sw.mes.yb.production.utils.RecycledBatchGenerator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: xushu
 * @Date: 2022/08/17/16:24
 * @Description:
 */
@Service
@Transactional
@Slf4j
public class RecycledMaterialManageServiceImpl extends BaseServiceImpl<RecycledMaterialManage> implements RecycledMaterialManageService {
    RecycledMaterialManageDao dao;
    @Autowired
    public void setDao(RecycledMaterialManageDao dao) {
        super.setBaseDao(dao);
        this.dao=dao;
    }
    @Autowired
    RecycledMaterialManageDetailService recycledMaterialManageDetailService;
    @Autowired
    ModelMapper modelMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RabbitMqService rabbitMqService;
    @Autowired
    private DictionaryItemService dictionaryItemService;
    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private LongCrystalService longCrystalService;

    @Autowired
    private LoadingTaskService loadingTaskService;

    @Autowired
    private AgainTaskDetailService againTaskDetailService;

    @Autowired
    private YbInspectDataService ybInspectDataService;

    @Autowired
    private MaterialModelService materialModelService;
    @Autowired
    private ProductionScheduleService productionScheduleService;

    @Autowired
    private MaterialCleanFeignClients materialCleanFeignClients;

    @Autowired
    private ErpOrderService erpOrderService;
    @Value("${spring.erpServiceUrl}")
    private String erpServiceUrl;
    @Autowired
    private ErpRequestUtil erpRequestUtil;
    @Autowired
    private ProductionOrderService productionOrderService;
    @Autowired
    private FbFeignClients fbFeignClients;

    @Autowired
    private StoreFeignClients storeFeignClients;

    @Autowired
    private ReportSapGoodsmvtService reportSapGoodsmvtService;

    @Autowired
    private RecycledReportSapRecordService recycledReportSapRecordService;

    @Autowired
    private WMSOutputService wmsInputService;

    @Autowired
    private CrystalMaterialRelationService crystalMaterialRelationService;

    @Autowired
    private RecycledBatchGenerator recycledBatchGenerator;

    @Autowired
    private SurplusInfoService surplusInfoService;

    @Value("${spring.profiles.active}")
    private String active;

    //TODO 设置wms api
    @Value("${spring.wmsServiceUrl}")
    private String wmsServiceUrl;

    private final String recycleToWms = "/api/InboundRecycledMaterial";


    @Override
    public void softDeleteById(Long id) {
        dao.softDeleteById(id);
    }


    @Override
    public void exportExcel(HttpServletRequest request, HttpServletResponse resp) throws  Exception{
        SearchFilter filter = new SearchFilter("del", SearchFilter.Operator.EQ,0);//查询未删除的列表
        Specification<RecycledMaterialManage> specification = DynamicSpecifications.bySearchFilter(request, RecycledMaterialManage.class,filter);
        //主表
        List<RecycledMaterialManage> recycledMaterialManages = findByExampleSort(specification, Sort.by(Sort.Direction.ASC,  "id"));
        List<DictionaryItem> productCategoryItems = dictionaryItemService.findByThemeValueAndEnable("product_category",true);
//        List<DictionaryItem> factoryCateItems = dictionaryItemService.findByThemeValueAndEnable("FactoryCate",true);
//        List<DictionaryItem> gearItems = dictionaryItemService.findByThemeValueAndEnable("Gear",true);
        //附表
        List<RecycledMaterialManageDetailExportDto> recycledMaterialManageDetailExportDtos = new ArrayList<>();
        for(RecycledMaterialManage recycledMaterialManage : recycledMaterialManages){
            List<RecycledMaterialManageDetail> recycledMaterialManageDetails = recycledMaterialManageDetailService.getDetailByManageId(recycledMaterialManage.getId());
            if(null == recycledMaterialManageDetails || recycledMaterialManageDetails.isEmpty()){
                RecycledMaterialManageDetailExportDto recycledMaterialManageDetailExportDto = modelMapper.map(recycledMaterialManage,RecycledMaterialManageDetailExportDto.class);
                List<String> productionTypeNames = productCategoryItems.stream().filter(temp->temp.getValue().equals(recycledMaterialManageDetailExportDto.getProductionCategory())).map(DictionaryItem::getName).collect(Collectors.toList());
                if(productionTypeNames.size()>0){
                    recycledMaterialManageDetailExportDto.setProductionCategory(productionTypeNames.get(0));
                }
                recycledMaterialManageDetailExportDtos.add(recycledMaterialManageDetailExportDto);
                continue;
            }
            for(RecycledMaterialManageDetail recycledMaterialManageDetail : recycledMaterialManageDetails){
                RecycledMaterialManageDetailExportDto recycledMaterialManageDetailExportDto = modelMapper.map(recycledMaterialManage,RecycledMaterialManageDetailExportDto.class);
                List<String> productionTypeNames = productCategoryItems.stream().filter(temp->temp.getValue().equals(recycledMaterialManageDetailExportDto.getProductionCategory())).map(DictionaryItem::getName).collect(Collectors.toList());
                if(productionTypeNames.size() >0 ){
                    recycledMaterialManageDetailExportDto.setProductionCategory(productionTypeNames.get(0));
                    recycledMaterialManageDetailExportDto.setProductionType(productionTypeNames.get(0));
                }
//                recycledMaterialManageDetailExportDtos.add(recycledMaterialManageDetailExportDto);
                recycledMaterialManageDetailExportDto.setRecycleNo(recycledMaterialManageDetail.getRecycleNo());
                recycledMaterialManageDetailExportDto.setProductLevel(recycledMaterialManageDetail.getProductLevel());
                recycledMaterialManageDetailExportDto.setStatus(StockStateEnum.getDescByCode(recycledMaterialManage.getStatus()));
                recycledMaterialManageDetailExportDto.setErpOrder(recycledMaterialManage.getErpOrder());
                recycledMaterialManageDetailExportDtos.add(recycledMaterialManageDetailExportDto);

            }
        }
        if(recycledMaterialManageDetailExportDtos.isEmpty()){
            throw new  BusinessException("无匹配数据");
        }
        try {
            EasyExcelUtils.write(resp, RecycledMaterialManageDetailExportDto.class, "回收料管理", "回收料管理", recycledMaterialManageDetailExportDtos);
        } catch (Exception e) {
            e.printStackTrace();
            throw new  BusinessException("导出异常");
        }
    }

    @Override
    public Integer countTimeByParam(String key) {
        return dao.countTimeByParam(key);
    }

    @Override
    public BigDecimal findTiZhaGaiByLotNo(String lotNo) {
        return dao.findTiZhaGaiByLotNo(lotNo);
    }

    @Override
    public BigDecimal findTiJianLiaoByLotNo(String lotNo) {
        return dao.findTiJianLiaoByLotNo(lotNo);
    }

    @Override
    public BigDecimal findGuoDiLiaoByLotNo(String lotNo) {
        return dao.findDunGuoLiaoByLotNo(lotNo);
    }

    @Override
    public BigDecimal findDunGuoLiaoByLotNo(String lotNo) {
        return dao.findDunGuoLiaoByLotNo(lotNo);
    }

    @Override
    public void recycledMaterialIn(RecycledMaterialManageDto recycledMaterialManageDto) {

        //回收料管理的数据应存到待清洗表中
        MaterialStoreSignBoxDto materialStoreSignBoxDto = new MaterialStoreSignBoxDto();
        materialStoreSignBoxDto.setWeight(recycledMaterialManageDto.getWeight());
        materialStoreSignBoxDto.setMaterialCode(recycledMaterialManageDto.getMaterialCode());
        materialStoreSignBoxDto.setMaterialName(recycledMaterialManageDto.getMaterialName());
        materialStoreSignBoxDto.setMaterialLevel(recycledMaterialManageDto.getGrade());
        materialStoreSignBoxDto.setMaterialModel(recycledMaterialManageDto.getSpecification());
        materialStoreSignBoxDto.setMaterialGear(recycledMaterialManageDto.getGear());
        materialStoreSignBoxDto.setCreateUser(recycledMaterialManageDto.getCreateBy());
        materialStoreSignBoxDto.setCreateTime(Instant.ofEpochMilli(recycledMaterialManageDto.getCreateTime().getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime());
        materialStoreSignBoxDto.setUpdateUser(recycledMaterialManageDto.getUpdateBy());
        materialStoreSignBoxDto.setUpdateTime(Instant.ofEpochMilli(recycledMaterialManageDto.getUpdateTime().getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime());
        materialStoreSignBoxDto.setAufnr(recycledMaterialManageDto.getErpOrder());
        materialStoreSignBoxDto.setBoxNo(recycledMaterialManageDto.getBoxNo());
        materialStoreSignBoxDto.setPickingStatus(0);
        materialStoreSignBoxDto.setMaterialType(2);
        materialStoreSignBoxDto.setErpWarehouseCode(recycledMaterialManageDto.getErpWarehouseCode());
        //新增托号，托号用回收料管理模块中的托号
        materialStoreSignBoxDto.setTrayNo(recycledMaterialManageDto.getTrayNo());
        //批次号用回收料管理模块中的批次号
        materialStoreSignBoxDto.setProductBatchNo(recycledMaterialManageDto.getProduceBatchNo());

        Result result = materialCleanFeignClients.create(materialStoreSignBoxDto);
        if (result.getCode() != ResultCode.SUCCESS.getCode()) {
            throw new BusinessException("调用清洗原料接收:[materialStoreSignBox/create]失败: " + result.getMessage());
        }
        RecycledMaterialInDto recycledMaterialInDto;
        String url = wmsServiceUrl + recycleToWms;
        //不可回收料，入库
        if (recycledMaterialManageDto.getRecycledMaterialType().equals("不可用回收料")) {
            recycledMaterialInDto = buildNonRecycledMaterialInDto(recycledMaterialManageDto);
            if ("prod".equals(active)) {

                ResultWms resultJson = requestRecycleMaterialToWMS(url, recycledMaterialInDto, "不可用回收料入库到WMS");
                if (null != resultJson) {
                    if (!resultJson.getCode().equals("1")) {
                        throw new BusinessException("入库到wms失败,请求接口失败");
                    }
                } else {
                    throw new BusinessException("入库到wms失败,请求接口异常");
                }
            }
            //可回收料,重量>0，入库
        } else if (recycledMaterialManageDto.getRecycledMaterialType().equals("可用回收料")) {
            if (null != recycledMaterialManageDto.getWeight() && recycledMaterialManageDto.getWeight().compareTo(BigDecimal.ZERO) > 0) {
                recycledMaterialInDto = buildRecycledMaterialInDto(recycledMaterialManageDto);
                if ("prod".equals(active)) {

                    ResultWms resultJson = requestRecycleMaterialToWMS(url, recycledMaterialInDto, "可用回收料过账到WMS,发起到清洗原料车间");
                    if (null != resultJson) {
                        if (!resultJson.getCode().equals("1")) {
                            throw new BusinessException("入库到wms失败,请求接口失败");
                        }
                    } else {
                        throw new BusinessException("入库到wms失败,请求接口异常");
                    }
                }
            }

        } else {
            //todo:循环料现在未过回收料
        }
//        String url = wmsServiceUrl+recycleToWms;
//        ResultWms resultJson = requestRecycleMaterialToWMS(url,recycledMaterialInDto,"可回收料入库到WMS");
//        if(null != resultJson) {
//            if (!resultJson.getCode().equals("1")) {
//                throw new BusinessException("入库到wms失败,请求接口失败");
//            }
//        }else{
//            throw new BusinessException("入库到wms失败,请求接口异常");
//        }

    }

    @Override
    public void recycledMaterialIn(RecycledMaterialManageDto recycledMaterialManageDto, String hasGone) {

        if ("WMS".equals(hasGone)) {

            RecycledMaterialInDto recycledMaterialInDto;
            String url = wmsServiceUrl + recycleToWms;
            //不可回收料，入库
            if (recycledMaterialManageDto.getRecycledMaterialType().equals("不可用回收料")) {
                recycledMaterialInDto = buildNonRecycledMaterialInDto(recycledMaterialManageDto);
                if ("prod".equals(active)) {

                    ResultWms resultJson = requestRecycleMaterialToWMS(url, recycledMaterialInDto, "不可用回收料入库到WMS");
                    if (null != resultJson) {
                        if (!resultJson.getCode().equals("1")) {
                            throw new BusinessException("入库到wms失败,请求接口失败");
                        }
                    } else {
                        throw new BusinessException("入库到wms失败,请求接口异常");
                    }
                }
                //可回收料,重量>0，入库
            } else if (recycledMaterialManageDto.getRecycledMaterialType().equals("可用回收料")) {
                if (null != recycledMaterialManageDto.getWeight() && recycledMaterialManageDto.getWeight().compareTo(BigDecimal.ZERO) > 0) {
                    recycledMaterialInDto = buildRecycledMaterialInDto(recycledMaterialManageDto);
                    if ("prod".equals(active)) {

                        ResultWms resultJson = requestRecycleMaterialToWMS(url, recycledMaterialInDto, "可用回收料过账到WMS,发起到清洗原料车间");
                        if (null != resultJson) {
                            if (!resultJson.getCode().equals("1")) {
                                throw new BusinessException("入库到wms失败,请求接口失败");
                            }
                        } else {
                            throw new BusinessException("入库到wms失败,请求接口异常");
                        }
                    }
                }

            } else {
                //todo:循环料现在未过回收料
            }
        } else {
            //回收料管理的数据应存到待清洗表中
            MaterialStoreSignBoxDto materialStoreSignBoxDto = new MaterialStoreSignBoxDto();
            materialStoreSignBoxDto.setWeight(recycledMaterialManageDto.getWeight());
            materialStoreSignBoxDto.setMaterialCode(recycledMaterialManageDto.getMaterialCode());
            materialStoreSignBoxDto.setMaterialName(recycledMaterialManageDto.getMaterialName());
            materialStoreSignBoxDto.setMaterialLevel(recycledMaterialManageDto.getGrade());
            materialStoreSignBoxDto.setMaterialModel(recycledMaterialManageDto.getSpecification());
            materialStoreSignBoxDto.setMaterialGear(recycledMaterialManageDto.getGear());
            materialStoreSignBoxDto.setCreateUser(recycledMaterialManageDto.getCreateBy());
            materialStoreSignBoxDto.setCreateTime(Instant.ofEpochMilli(recycledMaterialManageDto.getCreateTime().getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime());
            materialStoreSignBoxDto.setUpdateUser(recycledMaterialManageDto.getUpdateBy());
            materialStoreSignBoxDto.setUpdateTime(Instant.ofEpochMilli(recycledMaterialManageDto.getUpdateTime().getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime());
            materialStoreSignBoxDto.setAufnr(recycledMaterialManageDto.getErpOrder());
            materialStoreSignBoxDto.setBoxNo(recycledMaterialManageDto.getBoxNo());
            materialStoreSignBoxDto.setPickingStatus(0);
            materialStoreSignBoxDto.setMaterialType(2);
            materialStoreSignBoxDto.setErpWarehouseCode(recycledMaterialManageDto.getErpWarehouseCode());
            //新增托号，托号用回收料管理模块中的托号
            materialStoreSignBoxDto.setTrayNo(recycledMaterialManageDto.getTrayNo());
            //批次号用回收料管理模块中的批次号
            materialStoreSignBoxDto.setProductBatchNo(recycledMaterialManageDto.getProduceBatchNo());

            Result result = materialCleanFeignClients.create(materialStoreSignBoxDto);
            if (result.getCode() != ResultCode.SUCCESS.getCode()) {
                throw new BusinessException("调用清洗原料接收:[materialStoreSignBox/create]失败: " + result.getMessage());
            }
        }
    }

    /**
     * 余料发起入库到线边仓
     *
     * @param recycledMaterialManage 回收料数据
     * @param reason                 入库原因
     * @return 入库单号
     */
    @Override
    public String startSurplusWarehousing(RecycledMaterialManage recycledMaterialManage, String reason) {
        try {
            //通过计划工单中的片区field4找到字典中的成品仓
            String workOrderNo = recycledMaterialManage.getWorkOrderNo();
            String warehouseCode = getWareHouseCodeByWorkOrderNo(workOrderNo);
            String factoryWorkTypeName = getFactoryWorkTypeNameByWorkOrderNo(workOrderNo);
            factoryWorkTypeName = factoryWorkTypeName + RecycleCleanSAPEnum.余料.getDesc();
            //调线边仓
            WarehouseInputBillBo warehouseInputBillBo = newInputBill(recycledMaterialManage, reason, warehouseCode);
            Result<String> result = storeFeignClients.automaticInputOut(warehouseInputBillBo);
            Integer code = result.getCode();
            String data = result.getData();
            if (code != 200 || StringUtils.isBlank(data)) {
                throw new BusinessException("余料入库失败，状态码：" + code + "，反馈信息：" + result.getMessage());
            } else {
                //1 回收料产出报工SAP
                String finalWarehouseCode = warehouseCode;
                try {
                    //拉晶成本中心的,报详情到sap,批次号用日批次号;
                    // 业务说明仓位都一致
                    if ("2".equals(recycledMaterialManage.getKostl())) {
                        List<RecycledMaterialManageDetail> recycledMaterialManageDetailDtos = recycledMaterialManageDetailService.getDetailByManageId(recycledMaterialManage.getId());
                        if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
                            for (RecycledMaterialManageDetail detail : recycledMaterialManageDetailDtos) {
                                this.handleReportSapGoodsmvtDto(recycledMaterialManage.getMaterialCategory(),detail.getWorkOrderNo(), recycledMaterialManage.getMaterialCode(), recycledMaterialManage.getDateProduceBatchNo(), detail.getWeight(), recycledMaterialManage.getUnitName(), finalWarehouseCode, factoryWorkTypeName);
                            }
                        }
                    } else {
                        this.handleReportSapGoodsmvtDto(recycledMaterialManage.getMaterialCategory(),workOrderNo, recycledMaterialManage.getMaterialCode(), recycledMaterialManage.getDateProduceBatchNo(), recycledMaterialManage.getWeight(), recycledMaterialManage.getUnitName(), finalWarehouseCode, factoryWorkTypeName);
                    }
                } catch (Exception e) {
                    log.error("余料上报异常:" + e.getMessage());
                }
            }
            return data;
        } catch (Exception e) {
            throw new BusinessException("余料入库异常，" + e.getMessage());
        }
    }

    /**
     * 通过工单号获取成品仓库位
     *
     * @param workOrderNo 计划工单
     * @return
     */
    @Jinko(author = "yyl", value = "通过工单号获取库位")
    private String getWareHouseCodeByWorkOrderNo(String workOrderNo) {
        //通过计划工单中的片区field4找到字典中的成品仓
        ProductionOrder productionOrder = productionOrderService.findByAufnr(workOrderNo);
        String field4 = null;
        String warehouseCode = "";
        if (null == productionOrder) {
            throw new BusinessException(workOrderNo + "工单不存在!");
        } else {
            field4 = productionOrder.getField4();
        }
        if (null != field4) {
            DictionaryItem warehouseLocation = dictionaryItemService.findNameByThemeValueAndItemValue("ByProductWarehouseLocation", field4);
            if (null != warehouseLocation) {
                    warehouseCode = warehouseLocation.getExtendValue1();
            }else {
                throw new BusinessException("关键字[ByProductWarehouseLocation]中的[工作中心编码]: " + field4 + " 未配置");
            }
        }
        return warehouseCode;
    }

    /**
     * 通过工单号获取对应成本中心名称
     * 硅料1
     * 拉晶2
     * 截断3
     * 刀剖4
     * 籽晶5
     *
     * @param workOrderNo 工单号
     * @return
     */
    @Jinko(author = "yyl", value = "通过工单号获取对应成本中心名称")
    private String getFactoryWorkTypeNameByWorkOrderNo(String workOrderNo) {
        ProductionOrder productionOrder = productionOrderService.findByAufnr(workOrderNo);
        if (null == productionOrder) {
            throw new BusinessException(workOrderNo + "工单不存在!");
        }
        String workType = String.valueOf(productionOrder.getWorkType());
        //查询成本中心名称
        String typeName = "";
        DictionaryItem factoryWorkTypeName = dictionaryItemService.findNameByThemeValueAndItemValueAndEnable("factoryWorkType", workType, true);
        if (null != factoryWorkTypeName) {
            typeName = factoryWorkTypeName.getName();
        } else {
            log.error("关键字[factoryWorkType]中的[词条值]: " + workType + " 未配置");
        }
        return typeName;
    }

    @Override
    public RecycledMaterialManage getByProduceBatchNo(String produceBatchNo) {
        return dao.getByProduceBatchNo(produceBatchNo);
    }

    /**
     * 废料入库到线边仓(并线边仓退料到wms)
     *
     * @param recycledMaterialManage
     * @param reason
     * @return
     */
    @Override
    public String startSurplusToWMS(RecycledMaterialManage recycledMaterialManage, String reason) {
        try {
            //通过计划工单中的片区field4找到字典中的成品仓
            String workOrderNo = recycledMaterialManage.getWorkOrderNo();
            String warehouseCode = getWareHouseCodeByWorkOrderNo(workOrderNo);
            if ("2".equals(recycledMaterialManage.getKostl())) {
                //拉晶成本中心的废料,直接入库到P31G或者P32G
                //找出对应库位关系
                DictionaryItem warehouseLocation = dictionaryItemService.findNameByThemeValueAndItemName("ScrapAllotWarehouse", warehouseCode);
                if (null != warehouseLocation) {
                    warehouseCode = warehouseLocation.getValue();
                } else {
                    throw new BusinessException("关键字[ScrapAllotWarehouse]中的[原始库位]: " + warehouseCode + " 未配置对应信息");
                }
            }
            String factoryWorkTypeName = getFactoryWorkTypeNameByWorkOrderNo(workOrderNo);
            factoryWorkTypeName = factoryWorkTypeName + "余料";
            //调线边仓,废料成品入库并上报SAP(线边仓退料到wms)
            WarehouseInputBillBo warehouseInputBillBo = newFlInputBill(recycledMaterialManage, reason, warehouseCode);
            Result<String> result = storeFeignClients.inputApply(warehouseInputBillBo);
            Integer code = result.getCode();
            String data = result.getData();
            if (code != 200 || StringUtils.isBlank(data)) {
                throw new BusinessException("废料入库失败，状态码：" + code + "，反馈信息：" + result.getMessage());
            } else {
                //1 回收料产出报工SAP
                String finalWarehouseCode = warehouseCode;
                try {
                    //拉晶成本中心的,报详情到sap,批次号用日批次号;
                    // 业务说明仓位都一致
                    if ("2".equals(recycledMaterialManage.getKostl())) {
                        List<RecycledMaterialManageDetail> recycledMaterialManageDetailDtos = recycledMaterialManageDetailService.getDetailByManageId(recycledMaterialManage.getId());
                        if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
                            for (RecycledMaterialManageDetail detail : recycledMaterialManageDetailDtos) {
                                this.handleReportSapGoodsmvtDto(recycledMaterialManage.getMaterialCategory(),detail.getWorkOrderNo(), recycledMaterialManage.getMaterialCode(), recycledMaterialManage.getDateProduceBatchNo(), detail.getWeight(), recycledMaterialManage.getUnitName(), finalWarehouseCode, factoryWorkTypeName);
                            }
                        }
                    } else {
                        this.handleReportSapGoodsmvtDto(recycledMaterialManage.getMaterialCategory(),workOrderNo, recycledMaterialManage.getMaterialCode(), recycledMaterialManage.getDateProduceBatchNo(), recycledMaterialManage.getWeight(), recycledMaterialManage.getUnitName(), finalWarehouseCode, factoryWorkTypeName);
                    }
                } catch (Exception e) {
                    log.error("废料上报异常:" + e.getMessage());
                }
            }
            return data;
        } catch (Exception e) {
            throw new BusinessException("废料入库到线边仓并由线边仓退库到wms异常，" + e.getMessage());
        }
    }

   /* @Override
    @ServiceLogs(description = "余料采集卡控工单超收")
    public Result checkOrderWeight(String orderNo, String workType, BigDecimal addWeight) {
        *//**
         *  卡控公式:
         * 	硅料1:	待确认
         *  拉晶2: 长晶棒产出+余料采集重量/(王小龙提供对应sql)配料记录重量+灌料记录重量<= 字典配置值
         * 	截断3: 圆棒检验数据库理论重量(是否反切为否0)+余料采集重量/长晶棒产出的重量<= 字典配置值
         * 	刀剖4: 方棒检验数据库理论重量(是否反切为否0)+余料采集重量/圆棒检验数据库理论重量(是否反切为否0)<= 字典配置值
         * 	籽晶5:	待确认
         *//*
        //查询对应字典以及配置 开启状态 RecycledWeightCheck 词条
        DictionaryItem dictionaryItem = dictionaryItemService.findNameByThemeValueAndItemValueAndEnable("RecycledWeightCheck", String.valueOf(workType), true);

        if (null == dictionaryItem) {
            //未开启对应工作中心余料超收卡控
            log.info("字典关键字RecycledWeightCheck的对应词条code:{}未开启,不进行工单{}重量超收卡控", workType, orderNo);
            return ResultGenerator.success();
        } else {
            //投入重量
            BigDecimal inputWeight = BigDecimal.ONE;
            //产出重量
            BigDecimal outputWeight = BigDecimal.ZERO;
            //字典配置超收比例
            String rate = dictionaryItem.getExtendValue();
            BigDecimal rateResult = NumberUtil.Object2BigDecimal(rate);
            if (rateResult == null) {
                log.info("字典关键字RecycledWeightCheck的对应词条code:{}的超收比例{}异常", workType, rate);
                return ResultGenerator.fail("【" + rate + "】计算结果转换成数字发生错误,请检查字典关键字RecycledWeightCheck词条配置!");
            }

            switch (workType) {
                case "1":
                    //待确定
                    break;
                case "2":
                    BigDecimal longCrystalSumWeight = longCrystalService.findSumWeightByOrderNo(orderNo);
                    BigDecimal recycledDetailSumWeight = recycledMaterialManageDetailService.findSumWeightByWorkOrderNo(orderNo);
                    BigDecimal totalTaskSumWeight = againTaskDetailService.findTotalSumWeightBySapNoAndInRawStatus(orderNo);
                    outputWeight = longCrystalSumWeight.add(recycledDetailSumWeight).add(addWeight);
                    inputWeight = totalTaskSumWeight;
                    break;
                case "3":
                    BigDecimal ybSumWeight = ybInspectDataService.findSumWeightByOrderNoAndIsCutBack(orderNo, 0);
                    BigDecimal recycledSumWeight = dao.findSumWeightByWorkOrderNo(orderNo);
                    BigDecimal longCrystalTotalWeight = longCrystalService.findSumWeightByOrderNo(orderNo);
                    outputWeight = ybSumWeight.add(recycledSumWeight).add(addWeight);
                    inputWeight = longCrystalTotalWeight;
                    break;
                case "4":
                    BigDecimal fbSumWeight = BigDecimal.ZERO;
                    Result<String> result = fbFeignClients.findSumWeightByOrderNoAndBackCut(orderNo, 0);
                    if (null != result && ResultCode.SUCCESS.getCode() == result.getCode() && null != result.getData()) {
                        fbSumWeight = new BigDecimal(result.getData());
                    } else {
                        log.info("统计工单" + orderNo + "刀剖产出查询异常!");
                        return ResultGenerator.fail("统计工单" + orderNo + "刀剖产出查询异常!");
                    }
                    BigDecimal recycledTotalWeight = dao.findSumWeightByWorkOrderNo(orderNo);
                    BigDecimal ybDataSumWeight = ybInspectDataService.findSumWeightByOrderNoAndIsCutBack(orderNo, 0);
                    outputWeight = fbSumWeight.add(recycledTotalWeight).add(addWeight);;
                    inputWeight = ybDataSumWeight;
                    break;
                case "5":
                    //待确定
                    break;
            }
            if (inputWeight.compareTo(BigDecimal.ZERO) < 1) {
                log.info("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
                return ResultGenerator.fail("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
            }
            //订单实际物料产出/投入 比例
            BigDecimal actualRate = outputWeight.divide(inputWeight, 6, BigDecimal.ROUND_HALF_UP);
            if (actualRate.compareTo(rateResult) > 0) {
                log.info("工单" + orderNo + "的产出:" + outputWeight + "投入:" + inputWeight + "比例计算结果:" + actualRate + "大于超收比例:" + rateResult);
                return ResultGenerator.fail("工单" + orderNo + "的产出:" + outputWeight + "投入:" + inputWeight + "比例计算结果:" + actualRate + "大于超收比例:" + rateResult);
            } else {
                return ResultGenerator.success();
            }
        }
    }
*/

//    @Override
//    @ServiceLogs(description = "余料采集卡控工单超收")
//    public Result checkOrderWeight(String orderNo, String workType, BigDecimal addWeight) {
//        /**
//         * todo:公式有更改,只卡控副产品(收集重量)与投入的比例值
//         * 截断余料：工单余料总重量<消耗*百分比（数据字典配置）
//         * 截断消耗取值：截断加工记录中的毛棒编号，查划线记录中的晶体重量
//         * 刀剖余料：工单余料总重量<消耗*百分比（数据字典配置）
//         * 刀剖消耗取值：刀剖加工记录的晶编，查圆棒检验数据库中的理论重量、
//         */
//        //查询对应字典以及配置 开启状态 RecycledWeightCheck 词条
//        DictionaryItem dictionaryItem = dictionaryItemService.findNameByThemeValueAndItemValueAndEnable("RecycledWeightCheck", String.valueOf(workType), true);
//
//        if (null == dictionaryItem) {
//            //未开启对应工作中心余料超收卡控
//            log.info("字典关键字RecycledWeightCheck的对应词条code:{}未开启,不进行工单{}重量超收卡控", workType, orderNo);
//            return ResultGenerator.success();
//        } else {
//            //投入重量
//            BigDecimal inputWeight = BigDecimal.ONE;
//            //余料副产品产出重量
//            BigDecimal outputWeight = BigDecimal.ZERO;
//            //字典配置超收比例
//            String rate = dictionaryItem.getExtendValue();
//            BigDecimal rateResult = NumberUtil.Object2BigDecimal(rate);
//            if (rateResult == null) {
//                log.info("字典关键字RecycledWeightCheck的对应词条code:{}的超收比例{}异常", workType, rate);
//                return ResultGenerator.fail("【" + rate + "】计算结果转换成数字发生错误,请检查字典关键字RecycledWeightCheck词条配置!");
//            }
//
//            switch (workType) {
//                case "1":
//                    //待确定
//                    break;
//                case "2":
//                    BigDecimal recycledDetailSumWeight = recycledMaterialManageDetailService.findSumWeightByWorkOrderNo(orderNo);
//                    BigDecimal totalTaskSumWeight = againTaskDetailService.findTotalSumWeightBySapNoAndInRawStatus(orderNo);
//                    outputWeight = recycledDetailSumWeight.add(addWeight);
//                    inputWeight = totalTaskSumWeight;
//                    break;
//                case "3":
//                    BigDecimal recycledSumWeight = dao.findSumWeightByWorkOrderNo(orderNo);
//                    //良正提供截断消耗投入
//                    BigDecimal jdTotalWeight = crystalMaterialRelationService.findJdSumWeightByOrderNo(orderNo);
//                    outputWeight = recycledSumWeight.add(addWeight);
//                    inputWeight = jdTotalWeight;
//                    break;
//                case "4":
//                    BigDecimal fbSumWeight = BigDecimal.ZERO;
//                    Result<String> result = fbFeignClients.findSumWeightByOrderNoAndBackCut(orderNo, 0);
//                    if (null != result && ResultCode.SUCCESS.getCode() == result.getCode() && null != result.getData()) {
//                        fbSumWeight = new BigDecimal(result.getData());
//                    } else {
//                        log.info("统计工单" + orderNo + "刀剖产出查询异常!");
//                        return ResultGenerator.fail("统计工单" + orderNo + "刀剖产出查询异常!");
//                    }
//                    BigDecimal recycledTotalWeight = dao.findSumWeightByWorkOrderNo(orderNo);
//                    BigDecimal dpSumWeightByOrderNo = crystalMaterialRelationService.findDpSumWeightByOrderNo(orderNo);
//                    outputWeight = recycledTotalWeight.add(addWeight);
//                    ;
//                    inputWeight = dpSumWeightByOrderNo;
//                    break;
//                case "5":
//                    //待确定
//                    break;
//            }
//            if (inputWeight.compareTo(BigDecimal.ZERO) < 1) {
//                log.info("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
//                return ResultGenerator.fail("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
//            }
//            //订单实际物料产出/投入 比例
//            BigDecimal actualRate = outputWeight.divide(inputWeight, 6, BigDecimal.ROUND_HALF_UP);
//            if (actualRate.compareTo(rateResult) > 0) {
//                log.info("工单" + orderNo + "的产出:" + outputWeight + "投入:" + inputWeight + "比例计算结果:" + actualRate + "大于超收比例:" + rateResult);
//                return ResultGenerator.fail("工单" + orderNo + "的产出:" + outputWeight + "投入:" + inputWeight + "比例计算结果:" + actualRate + "大于超收比例:" + rateResult);
//            } else {
//                return ResultGenerator.success();
//            }
//        }
//    }


    /**
     * 第四版本需求
     * 校验订单重量是否超出允许范围。
     * 该方法用于在进行余料采集时，根据不同的成本中心类型（工作中心类型），校验订单的重量是否超出了允许的范围。
     * 具体的校验逻辑根据不同的工作中心类型取值于SAP上报记录表，并与字典中配置的超收比例进行比较。
     *
     * @param orderNo   订单号，用于标识需要校验的订单。
     * @param workType  成本中心类型，用于确定订单属于哪种类型的成本中心，进而采用不同的校验逻辑。
     * @param addWeight 准备收集的订单重量，即待添加的余料重量。
     * @return 返回一个结果对象，如果订单重量未超出允许范围，则返回成功；否则返回失败，并给出相应的错误信息。
     */
    @Override
    @ServiceLogs(description = "余料采集卡控工单超收")
    public Result checkOrderWeight(String orderNo, String workType, BigDecimal addWeight) {
        /**
         * 校验逻辑：余料采集时重量录入，工单校验逻辑：取值为sap上报记录表。
         * 工序名称为：
         * 1硅料工单：(硅料收货的重量+硅料清洗余料的重量)/硅料清洗分选的重量<99%
         * 2单晶工单:(单晶收货的重量+拉晶余料的重量)/单晶消耗的重量<99%
         * 3截断工单：(截断收货的重量+截断余料的重量)/截断消耗的重量<99%
         * 4刀剖工单：(刀剖收货的重量+刀剖余料的重量)/刀剖消耗的重量<99%
         * 5籽晶工单：(籽晶收货的重量+籽晶余料的重量)/籽晶消耗的重量<99%
         */
        //查询对应字典以及配置 开启状态 RecycledWeightCheck 词条
        System.out.println("------" + workType);
        DictionaryItem dictionaryItem = dictionaryItemService.findNameByThemeValueAndItemValueAndEnable("RecycledWeightCheck", String.valueOf(workType), true);

        if (null == dictionaryItem) {
            //未开启对应工作中心余料超收卡控
            log.info("字典关键字RecycledWeightCheck的对应词条code:{}未开启,不进行工单{}重量超收卡控", workType, orderNo);
            return ResultGenerator.success();
        } else {
            //投入重量
            BigDecimal inputWeight = BigDecimal.ONE;
            //产出重量
            BigDecimal outputWeight = BigDecimal.ZERO;
            //消耗的重量
            BigDecimal consumeSumWeight = BigDecimal.ZERO;
            //消耗的冲销重量
            BigDecimal subConsumeSumWeight = BigDecimal.ZERO;
            //主产品的收货重量
            BigDecimal mainProductSumWeight = BigDecimal.ZERO;
            //主产品的收货冲销重量
            BigDecimal subMainProductSumWeight = BigDecimal.ZERO;
            //副产品的收货重量
            BigDecimal byProductSumWeight = BigDecimal.ZERO;
            //副产品的收货冲销重量
            BigDecimal subByProductSumWeight = BigDecimal.ZERO;
            //字典配置超收比例
            String rate = dictionaryItem.getExtendValue();
            BigDecimal rateResult = NumberUtil.Object2BigDecimal(rate);
            if (rateResult == null) {
                log.info("字典关键字RecycledWeightCheck的对应词条code:{}的超收比例{}异常", workType, rate);
                return ResultGenerator.fail("【" + rate + "】计算结果转换成数字发生错误,请检查字典关键字RecycledWeightCheck词条配置!");
            }

            switch (workType) {
                case "1":
                    //硅料消耗
                    consumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料消耗.getValue(), EnumValuesFactory.SapProgress.硅料消耗.getKey(), orderNo);
                    subConsumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料消耗冲销.getValue(), EnumValuesFactory.SapProgress.硅料消耗冲销.getKey(), orderNo);
                    //硅料收货的重量
                    mainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料收货.getValue(), EnumValuesFactory.SapProgress.硅料收货.getKey(), orderNo);
                    subMainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料收货冲销.getValue(), EnumValuesFactory.SapProgress.硅料收货冲销.getKey(), orderNo);
                    //硅料副产品的重量
                    byProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料余料收货.getValue(), EnumValuesFactory.SapProgress.硅料余料收货.getKey(), orderNo);
                    subByProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.硅料余料收货冲销.getValue(), EnumValuesFactory.SapProgress.硅料余料收货冲销.getKey(), orderNo);

                    outputWeight = mainProductSumWeight.add(subMainProductSumWeight).add(byProductSumWeight).add(subByProductSumWeight).add(addWeight);
                    inputWeight = consumeSumWeight.add(subConsumeSumWeight);
                    break;
                case "2":
                    //拉晶消耗
                    consumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.拉晶消耗.getValue(), EnumValuesFactory.SapProgress.拉晶消耗.getKey(), orderNo);
                    subConsumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.拉晶消耗冲销.getValue(), EnumValuesFactory.SapProgress.拉晶消耗冲销.getKey(), orderNo);
                    //单晶收货的重量
                    mainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.单晶收货.getValue(), EnumValuesFactory.SapProgress.单晶收货.getKey(), orderNo);
                    subMainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.单晶收货冲销.getValue(), EnumValuesFactory.SapProgress.单晶收货冲销.getKey(), orderNo);
                    //拉晶副产品的重量
                    byProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.拉晶余料收货.getValue(), EnumValuesFactory.SapProgress.拉晶余料收货.getKey(), orderNo);
                    subByProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.拉晶余料收货冲销.getValue(), EnumValuesFactory.SapProgress.拉晶余料收货冲销.getKey(), orderNo);

                    outputWeight = mainProductSumWeight.add(subMainProductSumWeight).add(byProductSumWeight).add(subByProductSumWeight).add(addWeight);
                    inputWeight = consumeSumWeight.add(subConsumeSumWeight);
                    break;
                case "3":
                    //截断消耗
                    consumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断消耗.getValue(), EnumValuesFactory.SapProgress.截断消耗.getKey(), orderNo);
                    subConsumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断消耗冲销.getValue(), EnumValuesFactory.SapProgress.截断消耗冲销.getKey(), orderNo);
                    //截断收货的重量
                    mainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断收货.getValue(), EnumValuesFactory.SapProgress.截断收货.getKey(), orderNo);
                    subMainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断收货冲销.getValue(), EnumValuesFactory.SapProgress.截断收货冲销.getKey(), orderNo);
                    //截断副产品的重量
                    byProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断余料收货.getValue(), EnumValuesFactory.SapProgress.截断余料收货.getKey(), orderNo);
                    subByProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.截断余料收货冲销.getValue(), EnumValuesFactory.SapProgress.截断余料收货冲销.getKey(), orderNo);

                    outputWeight = mainProductSumWeight.add(subMainProductSumWeight).add(byProductSumWeight).add(subByProductSumWeight).add(addWeight);
                    inputWeight = consumeSumWeight.add(subConsumeSumWeight);
                    break;
                case "4":
                    //刀剖消耗
                    consumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖消耗.getValue(), EnumValuesFactory.SapProgress.刀剖消耗.getKey(), orderNo);
                    subConsumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖消耗冲销.getValue(), EnumValuesFactory.SapProgress.刀剖消耗冲销.getKey(), orderNo);
                    //截断收货的重量
                    mainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖收货.getValue(), EnumValuesFactory.SapProgress.刀剖收货.getKey(), orderNo);
                    subMainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖收货冲销.getValue(), EnumValuesFactory.SapProgress.刀剖收货冲销.getKey(), orderNo);
                    //截断副产品的重量
                    byProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖余料收货.getValue(), EnumValuesFactory.SapProgress.刀剖余料收货.getKey(), orderNo);
                    subByProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.刀剖余料收货冲销.getValue(), EnumValuesFactory.SapProgress.刀剖余料收货冲销.getKey(), orderNo);

                    outputWeight = mainProductSumWeight.add(subMainProductSumWeight).add(byProductSumWeight).add(subByProductSumWeight).add(addWeight);
                    inputWeight = consumeSumWeight.add(subConsumeSumWeight);
                    break;
                case "5":
                    //籽晶消耗
                    consumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶消耗.getValue(), EnumValuesFactory.SapProgress.籽晶消耗.getKey(), orderNo);
                    subConsumeSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶消耗冲销.getValue(), EnumValuesFactory.SapProgress.籽晶消耗冲销.getKey(), orderNo);
                    //截断收货的重量
                    mainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶收货.getValue(), EnumValuesFactory.SapProgress.籽晶收货.getKey(), orderNo);
                    subMainProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶收货冲销.getValue(), EnumValuesFactory.SapProgress.籽晶收货冲销.getKey(), orderNo);
                    //截断副产品的重量
                    byProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶余料收货.getValue(), EnumValuesFactory.SapProgress.籽晶余料收货.getKey(), orderNo);
                    subByProductSumWeight = reportSapGoodsmvtService.findSumWeightByProcNameAndBwartAndOrderNo(EnumValuesFactory.SapProgress.籽晶余料收货冲销.getValue(), EnumValuesFactory.SapProgress.籽晶余料收货冲销.getKey(), orderNo);

                    outputWeight = mainProductSumWeight.add(subMainProductSumWeight).add(byProductSumWeight).add(subByProductSumWeight).add(addWeight);
                    inputWeight = consumeSumWeight.add(subConsumeSumWeight);
                    break;
            }
            if (inputWeight.compareTo(BigDecimal.ZERO) < 1) {
                log.info("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
                return ResultGenerator.fail("统计工单" + orderNo + "的投入查询结果值:" + inputWeight + "异常!");
            }
            //订单实际物料产出/投入 比例
            BigDecimal actualRate = outputWeight.divide(inputWeight, 6, BigDecimal.ROUND_HALF_UP);
            if (actualRate.compareTo(rateResult) > 0) {
                log.info("工单" + orderNo + "的产出是:" + outputWeight + "与投入:" + inputWeight + "比例计算结果为:" + actualRate + ",大于超收比例:" + rateResult);
                return ResultGenerator.fail("工单" + orderNo + "的产出是:" + outputWeight + "与投入:" + inputWeight + "比例计算结果为:" + actualRate + "大于超收比例:" + rateResult);
            } else {
                return ResultGenerator.success();
            }
        }
    }

    @Override
    public Result checkRecycledMaterialManageDtoOrderWeight(RecycledMaterialManageDto recycledMaterialManageDto) {
        List<RecycledMaterialManageDetailDto> recycledMaterialManageDetailDtos = recycledMaterialManageDto.getRecycledMaterialMangeDetailDtos();
        String kostl = recycledMaterialManageDto.getKostl();
        if (StringUtils.isNotBlank(kostl) && "2".equals(kostl) && null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
            //有详情,并且成本中心是2,说明是拉晶 需要先统计每种工单准备累加余料的总量,再校验
            Map<String, BigDecimal> collect = recycledMaterialManageDetailDtos.stream()
                    .collect(Collectors.groupingBy(
                            RecycledMaterialManageDetailDto::getWorkOrderNo,
                            Collectors.reducing(
                                    BigDecimal.ZERO,
                                    RecycledMaterialManageDetailDto::getWeight,
                                    BigDecimal::add
                            )
                    ));
            // 优化逻辑：检查所有工单号
            Result overallResult = ResultGenerator.success();
            for (String key : collect.keySet()) {
                Result result = checkOrderWeight(key, "2", collect.get(key));
                if (ResultCode.SUCCESS.getCode() != result.getCode()) {
                    overallResult = result; // 记录第一个失败的结果
                    break; // 如果有失败，不再继续检查其他工单
                }
            }
            return overallResult;
        } else {
            Result result = checkOrderWeight(recycledMaterialManageDto.getWorkOrderNo(), recycledMaterialManageDto.getKostl(), recycledMaterialManageDto.getWeight());
            return result;
        }
    }


    @SneakyThrows
    @Override
    public String importExcel(MultipartFile file) {
        Map<String, List<Map<String, Object>>> excelMap = null;
        try {
            excelMap = ExcelUtil.getExcelInfo(file);
        } catch (Exception e) {
            throw new RuntimeException("文件导入异常！" + e.getMessage());
        }
        StringBuilder stringBuilder=new StringBuilder();
        if (!excelMap.isEmpty()) {
            Collection<List<Map<String, Object>>> collection = excelMap.values();
            Iterator<List<Map<String, Object>>> iterator = collection.iterator();
            while (iterator.hasNext()) {
                List<Map<String, Object>> list = iterator.next();
                //将读取到的list做去空处理，解决因为表格编辑软件、版本不同造成的问题
                list.removeIf(map -> "null".equals(String.valueOf(map.get("序号"))) || "".equals(String.valueOf(map.get("序号"))));

                for (Map<String, Object> map : list) {
                    RecycledMaterialManage recycledMaterialManage = new RecycledMaterialManage();
                    String row = String.valueOf(map.get("序号"));
                    //当行号为空跳过这行
                    if ("null".equals(row) || "".equals(row)) {
                        stringBuilder.append("第"+ row +"行序号不能为空！");
//                        throw new RuntimeException("第"+ row +"行序号不能为空！");
                    }
                    if(StringUtils.isEmpty(String.valueOf(map.get("回收料类型")).trim())){
                        stringBuilder.append("第"+ row +"行 回收料类型不能为空！");
//                        throw new RuntimeException("第"+ row +"行 回收料类型不能为空！");
                    }
                    recycledMaterialManage.setRecycledMaterialType(String.valueOf(map.get("回收料类型")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("来源")).trim())){
                        stringBuilder.append("第"+ row +"行 来源不能为空！");
//                        throw new RuntimeException("第"+ row +"行 来源不能为空！");
                    }
                    recycledMaterialManage.setSource(String.valueOf(map.get("来源")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("产品类型")).trim())){
                        stringBuilder.append("第"+ row +"行 产品类型不能为空！");
//                        throw new RuntimeException("第"+ row +"行 产品类型不能为空！");
                    }
                    recycledMaterialManage.setProductionCategory(String.valueOf(map.get("产品类型")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("等级")).trim())){
                        stringBuilder.append("第"+ row +"行 等级不能为空！");
//                        throw new RuntimeException("第"+ row +"行 等级不能为空！");
                    }
                    recycledMaterialManage.setGrade(String.valueOf(map.get("等级")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("档位")).trim())){
                        stringBuilder.append("第"+ row +"行 档位不能为空！");
//                        throw new RuntimeException("第"+ row +"行 档位不能为空！");
                    }
                    recycledMaterialManage.setGear(String.valueOf(map.get("档位")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("厂区")).trim())){
                        stringBuilder.append("第"+ row +"行 厂区不能为空！");
//                        throw new RuntimeException("第"+ row +"行 厂区不能为空！");
                    }
                    recycledMaterialManage.setFactory(String.valueOf(map.get("厂区")).trim());
                    recycledMaterialManage.setStatus(1);
                    recycledMaterialManage.setCreateBy(BaseContextHandler.getUsername());
                    if(StringUtils.isEmpty(String.valueOf(map.get("组拖时间")).trim())){
                        stringBuilder.append("第"+ row +"行 组拖时间不能为空！");
//                        throw new RuntimeException("第"+ row +"行 组拖时间不能为空！");
                    }
                    try {
                        Date checkTime1 = DateUtil.toDate(String.valueOf(map.get("组拖时间")).trim(), "yyyy-MM-dd HH:mm:ss");
                        recycledMaterialManage.setCreateTime(new Date());
                    } catch (Exception e) {
                        stringBuilder.append("第"+ row +"行  时间格式错误！");
//                        throw new Exception("第"+ row +"行  时间格式错误！");
                    }
                    String lotNo = String.valueOf(map.get("炉次号")).trim();
                    if(StringUtils.isEmpty(lotNo)){
                       // stringBuilder.append("第"+ row +"行 炉次号不能为空！");
//                        throw new RuntimeException("第"+ row +"行 炉次号不能为空！");
                    }
                    //导入的炉次号，需要查询圆棒工单（【圆棒生产域—订单管理】生产工单(排程表) ）表炉次是否存在，不存在提示错误出来
                    ProductionSchedule longCrystal=productionScheduleService.findDataByLotNo(lotNo);
                    if(null==longCrystal){
                      //  stringBuilder.append("第"+ row +"行 炉次号"+ lotNo +"在圆棒工单中不存在！");
//                        throw new RuntimeException("第"+ row +"行 炉次号"+ lotNo +"在长晶棒检验中不存在！");
                    }
                    recycledMaterialManage.setLotNo(String.valueOf(map.get("炉次号")).trim());
                    if(StringUtils.isEmpty(String.valueOf(map.get("物料名称")).trim())){
                        stringBuilder.append("第"+ row +"行 物料名称不能为空！");
//                        throw new RuntimeException("第"+ row +"行 物料名称不能为空！");
                    }
                    recycledMaterialManage.setMaterialName(String.valueOf(map.get("物料名称")).trim());
                    String code = materialModelService.findCodeByName(String.valueOf(map.get("物料名称")).trim());
                    if (StringUtils.isEmpty(code)) {
                        stringBuilder.append("第" + row + "行 物料名称对应编号不存在！");
//                        throw new RuntimeException("第" + row + "行 物料名称对应编号不存在！");
                    }
                    recycledMaterialManage.setMaterialCode(code);
                    if (StringUtils.isEmpty(String.valueOf(map.get("重量")).trim())) {
                        stringBuilder.append("第" + row + "行 重量不能为空！");
//                        throw new RuntimeException("第" + row + "行 重量不能为空！");
                    }
                    try {
                        recycledMaterialManage.setWeight(new BigDecimal(String.valueOf(map.get("重量")).trim()).setScale(2, BigDecimal.ROUND_HALF_UP));
                    } catch (Exception e) {
                        e.printStackTrace();
                        stringBuilder.append("第" + row + "行 重量字段格式异常:"+String.valueOf(map.get("重量")).trim());
                    }
//                    recycledMaterialManage.setReceiver(String.valueOf(map.get("接收人")).trim());
//                    recycledMaterialManage.setReceiveTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(String.valueOf(map.get("接收时间")).trim()));
                    String sheetStock = String.valueOf(map.get("片料")).trim();
                    if (StringUtils.isEmpty(sheetStock) || "null".equalsIgnoreCase(sheetStock)) {
                        sheetStock = "";
                    } else if (!"片料".equals(sheetStock)) {
                        stringBuilder.append("不允许填写除片料和空的其他类型!");
//                        throw new BusinessException("不允许填写除片料和空的其他类型!");
                    }
                    recycledMaterialManage.setSheetStock(sheetStock);

//                    String boxNo = String.valueOf(map.get("料箱号")).trim();
//                    recycledMaterialManage.setBoxNo(boxNo);
//                    if (StringUtils.isEmpty(boxNo)) {
//                        stringBuilder.append("第" + row + "行 对应料箱号不存在！");
////                        throw new RuntimeException("第" + row + "行 物料名称对应编号不存在！");
//                    }
                    //生成托号
                    String trayNo = creatTrayNo(recycledMaterialManage, sheetStock);
                    RecycledMaterialManage entity = dao.findByTrayNo(trayNo);
                    if (null != entity) {
                        stringBuilder.append("第" + row + "行托号已存在");
//                        throw new RuntimeException("第" + row + "行托号已存在");
                    }
                    recycledMaterialManage.setTrayNo(trayNo);
                    if (StringUtils.isEmpty(String.valueOf(map.get("ERP工单")).trim())) {
                        stringBuilder.append("第" + row + "行 ERP工单不能为空！");
                    }
                    recycledMaterialManage.setErpOrder(String.valueOf(map.get("ERP工单")).trim());

                    if(StringUtils.isNotBlank(stringBuilder.toString())){
                        return stringBuilder.toString();
                    }
                    this.saveOrUpdate(recycledMaterialManage);
                }
            }
        }
        if(StringUtils.isNotBlank(stringBuilder.toString())){
            throw new RuntimeException(stringBuilder.toString());
        }
        return null;
    }

    @Override
    public void updateRecycledManageWeight(String materialBoxNo, BigDecimal weight) {
        dao.updateRecycledManageWeight(materialBoxNo,weight);
    }

    @Override
    public RecycledMaterialManage getByBoxNoAndStatus(String materialBoxNo) {
        return dao.getByBoxNoAndStatus(materialBoxNo);
    }


    @Override
    public RecycledMaterialManage getByBoxNo(String boxNo) {
        return dao.getByBoxNo(boxNo);
    }

    @Override
    public Result reportedErp(RecycledMaterialManageDto recycledMaterialManageDto) {
        Date date = new Date();
        RecycledMaterialManage recycledMaterialManage = get(recycledMaterialManageDto.getId());
        if (null == recycledMaterialManage) {
            return ResultGenerator.fail("回收料原信息不存在");
        }
//        // 已接收
//        if(StockStateEnum.RECEIVED.getCode() != recycledMaterialManage.getStatus()){
//            return ResultGenerator.fail(recycledMaterialManage.getSource() + "回收料当前不处于已接收状态,不能进行上报ERP操作：" + recycledMaterialManage.getTrayNo());
//        }
        // 待出库
//        if(!StockStateEnum.TOBEOUT.getCode().equals(recycledMaterialManage.getStatus())){
//            return ResultGenerator.fail(recycledMaterialManage.getSource() + "回收料当前不处于待出库状态,不能进行上报ERP操作：" + recycledMaterialManage.getTrayNo());
//        }
        if(null == recycledMaterialManage.getReportedState() || EnumValues.ReportedErp.未上报.getKey() != recycledMaterialManage.getReportedState()){
            return ResultGenerator.fail(recycledMaterialManage.getSource() + "回收料当前不处于未上报状态,不能进行上报ERP操作：" + recycledMaterialManage.getTrayNo());
        }
        if(recycledMaterialManage.getWeight().doubleValue() < 0){
            return ResultGenerator.fail(recycledMaterialManage.getSource() + "回收料当前重量小于0,不能进行上报ERP操作：" + recycledMaterialManage.getTrayNo());
        }
        // todo 上报成功后，更改上报状态

        MesToErpCcpEntity mesToErpCcpEntity = new MesToErpCcpEntity();

        // "cbatch": "(2)2023-8-16/129BP(A)正泰045", --批号
        mesToErpCcpEntity.setCbatch(recycledMaterialManage.getProduceBatchNo());
//        mesToErpCcpEntity.setCbatch(recycledMaterialManage.getMaterialCode() + "HSL");
        // "iquantity": "1.0000000000", --数量	同种订单产品合并汇总后的数量
        mesToErpCcpEntity.setIquantity(String.valueOf(recycledMaterialManage.getWeight()));
        // "cinvcode": "100100180103",  回收料中的物料编号
        mesToErpCcpEntity.setCinvcode(recycledMaterialManage.getMaterialCode());
        if("单晶".equals(recycledMaterialManageDto.getSource())) {
            mesToErpCcpEntity.setErpType(ErpPypeEnum.单晶回收料.getKey());
            // "cwhcode": "315", --仓库编码	从订单，常规：315，研发：316
            mesToErpCcpEntity.setCwhcode("029");
            recycledMaterialManage.setErpWarehouseCode("029");
            // "crdcode": "10216", --出库类别/收发类别	常规：10216，研发：10201
            mesToErpCcpEntity.setCrdcode("10220");

            // "cwhname": "回收原料库", --仓库名称  todo 无
            mesToErpCcpEntity.setCwhname("回收料入库单库位");

            ProductionOrder productionOrder = productionOrderService.findByAufnr(recycledMaterialManageDto.getErpOrder());
            if(null != productionOrder){
                // "iproorderid": "1000009317", --生产订单id	从订单获取
                mesToErpCcpEntity.setIproorderid(productionOrder.getTid());

                // "cmpocode": "2308011408-12吋(BNE01A1)(正泰045)", --订单号     合并汇总用的订单：erpOrderNo
                mesToErpCcpEntity.setCmpocode(productionOrder.getAufnr());
                if(productionOrder.getField1().equals("一车间")){
                    mesToErpCcpEntity.setCdepcode("1201");
                } else if (productionOrder.getField1().equals("二车间")){
                    mesToErpCcpEntity.setCdepcode("1206");
                }
//                if(StringUtils.isEmpty(productionOrder.getField1())){
//                    String substring = productionOrder.getAufnr().substring(10, 11);
//                    if("5".equals(substring)){
//                        // "cdepname": "开方五车间",--部门名称	从订单获取   todo
//                        mesToErpCcpEntity.setCdepname("单晶五车间（三期）");
//                        // "cdepcode": "1413", --部门编码	从订单获取
//                        mesToErpCcpEntity.setCdepcode("1413");
//                    } else {
//                        mesToErpCcpEntity.setCdepname("单晶六车间（三期）");
//                        // "cdepcode": "1413", --部门编码	从订单获取
//                        mesToErpCcpEntity.setCdepcode("1417");
//                    }
//                } else {
//                    if("五车间".equals(productionOrder.getField1())){
//                        // "cdepname": "开方五车间",--部门名称	从订单获取   todo
//                        mesToErpCcpEntity.setCdepname("单晶五车间（三期）");
//                        // "cdepcode": "1413", --部门编码	从订单获取
//                        mesToErpCcpEntity.setCdepcode("1413");
//                    } else {
//                        mesToErpCcpEntity.setCdepname("单晶六车间（三期）");
//                        // "cdepcode": "1413", --部门编码	从订单获取
//                        mesToErpCcpEntity.setCdepcode("1417");
//                    }
//                }
                List<MaterialModel> materialModelByCode = materialModelService.findMaterialModelByCode(productionOrder.getMatnr());
                if(!materialModelByCode.isEmpty()){
                    MaterialModel materialModel = materialModelByCode.get(0);
                    // 材料名称  产成品使用母建，回收料使用子健 新增  cinvname
                    mesToErpCcpEntity.setCinvname(materialModel.getName());
                    //  单位 产成品使用母建，回收料使用子健 新增   cinvm_unit
                    mesToErpCcpEntity.setCinvm_unit(materialModel.getUnit().getCode());
                }
                List<ErpOrder> byModIdAndInvCode1 = erpOrderService.findByModIdAndInvCode1(productionOrder.getModid(), productionOrder.getAufnr());
                if(!byModIdAndInvCode1.isEmpty()){
                    ErpOrder erpOrder = byModIdAndInvCode1.get(0);
                    // 生产订单行号,目前填写1 产成品使用母建，回收料使用子健 新增  imoseq
                    mesToErpCcpEntity.setImoseq(NumberUtil.object2String(erpOrder.getImoseq(),null));
                    // 子建行号,目前填写1 产成品使用母建，回收料使用子健 新增    irowno
                    mesToErpCcpEntity.setIrowno(NumberUtil.object2String(erpOrder.getIrowno(),null));
                }
                // 规格型号 产成品使用母建，回收料使用子健 新增 cinsted
//            mesToErpCcpEntity.setCinsted(fbProductionOrder.get);

                // 应入库数量，取订单数量 产成品使用母建，回收料使用子健 新增 inquantity todo 不确定
                mesToErpCcpEntity.setInquantity(NumberUtil.object2String(productionOrder.getMenge(),null));

                // 入库记录ID 先不进行填写进行调试 产成品使用母建，回收料使用子健 新增 impoids todo
//            mesToErpCcpEntity.setImpoids();

                // 是否关联副产品 先不进行填写进行调试 产成品使用母建，回收料使用子健 新增    brelated
//            mesToErpCcpEntity.setBre  lated();

                // 生产订单号 产成品使用母建，回收料使用子健 新增     cmocode
                mesToErpCcpEntity.setCmocode(productionOrder.getAufnr());
            }
        }   else if("截断及开方".equals(recycledMaterialManageDto.getSource())) {
            mesToErpCcpEntity.setErpType(ErpPypeEnum.机加回收料.getKey());
            FbProductionOrderDto fbProductionOrderDto = new FbProductionOrderDto();
            fbProductionOrderDto.setAufnr(recycledMaterialManageDto.getErpOrder());
            Result<FbProductionOrderDto> result = fbFeignClients.findByAufnr(fbProductionOrderDto);
            FbProductionOrderDto fbProductionOrderDto1 = null;
            if(null != result && ResultCode.SUCCESS.getCode() == result.getCode() && null != result.getData()){
                fbProductionOrderDto1 = result.getData();
            }
            // "cwhcode": "315", --仓库编码	从订单，常规：315，研发：316
            mesToErpCcpEntity.setCwhcode("013");
            recycledMaterialManage.setErpWarehouseCode("013");
            // "crdcode": "10216", --出库类别/收发类别	常规：10216，研发：10201
            mesToErpCcpEntity.setCrdcode("10204");
            // "cdepcode": "1413", --部门编码	从订单获取
            mesToErpCcpEntity.setCdepcode("1202");
            // "cwhname": "回收原料库", --仓库名称
            mesToErpCcpEntity.setCwhname("开方产成品库（三期）");
            // "cdepname": "开方五车间",--部门名称	从订单获取
            mesToErpCcpEntity.setCdepname("开方一车间");
            if(null != fbProductionOrderDto1){
                // "iproorderid": "1000009317", --生产订单id	从订单获取 todo
//                mesToErpCcpEntity.setIproorderid(fbProductionOrderDto1.gett);
                // "cmpocode": "2308011408-12吋(BNE01A1)(正泰045)", --订单号     合并汇总用的订单：erpOrderNo
                mesToErpCcpEntity.setCmpocode(fbProductionOrderDto1.getAufnr());


                List<MaterialModel> materialModelByCode = materialModelService.findMaterialModelByCode(fbProductionOrderDto1.getMatnr());
                if(!materialModelByCode.isEmpty()){
                    MaterialModel materialModel = materialModelByCode.get(0);
                    // 材料名称  产成品使用母建，回收料使用子健 新增  cinvname
                    mesToErpCcpEntity.setCinvname(materialModel.getName());
                    //  单位 产成品使用母建，回收料使用子健 新增   cinvm_unit
                    mesToErpCcpEntity.setCinvm_unit(materialModel.getUnit().getCode());
                }
                List<ErpOrder> byModIdAndInvCode1 = erpOrderService.findByModIdAndInvCode1(fbProductionOrderDto1.getModid(), fbProductionOrderDto1.getAufnr());
                if(!byModIdAndInvCode1.isEmpty()){
                    ErpOrder erpOrder = byModIdAndInvCode1.get(0);
                    // 生产订单行号,目前填写1 产成品使用母建，回收料使用子健 新增  imoseq
                    mesToErpCcpEntity.setImoseq(NumberUtil.object2String(erpOrder.getImoseq(),null));
                    // 子建行号,目前填写1 产成品使用母建，回收料使用子健 新增    irowno
                    mesToErpCcpEntity.setIrowno(NumberUtil.object2String(erpOrder.getIrowno(),null));
                    // todo 过滤子件料号
                }
                // 规格型号 产成品使用母建，回收料使用子健 新增 cinsted
//            mesToErpCcpEntity.setCinsted(fbProductionOrder.get);

                // 应入库数量，取订单数量 产成品使用母建，回收料使用子健 新增 inquantity todo 不确定
                mesToErpCcpEntity.setInquantity(NumberUtil.object2String(fbProductionOrderDto1.getMenge(),null));

                // 入库记录ID 先不进行填写进行调试 产成品使用母建，回收料使用子健 新增 impoids todo
//            mesToErpCcpEntity.setImpoids();

                // 是否关联副产品 先不进行填写进行调试 产成品使用母建，回收料使用子健 新增    brelated
//            mesToErpCcpEntity.setBrelated();

                // 生产订单号 产成品使用母建，回收料使用子健 新增     cmocode
                mesToErpCcpEntity.setCmocode(fbProductionOrderDto1.getAufnr());
            }
        }
        mesToErpCcpEntity.setDocTime(recycledMaterialManage.getUpdateTime());
        ErpRequestDto erpRequestDto = new ErpRequestDto();
        erpRequestDto.setMesToErpCcpEntity(mesToErpCcpEntity);
        erpRequestDto.setUrl(erpServiceUrl);
        ErpAddResultDto erpAddResultDto = erpRequestUtil.postToErp(erpRequestDto);
        if(null == erpAddResultDto || !erpAddResultDto.getErrcode().equals(String.valueOf(ResultCode.SUCCESS.getCode()))){
            throw new RuntimeException("回收料上报失败：" + JSONObject.toJSONString(erpAddResultDto.getErrmsg()));
        }

        recycledMaterialManage.setReportedState(EnumValues.ReportedErp.已上报.getKey());
        recycledMaterialManage.setErpOrder(erpAddResultDto.getCcode());
        recycledMaterialManage.setErpTime(date);
        saveOrUpdate(recycledMaterialManage);
        return ResultGenerator.success();
    }

    /**
     * 生成托号
     *
     * @param recycledMaterialManageDto
     * @param sheetStock                片料
     * @return
     */
    private String creatTrayNo(RecycledMaterialManage recycledMaterialManageDto, String sheetStock) {
        //厂区车间
        //String factory = recycledMaterialManageDto.getFactory();
        //todo:三期暂时写死 3
        String factory = "3";
        if (com.sw.mes.core.utils.StringUtils.isNotBlank(recycledMaterialManageDto.getProductionCategory())) {
            factory = factory + "-" + recycledMaterialManageDto.getProductionCategory();
        }
        String today = LocalDate.now().toString();
        String key = "(" + factory + ")" + today;
        Integer times = this.countTimeByParam(key) + 1;
        String materialName = recycledMaterialManageDto.getMaterialName();
        String grade = recycledMaterialManageDto.getGrade();
        if (com.sw.mes.core.utils.StringUtils.isNotBlank(recycledMaterialManageDto.getGear())) {
            grade = grade + "-" + recycledMaterialManageDto.getGear();
        }
        String materialTypeValue = null;
        if (com.sw.mes.core.utils.StringUtils.isBlank(materialName)) {
            throw new BusinessException("请输入物料名称!");
        } else {
            materialTypeValue = dictionaryItemService.findValueByThemeValueAndItemName("ReduceTypeName", materialName);
        }
        String trayNo = key + "/" + times + materialTypeValue + "(" + grade + ")" + sheetStock;

        return trayNo;
    }

    private RecycledMaterialInDto buildNonRecycledMaterialInDto(RecycledMaterialManageDto recycledMaterialManageDto) {
        RecycledMaterialInDto recycledMaterialInDto = new RecycledMaterialInDto();
        recycledMaterialInDto.setBatchNo(recycledMaterialManageDto.getTrayNo());
        recycledMaterialInDto.setInQty(recycledMaterialManageDto.getWeight());
        recycledMaterialInDto.setLevelID(recycledMaterialManageDto.getGrade());
        recycledMaterialInDto.setMaterialClassID("2");
        recycledMaterialInDto.setMaterialNo(recycledMaterialManageDto.getMaterialCode());
        recycledMaterialInDto.setOperateDT(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        recycledMaterialInDto.setOperator(BaseContextHandler.getUsername());
        recycledMaterialInDto.setOutQty(new BigDecimal("0"));
        recycledMaterialInDto.setPlanNo(recycledMaterialManageDto.getTrayNo());
        recycledMaterialInDto.setRemark(null);
        recycledMaterialInDto.setSpecification(recycledMaterialManageDto.getSpecification());
        recycledMaterialInDto.setUnit(recycledMaterialManageDto.getUnitName());
        return recycledMaterialInDto;
    }

    private RecycledMaterialInDto buildRecycledMaterialInDto(RecycledMaterialManageDto recycledMaterialManageDto) {
        RecycledMaterialInDto recycledMaterialInDto = new RecycledMaterialInDto();
        recycledMaterialInDto.setBatchNo(recycledMaterialManageDto.getTrayNo());
        recycledMaterialInDto.setInQty(recycledMaterialManageDto.getWeight());
        recycledMaterialInDto.setLevelID(recycledMaterialManageDto.getGrade());
        if(recycledMaterialManageDto.getRecycledMaterialType().equals("可用回收料")){
            recycledMaterialInDto.setMaterialClassID("3");
        }else{
            recycledMaterialInDto.setMaterialClassID("1");
        }
        recycledMaterialInDto.setMaterialNo(recycledMaterialManageDto.getMaterialCode());
        recycledMaterialInDto.setOperateDT(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        recycledMaterialInDto.setOperator(BaseContextHandler.getUsername());
        recycledMaterialInDto.setOutQty(recycledMaterialManageDto.getWeight());
        recycledMaterialInDto.setPlanNo(recycledMaterialManageDto.getTrayNo());
        recycledMaterialInDto.setRemark(null);
        recycledMaterialInDto.setSpecification(recycledMaterialManageDto.getSpecification());
        recycledMaterialInDto.setUnit(recycledMaterialManageDto.getUnitName());
        return recycledMaterialInDto;
    }

    private ResultWms requestRecycleMaterialToWMS(String url, RecycledMaterialInDto recycledMaterialInDto, String requestName) {
        String resultJson;
        boolean isErr = false;
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
            headers.setContentType(mediaType);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            List<RecycledMaterialInDto> recycledMaterialInDtos =new ArrayList<>();
            recycledMaterialInDtos.add(recycledMaterialInDto);
            HttpEntity<List<RecycledMaterialInDto>> httpEntity = new HttpEntity<>(recycledMaterialInDtos, headers);
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
            resultJson = responseEntity.getBody();
        } catch (Exception e){
            e.printStackTrace();
            resultJson = e.getMessage();
            isErr = true;
        }
        try{
            SysLog syslog = new SysLog();
            syslog.setCreateTime(new Date());
            syslog.setType("info");
            syslog.setCreateUserId(BaseContextHandler.getUserID());
            syslog.setCreateUserName("SYSTEM");
            syslog.setContent(JSON.toJSONString(recycledMaterialInDto));
            syslog.setResult(resultJson);
            syslog.setMethodName("requestRecycleMaterialToWMS()");
            syslog.setStatus(1);
            syslog.setName(requestName);
            syslog.setServerAddr(url);
            syslog.setReqType("HTTP");
            syslog.setReqIp(IpUtils.getLocalIP());
            sysLogService.save(syslog);
            //rabbitMqService.sendMessage(JSONObject.toJSONString(syslog), ExchangeEnum.SYS_LOG_EXCHANGE, QueueEnum.SYS_LOG_QUEUE, RoutingKey.SYS_LOG_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (isErr){
            return null;
        }else {
            return JSON.parseObject(resultJson, new TypeReference<ResultWms>(){});
        }


    }


    /**
     * 封装 回收料入库信息
     *
     * @param manage 回收料信息
     * @param reason 入库原因
     * @param warehouseCode 库位编码
     * @return
     */
    private WarehouseInputBillBo newInputBill(RecycledMaterialManage manage, String reason,String warehouseCode) {
        WarehouseInputBillBo inputBill = new WarehouseInputBillBo();
        inputBill.setType(RecycleTypeEnum.余料入库.getDesc());
        inputBill.setRemark(reason);
        inputBill.setWarehouseCode(warehouseCode);
        inputBill.setAutoAudit(true);
        inputBill.setAutomaticOut(false);
        //入库物料明细
        List<WarehouseInputBillDetailBo> inputBillDetails = new ArrayList<>();
        WarehouseInputBillDetailBo dto = new WarehouseInputBillDetailBo();

        //组装物料明细数据
        dto.setDateProduceBatchNo(manage.getDateProduceBatchNo());
        dto.setBatchNo(manage.getProduceBatchNo());
        dto.setCrystalNo(manage.getDateProduceBatchNo());
        dto.setSupplier("太原晶科");
        dto.setSupplierCode("TYJK");
        dto.setCount(manage.getWeight());
        //字段需要与物料主数据对齐
        List<MaterialModel> materialModelList = materialModelService.findMaterialModelByCode(manage.getMaterialCode());
        if (null == materialModelList || materialModelList.size() == 0) {
            throw new BusinessException("该料号不存在，请检查");
        }
        MaterialModel materialModel = materialModelList.get(0);

        dto.setMaterialModelId(Long.valueOf(materialModel.getId()));
        dto.setMaterialModelCode(materialModel.getCode());
        dto.setMaterialModelName(materialModel.getName());
        dto.setMaterialTypeName(materialModel.getMaterialType().getName());
        dto.setMaterialTh(materialModel.getNumberOfDrawings());
        dto.setUnitName(manage.getUnitName());
        dto.setSpecification(materialModel.getSpecification());
        dto.setBoxNo(manage.getBoxNo());
        dto.setWeight(manage.getWeight());
        dto.setMaterialGear(manage.getGear());
        dto.setMaterialModel(manage.getConductionType());
        //此工单号对于线边仓无用
        dto.setWorkOrderNo(manage.getWorkOrderNo());
        dto.setWarehouseCode(warehouseCode);
        Result<WarehouseModelDto> codeResult = storeFeignClients.getCode(warehouseCode);
        if (codeResult.getCode() == ResultCode.SUCCESS.getCode()) {
            dto.setWarehouseId(codeResult.getData().getId());
        }
        inputBillDetails.add(dto);
        inputBill.setInputBillDetails(inputBillDetails);
        return inputBill;
    }


    /**
     * 废料成品入库(线边仓退料到wms)
     *
     * @param entity
     * @param reason
     * @param warehouseCode
     * @return
     */
    private WarehouseInputBillBo newFlInputBill(RecycledMaterialManage entity, String reason, String warehouseCode) {
        WarehouseInputBillBo inputBill = new WarehouseInputBillBo();
        inputBill.setType(RecycleTypeEnum.废料入库.getDesc());
        inputBill.setRemark(reason);
        inputBill.setAutoAudit(false);
        inputBill.setAutomaticOut(false);
        inputBill.setWarehouseCode(warehouseCode);
        inputBill.setCreateUserId(BaseContextHandler.getUserID());
        inputBill.setCreateUserName(BaseContextHandler.getUsername());
        //入库物料明细
        List<WarehouseInputBillDetailBo> inputBillDetails = new ArrayList<>();
        WarehouseInputBillDetailBo dto = new WarehouseInputBillDetailBo();

        //组装物料明细数据
        //暂时使用固定编码,待后期业务完善
        dto.setSupplier("太原晶科");
        dto.setSupplierCode("TYJK");
        dto.setBatchNo(entity.getProduceBatchNo());
        dto.setCrystalNo(entity.getDateProduceBatchNo());
        dto.setDateProduceBatchNo(entity.getDateProduceBatchNo());
        dto.setWarehouseCode(warehouseCode);
        dto.setCount(entity.getWeight());
        //字段需要与物料主数据对齐
        //字段需要与物料主数据对齐
        MaterialModel materialModel = materialModelService.findByCode(entity.getMaterialCode());
        if (materialModel == null) {
            throw new BusinessException("【" + entity.getMaterialCode() + "】物料主数据不存在，请检查数据！");
        }
        dto.setMaterialModelId(Long.valueOf(materialModel.getId()));
        dto.setMaterialModelCode(materialModel.getCode());
        dto.setMaterialModelName(materialModel.getName());
        dto.setMaterialTypeName(materialModel.getMaterialType().getName());
        dto.setMaterialTh(materialModel.getNumberOfDrawings());
        dto.setUnitName(materialModel.getUnit().getName());
        dto.setSpecification(materialModel.getSpecification());
        dto.setWorkOrderNo(entity.getWorkOrderNo());
        dto.setMaterialGear(entity.getGear());
        dto.setMaterialLevel(entity.getGrade());
        dto.setSpecification(entity.getSpecification());
        dto.setTraceid(entity.getTrayNo());
        dto.setSerialNo(entity.getTrayNo());
        //todo:主数据中无等级,待下发后再判断 AB : N,CD:Y;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date currentTime = new Date();
        String currentTimeString = formatter.format(currentTime);
        dto.setLotatt01(currentTimeString);
        dto.setLotatt08("N");
        dto.setLotatt12(entity.getProduceBatchNo());
        dto.setLotatt19("00");
        inputBillDetails.add(dto);
        inputBill.setAutomaticOut(false);
        inputBill.setInputBillDetails(inputBillDetails);
        return inputBill;
    }

    /**
     * 余料收集,入库成功后副产品报内部系统,供上报sap使用
     *
     * @param materialCategory    物料类别(1 余料(默认) 2 废料)
     * @param workOrderNo    工单
     * @param materialCode   物料编码
     * @param produceBatchNo 产品批次
     * @param weight         数量(重量)
     * @param unitName       单位(KG,PC)
     * @param warehouseCode       库存地点编码
     * @param factoryWorkTypeName       工序名称 ("余料"-->某成本中心名称+余料:例如拉晶余料)
     */
    @Jinko(author = "yyl", value = "余料收集,入库成功后副产品报内部系统,供上报sap使用")
    private void handleReportSapGoodsmvtDto(Integer materialCategory ,String workOrderNo, String materialCode, String produceBatchNo, BigDecimal weight, String unitName, String warehouseCode, String factoryWorkTypeName) {
        ReportSapGoodsmvtDto reportSapGoodsmvtDto = new ReportSapGoodsmvtDto();
        List<ReportSapChargItemDto> reportSapChargItemDtos = new ArrayList<>();
        ReportSapChargItemDto reportSapChargItemDto = new ReportSapChargItemDto();
//        reportSapChargItemDto.setAtnam("P01");
//        reportSapChargItemDto.setAtwrt("JK1");
        reportSapChargItemDtos.add(reportSapChargItemDto);
        reportSapGoodsmvtDto.setChargItems(reportSapChargItemDtos);
        reportSapGoodsmvtDto.setAufnr(workOrderNo);
        reportSapGoodsmvtDto.setCharg(produceBatchNo);
        reportSapGoodsmvtDto.setBwart("531");
        reportSapGoodsmvtDto.setWerks("5041");
        reportSapGoodsmvtDto.setMatnr(materialCode);
        reportSapGoodsmvtDto.setMenge(weight == null ? "0" : weight.toString());
        reportSapGoodsmvtDto.setMeins(unitName);
        reportSapGoodsmvtDto.setLgort(warehouseCode);
        reportSapGoodsmvtDto.setZfcpFlag("X");
        reportSapGoodsmvtDto.setProcName(factoryWorkTypeName);
        ReportSapGoodsmvt reportSapGoodsmvt = fromDto(reportSapGoodsmvtDto);
        reportSapGoodsmvt.setStatus(false);
        reportSapGoodsmvt.setProcName(factoryWorkTypeName);
        reportSapGoodsmvtService.saveOrUpdate(reportSapGoodsmvt);

        ThreadManager.getThreadPollProxy().execute(() -> {
            try {
                //异步记录日志
                RecycledReportSapRecord recycledReportSapRecord = fromRecordDto(reportSapGoodsmvtDto);
                if (RecycleTypeEnum.余料.getCode() == materialCategory) {
                    recycledReportSapRecord.setRecordType(1);
                    recycledReportSapRecordService.saveRecycledRecordRecord(recycledReportSapRecord);
                } else {
                    recycledReportSapRecord.setRecordType(2);
                    recycledReportSapRecordService.saveWasteRecordRecord(recycledReportSapRecord);
                }
            } catch (Exception e) {
                log.error("记录mes发送SAP的余料副产品收货记录失败" + e.getMessage());
            }
        });
    }

    public ReportSapGoodsmvt fromDto(ReportSapGoodsmvtDto dto) {
        ReportSapGoodsmvt reportSapGoodsmvt = modelMapper.map(dto, ReportSapGoodsmvt.class);
        reportSapGoodsmvt.setChargItem(new Gson().toJson(dto.getChargItems()));
        return reportSapGoodsmvt;
    }

    public RecycledReportSapRecord fromRecordDto(ReportSapGoodsmvtDto dto) {
        RecycledReportSapRecord recycledReportSapRecord = modelMapper.map(dto, RecycledReportSapRecord.class);
        recycledReportSapRecord.setChargItem(new Gson().toJson(dto.getChargItems()));
        recycledReportSapRecord.setCreateDate(new Date());
        recycledReportSapRecord.setCreateUser(BaseContextHandler.getUsername());
        return recycledReportSapRecord;
    }

    /**
     * 刀剖成本中心4,籽晶去向2,余料自动入库并由线边仓手动调拨
     *
     * @param recycledMaterialManage
     * @param reason
     * @return
     */
    @Override
    public String startSurplusToSeedWarehousing(RecycledMaterialManage recycledMaterialManage, String reason) {
        try {
            //通过计划工单中的片区field4找到字典中的成品仓
            String workOrderNo = recycledMaterialManage.getWorkOrderNo();
            String warehouseCode = getWareHouseCodeByWorkOrderNo(workOrderNo);
            String nextWarehouseCode = "";
            String factoryWorkTypeName = getFactoryWorkTypeNameByWorkOrderNo(workOrderNo);
            factoryWorkTypeName = factoryWorkTypeName + RecycleCleanSAPEnum.余料.getDesc();
            //发起入库到副产品成品仓,成功后线边仓手动调拨到籽晶仓
            //封装余料成品入库数据
            WarehouseInputBillBo warehouseInputBillBo = newInputBill(recycledMaterialManage, reason, warehouseCode);
            //封装调拨数据
            DictionaryItem warehouseLocation = dictionaryItemService.findNameByThemeValueAndItemName("seedAllotWarehouse", warehouseCode);
            if (null != warehouseLocation) {
                nextWarehouseCode = warehouseLocation.getValue();
            }else {
                throw new BusinessException("关键字[seedAllotWarehouse]中的[原始库位]: " + warehouseCode + " 未配置对应信息");
            }
            WarehouseAllotBillDto warehouseAllotBillDto = newAllotBill(recycledMaterialManage, warehouseCode, nextWarehouseCode);
            //合并对象
            StoreDto storeDto = new StoreDto();
            storeDto.setInputBillBo(warehouseInputBillBo);
            storeDto.setWarehouseAllotBillDto(warehouseAllotBillDto);
            //创建自动入库单AND人工审核调拨单
            Result<String> result = storeFeignClients.createInputAndAllotAndOut(storeDto);
            Integer code = result.getCode();
            String data = result.getData();
            if (ResultCode.SUCCESS.getCode() != code) {
                throw new BusinessException("余料入库并调拨到籽晶仓异常，状态码：" + code + "，反馈信息：" + result.getMessage());
            } else {
                //1 回收料产出报工SAP
                String finalWarehouseCode = warehouseCode;
                try {
                    this.handleReportSapGoodsmvtDto(recycledMaterialManage.getMaterialCategory(), workOrderNo, recycledMaterialManage.getMaterialCode(), recycledMaterialManage.getDateProduceBatchNo(), recycledMaterialManage.getWeight(), recycledMaterialManage.getUnitName(), finalWarehouseCode, factoryWorkTypeName);
                } catch (Exception e) {
                    log.error("余料上报异常:" + e.getMessage());
                }
            }
            return data;
        } catch (Exception e) {
            throw new BusinessException("余料入库异常，" + e.getMessage());
        }
    }



    /**
     * 清洗硅料成品调拨数据封装
     *
     * @param entity 组托数据
     * @param warehouseCode 原始库位
     * @param nextWarehouseCode 调拨库位
     * @return
     */
    private WarehouseAllotBillDto newAllotBill(RecycledMaterialManage entity, String warehouseCode, String nextWarehouseCode) {
        MaterialModel materialModel = materialModelService.findByCode(entity.getMaterialCode());
        if (materialModel == null) {
            throw new BusinessException("【" + entity.getMaterialCode() + "】物料主数据不存在，请检查数据！");
        }
        //封装线边仓调拨数据
        WarehouseAllotBillDto warehouseAllotBillDto = new WarehouseAllotBillDto();
        List<WarehouseAllotBillDetailDto> allotBillDetailDtos = new ArrayList<>();
        WarehouseAllotBillDetailDto warehouseAllotBillDetailDto = new WarehouseAllotBillDetailDto();
        warehouseAllotBillDetailDto.setSupplier("太原晶科");
        warehouseAllotBillDetailDto.setWarehouseId(null);
        warehouseAllotBillDetailDto.setBatchNo(entity.getProduceBatchNo());
        warehouseAllotBillDetailDto.setCrystalNo(entity.getDateProduceBatchNo());
        warehouseAllotBillDetailDto.setCount(entity.getWeight());
        warehouseAllotBillDetailDto.setMaterialModelId(Long.valueOf(materialModel.getId()));
        warehouseAllotBillDetailDto.setMaterialModelCode(materialModel.getCode());
        warehouseAllotBillDetailDto.setMaterialModelName(materialModel.getName());
        if (null != materialModel.getMaterialType()) {
            warehouseAllotBillDetailDto.setMaterialTypeName(materialModel.getMaterialType().getName());
        }
        if (null != materialModel.getUnit()) {
            warehouseAllotBillDetailDto.setUnitName(materialModel.getUnit().getName());
        }
        warehouseAllotBillDetailDto.setSupplier(materialModel.getSupplier());
        warehouseAllotBillDetailDto.setSpecification(materialModel.getSpecification());
        warehouseAllotBillDetailDto.setMaterialTh(materialModel.getNumberOfDrawings());
        warehouseAllotBillDetailDto.setWarehouseCode(warehouseCode);
        Result<WarehouseModelDto> codeResult = storeFeignClients.getCode(warehouseCode);
        if (codeResult.getCode() == ResultCode.SUCCESS.getCode()) {
            warehouseAllotBillDetailDto.setWarehouseId(codeResult.getData().getId());
        }
        warehouseAllotBillDetailDto.setAllotWarehouseCode(nextWarehouseCode);
        allotBillDetailDtos.add(warehouseAllotBillDetailDto);
        warehouseAllotBillDto.setAllotBillDetailDtos(allotBillDetailDtos);
        warehouseAllotBillDto.setCreateUserName(BaseContextHandler.getUsername());
        warehouseAllotBillDto.setCreateUserId(BaseContextHandler.getUserID());
        warehouseAllotBillDto.setAutoAudit(false);
        if ("3".equals(entity.getKostl())) {
            warehouseAllotBillDto.setAllotType(RecycleNoAutoAllotWarehouseEnum.截断余料调拨籽晶仓.getDesc());
        } else if ("4".equals(entity.getKostl())) {
            warehouseAllotBillDto.setAllotType(RecycleNoAutoAllotWarehouseEnum.刀剖余料调拨籽晶仓.getDesc());
        }
        return warehouseAllotBillDto;
    }


    /**
     * 新增或编辑回收料信息
     *
     * @param recycledMaterialManageDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Result saveOrUpdateRecycledMaterial(RecycledMaterialManageDto recycledMaterialManageDto) {
        Integer hasGone = recycledMaterialManageDto.getHasGone();
        Long manageId = recycledMaterialManageDto.getId();
        Date now = new Date();
        String username = BaseContextHandler.getUsername();
        List<String> recycleNos = new ArrayList<>();
        List<RecycledMaterialManageDetailDto> recycledMaterialManageDetailDtos = recycledMaterialManageDto.getRecycledMaterialMangeDetailDtos();
        if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
            recycleNos = recycledMaterialManageDetailDtos.stream().map(temp -> temp.getRecycleNo()).collect(Collectors.toList());
            HashSet<String> hashSet = new HashSet<>(recycleNos);
            //只有单晶/刀剖回收料需要校验详情的编码是否重复
            if (recycleNos.size() != 0 && hashSet.size() != 0 && recycleNos.size() != hashSet.size()) {
                return ResultGenerator.fail("回收料重复");
            }
            //卡控定向标识
            Set<String> workOrderNoS = recycledMaterialManageDetailDtos.stream().map(recycledMaterialManageDetailDto -> recycledMaterialManageDetailDto.getWorkOrderNo()).collect(Collectors.toSet());
            if (null != workOrderNoS && workOrderNoS.size() > 1) {
                //多工单的时候,校验工单对应定向标识是否相同
                checkOrderInfo(workOrderNoS);
            }
        }
        //卡控超收情况
        Result checkResult = this.checkRecycledMaterialManageDtoOrderWeight(recycledMaterialManageDto);
        if (ResultCode.SUCCESS.getCode() != checkResult.getCode()) {
            return ResultGenerator.fail(checkResult.getMessage());
        }
        if (manageId != null) {//编辑
//            if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
//                //todo:说明是拉晶 ,因变更需求后是混订单,不确定修改后的重量具体放到哪个订单上,先卡控拉晶不允许编辑
//                return ResultGenerator.fail("拉晶成本中心采集不允许修改重量!");
//            }
            Integer status = recycledMaterialManageDto.getStatus();
            if (null == status) {
                return ResultGenerator.fail("缺少状态参数");
            }
            if (status.equals(StockStateEnum.REFUSE.getCode()) || status.equals(StockStateEnum.TOBEOUT.getCode()) || status.equals(StockStateEnum.CANCEL.getCode())) {
                recycledMaterialManageDetailService.deleteByManageId(manageId);
            } else {
                return ResultGenerator.fail("该状态不可编辑");
            }
            recycledMaterialManageDto.setUpdateBy(username);
            recycledMaterialManageDto.setUpdateTime(now);
        } else {//新增
            String materialBoxNo = recycledMaterialManageDto.getBoxNo();
            RecycledMaterialManage materialManage = this.getByBoxNoAndStatus(materialBoxNo);
            if (null != materialManage) {
                return ResultGenerator.fail("该箱号: " + materialBoxNo + " 被占用,领料清空后方可使用!");
            }
            //todo: 暂时使用批次当做托号
            //定向标识为空的时候,默认为: 非定向
            String directionalSign = recycledMaterialManageDto.getDirectionalSign();
            if (com.sw.mes.core.utils.StringUtils.isBlank(directionalSign)) {
                directionalSign = "非定向";
                recycledMaterialManageDto.setDirectionalSign(directionalSign);
            }
            if (com.sw.mes.core.utils.StringUtils.isBlank(recycledMaterialManageDto.getDopant()) || com.sw.mes.core.utils.StringUtils.isBlank(recycledMaterialManageDto.getWorkShop())) {
                return ResultGenerator.fail("缺少批次号生成必要参数");
            }
            DictionaryItem dictionaryItems = dictionaryItemService.findFirstValueByThemeValueAndEnableAndItemValueAndItemExtendValue("SapFabCode", true, recycledMaterialManageDto.getKostl(), recycledMaterialManageDto.getWorkShop());
            String workShopValue = "";
            if (null != dictionaryItems) {
                workShopValue = dictionaryItems.getExtendValue1();
            } else {
                return ResultGenerator.fail("字典关键字[SapFabCode]词条:成本中心代码[" + recycledMaterialManageDto.getKostl() + "]车间:[" + recycledMaterialManageDto.getWorkShop() + "未配置完整!");
            }

            DictionaryItem directionalSignValue = dictionaryItemService.findByThemeValueAndNameAndEnable("creatCrystalNo", directionalSign, true);
            if (null == directionalSignValue || com.sw.mes.core.utils.StringUtils.isBlank(directionalSignValue.getValue())) {
                return ResultGenerator.fail("字典关键字[creatCrystalNo]词条:实际值 [" + directionalSign + "未配置!");
            } else {
                if (directionalSignValue.getValue().length() > 1) {
                    return ResultGenerator.fail("字典关键字[creatCrystalNo]词条:实际值 [" + directionalSign + "配置值异常,必须一位字符!");
                }
            }
            String dataBatchNoGenerator = recycledBatchGenerator.dataBatchNoGenerator(directionalSign, directionalSignValue.getValue(), workShopValue, recycledMaterialManageDto.getKostl());
            log.info("在时间:{},余料采集生成日批次号:{}", now, dataBatchNoGenerator);
            String produceBatchNo = recycledBatchGenerator.batchNoGenerator(directionalSign, recycledMaterialManageDto.getDopant(), recycledMaterialManageDto.getWorkShop());
            String trayNo = produceBatchNo;
            recycledMaterialManageDto.setTrayNo(trayNo);
            //字段需要与物料主数据对齐
            MaterialModel materialModel = materialModelService.findByCode(recycledMaterialManageDto.getMaterialCode());
            if (materialModel == null) {
                return ResultGenerator.fail("【" + recycledMaterialManageDto.getMaterialCode() + "】物料主数据不存在，请检查数据！");
            }
            recycledMaterialManageDto.setUnitName(materialModel.getUnit().getName());
            recycledMaterialManageDto.setSpecification(materialModel.getSpecification());
            recycledMaterialManageDto.setGrade(materialModel.getProductLevel());
            recycledMaterialManageDto.setProduceBatchNo(produceBatchNo);
            recycledMaterialManageDto.setDateProduceBatchNo(dataBatchNoGenerator);
            recycledMaterialManageDto.setCreateBy(username);
            recycledMaterialManageDto.setCreateTime(now);
            recycledMaterialManageDto.setUpdateBy(username);
            recycledMaterialManageDto.setUpdateTime(now);
            if (null == hasGone) {
                //默认去向1 硅料车间
                recycledMaterialManageDto.setHasGone(RecycleTypeEnum.硅料车间.getCode());
            }
        }
        if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
            //入参存在详情,校验单晶/刀剖回收料详情是否存在其他的记录中
            List<String> usedRecycleNos = recycledMaterialManageDetailService.getDetailByRecycleNos(recycleNos);
            if (usedRecycleNos != null && !usedRecycleNos.isEmpty() && usedRecycleNos.size() > 0) {
                return ResultGenerator.fail("物料已被组托!");
            }
        }
        recycledMaterialManageDto.setStatus(StockStateEnum.TOBEOUT.getCode());
        if ("2".equals(recycledMaterialManageDto.getKostl()) && null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
            //校验并更新单晶余料重量,并记录原始重量
            recycledMaterialManageDetailDtos.stream().forEach(temp ->
                    surplusInfoService.updateWeightBySurplusCode(temp.getOriginalWeight(), temp.getWeight(), temp.getRecycleNo())
            );
        }
        //保存主表记录
        RecycledMaterialManage recycledMaterialManage = fromDto(recycledMaterialManageDto);
        this.saveOrUpdate(recycledMaterialManage);
        if (null != recycledMaterialManageDetailDtos && !recycledMaterialManageDetailDtos.isEmpty() && recycledMaterialManageDetailDtos.size() > 0) {
            List<RecycledMaterialManageDetail> recycledMaterialManageDetails = recycledMaterialManageDetailDtos.stream().map(entity -> fromDetailDto(entity))
                    .collect(Collectors.toList());
            recycledMaterialManageDetails.stream().forEach(temp -> temp.setManageId(recycledMaterialManage.getId()));
            recycledMaterialManageDetailService.saveAll(recycledMaterialManageDetails);
        }
        return ResultGenerator.success();
    }

    private RecycledMaterialManage fromDto(RecycledMaterialManageDto recycledMaterialManageDto) {
        return modelMapper.map(recycledMaterialManageDto, RecycledMaterialManage.class);
    }

    private RecycledMaterialManageDetail fromDetailDto(RecycledMaterialManageDetailDto entity) {
        return modelMapper.map(entity, RecycledMaterialManageDetail.class);
    }

    @Override
    public RecycledMaterialManage getRecycleMaterialByTrayNo(String trayNo) {
        return dao.getRecycleMaterialByTrayNo(trayNo);
    }

    @Override
    public RecycledMaterialManage getRecycleMaterialByRecycleNo(String recycleNo) {
        return dao.getRecycleMaterialByRecycleNo(recycleNo);
    }

    /**
     * 检查订单信息，确保所有订单满足特定条件（有相同的定向标识）。
     *
     * @param aufnrs 一个包含订单号的集合。
     */
    public void checkOrderInfo(Set<String> aufnrs) {
        List<String> list = new ArrayList<>(aufnrs);
        List<ProductionOrder> sapProductionOrders = productionOrderService.findByAufnrs(list);
        if (CollectionUtil.isEmpty(sapProductionOrders)) {
            throw new RuntimeException("工单查询异常!");
        } else {
            // 遍历订单数据，如果定向标识为空，则设置为"非定向"。
            sapProductionOrders.forEach(entity -> {
                if (com.sw.mes.core.utils.StringUtils.isBlank(entity.getZorientationind())) {
                    entity.setZorientationind("非定向");
                }
            });
            Set<String> zorientationindSet = sapProductionOrders.stream().map(ProductionOrder::getZorientationind).collect(Collectors.toSet());
            if (zorientationindSet.size() != 1) {
                throw new RuntimeException("不是相同定向标识不能组托");
            }
        }
    }
}
