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

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.sw.mes.base.factory.init.entity.Equipment;
import com.sw.mes.base.factory.init.service.EquipmentService;
import com.sw.mes.base.factory.material.entity.MaterialModel;
import com.sw.mes.base.factory.material.service.MaterialModelService;
import com.sw.mes.base.global.GlobalSwitch;
import com.sw.mes.base.global.GlobalSwitchNamespace;
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.system.AccessoryFeignClients;
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.AccessoryProductionOrderDto;
import com.sw.mes.core.dto.WarehouseModelDto;
import com.sw.mes.core.dto.store.*;
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.utils.IpUtils;
import com.sw.mes.enumvalue.EnumValuesServer;
import com.sw.mes.mmcs.service.MMcsInterfaceService;
import com.sw.mes.production.entity.FormulaScheme;
import com.sw.mes.production.service.FormulaSchemeService;
import com.sw.mes.sap.entity.ReportSapGoodsmvt;
import com.sw.mes.sap.service.ReportSapGoodsmvtService;
import com.sw.mes.yb.mcs.service.YbMesToMcsService;
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.LoadingTaskDao;
import com.sw.mes.yb.production.dto.AgainTaskDetail.TaskDetailExportDto;
import com.sw.mes.yb.production.dto.InputFurnaceBurden.InputFurnaceBurdenExportParam;
import com.sw.mes.yb.production.dto.LoadingTask.FeedingInformationDto;
import com.sw.mes.yb.production.dto.LoadingTask.IngredientInfoDto;
import com.sw.mes.yb.production.dto.LoadingTask.LoadingTaskDto;
import com.sw.mes.yb.production.dto.PartReturnMaterialDto;
import com.sw.mes.yb.production.dto.ProductionBucketRecipeRecordDto;
import com.sw.mes.yb.production.dto.ProductionCircleRecipeDetailDto;
import com.sw.mes.yb.production.dto.ProductionMaterialReturnRecordDto;
import com.sw.mes.yb.production.entity.*;
import com.sw.mes.yb.production.service.*;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 李儒
 * @Date: Create in
 * @Modified By:
 */
@Slf4j
@Service
@Transactional
public class LoadingTaskServiceImpl extends BaseServiceImpl<LoadingTask> implements LoadingTaskService {
	@Autowired
	ModelMapper modelMapper;

	LoadingTaskDao dao;

	@Autowired
	public void setDao(LoadingTaskDao dao) {
		super.setBaseDao(dao);
		this.dao = dao;
	}

	@Autowired
	private LoadingTaskLogService loadingTaskLogService;


	@Autowired
	private BlastFurnaceDetailService blastFurnaceDetailService;

	@Autowired
	StoreFeignClients storeFeignClients;

	@Autowired
	AccessoryFeignClients accessoryFeignClients;

    @Autowired
    @Lazy
    MMcsInterfaceService mMcsInterfaceService;

    @Autowired
    private DictionaryItemService dictionaryItemService;

    @Autowired
    private ProductionCircleRecipeDetailService productionCircleRecipeDetailService;

	@Autowired
	private ProductionMaterialReturnRecordService productionMaterialReturnRecordService;

	@Autowired
	private ProductionScheduleService scheduleService;

	@Autowired
	private ProductionOrderService productionOrderService;

	@Autowired
	private MaterialModelService materialModelService;

	@Autowired
	private ReportSapGoodsmvtService reportSapGoodsmvtService;

	@Autowired
	private EquipmentService equipmentService;

	@Autowired
	private SysLogService sysLogService;

	@Autowired
	private YbMesToMcsService mesToMcsService;

/*	@Autowired
	private RestTemplate restTemplate;*/

//	@Value("${spring.etlIp}")
//	private String etlIp;

	public static final String url = "/data/materialDataNumCheck";

    @Override
    public LoadingTask getFinishTask(String equipmentCode, String lotNo) {
        List<LoadingTask> task = dao.getFinishTask(equipmentCode, lotNo);
        if (task.size() > 0) {
            return task.get(0);
        }
        return null;
    }

    @Override
    public BigDecimal getPeiLiaoTotalWeightByLotNo(String lotNo) {

        return dao.getPeiLiaoTotalWeightByLotNo(lotNo);
    }

    @Override
    public List<LoadingTask> findByLotNo(String lotNo) {
        return dao.findByLotNo(lotNo);
    }

	@Override
//	@ServiceLogs(description = "获取确认投料时间-建议其他地方不要使用该方法")
	public List<LoadingTask> findByLotNoV2(String source,String lotNo) {
		LoadingTask loadingTask = dao.findSuccessByLotNo(lotNo);
		List<LoadingTask> byLotNo = new ArrayList<>();
		byLotNo.add(loadingTask);
		SysLog sysLog = new SysLog();
		new SysLog().setCreateTime(new Date());
		sysLog.setType("info");
		sysLog.setCreateUserName(BaseContextHandler.getUsername());
		sysLog.setContent(JSON.toJSONString(byLotNo));
		sysLog.setMethodName("获取确认投料时间");
		sysLog.setName("获取确认投料时间");
		sysLog.setReqIp(IpUtils.getLocalIP());
		sysLogService.save(sysLog);
		return byLotNo;
	}

	@Override
    public List<LoadingTask> findBySapNo(String sapNo) {
        return dao.findBySapNo(sapNo);
    }

    @Override
    public List<LoadingTask> findByEquipmentCode(String equipmentCode) {
        return dao.findByEquipmentCode(equipmentCode);
    }

    @Override
    public LoadingTask getByEquipmentAndStateLastTask(String equipmentCode, String lotNo, Integer rawstatus) {
        return dao.getByEquipmentAndStateLastTask(equipmentCode, lotNo, rawstatus);
    }

    @Override
    public LoadingTask getByEquipmentAndSuccessLastTask(String equipmentCode, String lotNo) {
        return dao.getByEquipmentAndSuccessLastTask(equipmentCode, lotNo);
    }

	@Override
	public String getLastOneHeight(String equipmentCode) {
		return dao.getLastOneHeight(equipmentCode);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void backTask(Long id, String cause) {
		LoadingTask task = this.get(id);
		// 确认投料卡控
		if (GlobalSwitch.enable(GlobalSwitchNamespace.NAMESPACE_YB_CHECK, "checkBackMaterialByConfirm", true)){
			if (task.getConfirm() == 1) throw new RuntimeException("IPC中已确认投料，无法退料");
		}

		if(task.getRawStatus().equals(LoadingTaskDto.rawStatus_3) || task.getRawStatus().equals(LoadingTaskDto.rawStatus_4)) {
			task.setRawStatus(LoadingTaskDto.rawStatus_5);
			task.setOperationCause(cause);
			task.setUserName(BaseContextHandler.getUsername());
			task.setOperationTime(new Date());
			task.setRealWeight(new BigDecimal(0));
			this.saveOrUpdate(task);

			//装料任务记录
			loadingTaskLogService.saveByLoadingTask(task);

			// 修改排程状态
			ProductionSchedule schedule = scheduleService.get(task.getScheduleId());
			schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.待备料.getKey());
			schedule.setStatusInfo("配料任务退料");
			scheduleService.saveOrUpdate(schedule);

			// 解锁库存明细
			List<LockInventoryDto> unLockInventoryList = new ArrayList<>();

			// 记录退料明细
			List<BlastFurnaceDetail> detailList = blastFurnaceDetailService.getBlastFurnaceDetailList(id);
			List<ProductionMaterialReturnRecord> backList =  new ArrayList<>();
//			StringBuilder ids = new StringBuilder(",");
			for (BlastFurnaceDetail detail : detailList) {
				ProductionMaterialReturnRecord back = new ProductionMaterialReturnRecord();
//				ids.append(detail.getId());
				back.setTaskId(id);
				back.setTaskRecordId(detail.getId());
				back.setEquipmentNo(task.getEquipmentCode());
				back.setLotNo(task.getLotNo());
				back.setAgainNum(0);
				back.setProductCode(detail.getMaterialCode());
				back.setMaterialCode(detail.getMaterialCode());
				back.setMaterialName(detail.getMaterialName());
				back.setBatchNo(detail.getBatchNo());
				back.setWeight(detail.getWeight());
				back.setMaterialTypeName(detail.getMaterialTypeName());
				back.setSupplierName(detail.getSupplierName());
				back.setInstallTime(detail.getInstallTime());
				back.setPailNum("1");
				back.setInstallUser(detail.getUserName());
				back.setSapOrderNo(task.getSapNo());
				back.setSapProductCode(task.getProductCode());
				back.setCarrierNo(task.getCarrierNo());
				back.setBucketNo(detail.getBatchNo());
				back.setCreateUser(BaseContextHandler.getUsername());
				back.setCreateTime(new Date());
				back.setReason(cause);

				backList.add(back);

				// 组织解锁库存数据
				LockInventoryDto inventory = new LockInventoryDto();
				inventory.setMaterialModelCode(detail.getMaterialCode());
				inventory.setBatchNo(detail.getBatchNo());
				inventory.setUniqueCode(detail.getUniqueCode() == null? "": detail.getUniqueCode());
				inventory.setWarehouseId(detail.getStoreLocationId().longValue());
				inventory.setQuantity(detail.getWeight());

				unLockInventoryList.add(inventory);
			}

			// 保存退料明细
			productionMaterialReturnRecordService.saveAll(backList);

			// 解锁库存
			Result result = storeFeignClients.unLockInventory(unLockInventoryList);
			if (result.getCode() != ResultCode.SUCCESS.getCode()){
				throw new RuntimeException("线边仓解锁库存失败：" + result.getMessage());
			}

			// 删除配料记录
			blastFurnaceDetailService.deleteByLoadingTaskId(task.getId());
			blastFurnaceDetailLogService.deleteByLoadingTaskId(task.getId());

//			try {
//				ids.append("1")
//				deleteEtlMaterialReport(ids.toString(), "127.0.0.1" + url);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}

		}else {
			throw new RuntimeException("非取消状态无法重复叫料");
		}
	}

	/*@Async
	public String deleteEtlMaterialReport(String ids, String url) {
		HttpHeaders headers = new HttpHeaders();
		MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(mediaType);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		HttpEntity<String> httpEntity = new HttpEntity<>(ids, headers);
		//使用exchange请求接口
		ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
		return exchange.getBody();
	}*/


	@Override
	public void repeatOpenTask(Long id) {
		LoadingTask task = this.get(id);
		if(task.getRawStatus().equals(LoadingTaskDto.rawStatus_2) || task.getRawStatus().equals(LoadingTaskDto.rawStatus_5)) {
			//验证是否已重新叫料
			boolean isDoubleTask = doubleTaskValidate(task);
			if(isDoubleTask) {
				throw new RuntimeException("相同炉次已存在叫料任务");
			}

			//创建新任务
			LoadingTask newTask = new LoadingTask(task,LoadingTaskDto.rawStatus_0);
			this.saveOrUpdate(newTask);

			// 修改排程状态
			ProductionSchedule schedule = scheduleService.get(task.getScheduleId());
			schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.待备料.getKey());
			schedule.setStatusInfo("配料任务重新叫料");
			scheduleService.saveOrUpdate(schedule);

//    		//下发生产任务接口
//    		mMcsInterfaceService.issueMoInterface(newTask);

			//装料任务记录
			loadingTaskLogService.saveByLoadingTask(newTask);
		}else {
			throw new RuntimeException("非取消状态无法重复叫料");
		}
	}

	@Override
	public void cancelTask(Long id, String cause) {
		LoadingTask task = this.get(id);
		ProductionSchedule schedule = scheduleService.get(task.getScheduleId());
		if (schedule.getStatus() != EnumValuesServer.ProductionScheduleStatus.未开始.getKey()
				&& schedule.getStatus() != EnumValuesServer.ProductionScheduleStatus.待备料.getKey()){
			throw new RuntimeException("排程为【未开始】或者【待备料】状态才能取消！");
		}
		if(task.getRawStatus().equals(LoadingTaskDto.rawStatus_0)) {
			task.setRawStatus(LoadingTaskDto.rawStatus_2);

			task.setOperationCause(cause);
			task.setUserName(BaseContextHandler.getUsername());
			task.setOperationTime(new Date());

			this.saveOrUpdate(task);

			if (GlobalSwitch.enable(GlobalSwitchNamespace.NAMESPACE_AUTOMATION, "CanningMaterial", false)) {
				//下发取消生产任务接口 装罐料下发
				mesToMcsService.cancelMoDistributionInterface(task);
			}
			//装料任务记录
			loadingTaskLogService.saveByLoadingTask(task);
		}else {
			throw new RuntimeException("非新建状态无法取消");
		}
	}

	@Override
	public Map<String,List<ProductionBucketRecipeRecordDto>> getRecipeByLoadingTaskId(Long id, String height) {
		Map<String,List<ProductionBucketRecipeRecordDto>> map1 =  new HashMap<>();
		String weight1 = dictionaryItemService.findValueByThemeValueAndItemName("SyggHeight",height);
		if(null == weight1){
			throw new RuntimeException("字典未配置数据");
		}
		BigDecimal weight = new BigDecimal(weight1);
		LoadingTask task = this.get(id);
		Long recipeId = task.getRecipeId();

		List <ProductionCircleRecipeDetail> productionCircleRecipeDetails = productionCircleRecipeDetailService.getProductionRecipeDetailsByParam(recipeId,"%初始装料%");
		if(null == productionCircleRecipeDetails || productionCircleRecipeDetails.size() <= 0){
			throw new RuntimeException("该产品未绑定产品配方");
		}
		Map<String, List<ProductionCircleRecipeDetail>> map = productionCircleRecipeDetails.stream().collect(Collectors.groupingBy(ProductionCircleRecipeDetail::getRecipeKind));
		Set set = map.keySet();
		Iterator iterator = set.iterator();
		while (iterator.hasNext()) {
			String key =iterator.next().toString();
			List<ProductionCircleRecipeDetail> entitys = map.get(key);
			List<ProductionCircleRecipeDetailDto> dtos = entitys.stream().map(temp-> modelMapper.map(temp, ProductionCircleRecipeDetailDto.class)).collect(Collectors.toList());
			List<ProductionBucketRecipeRecordDto> productionBucketRecipeRecordDtos = new ArrayList<>();
			for(ProductionCircleRecipeDetailDto temp:dtos) {
				ProductionBucketRecipeRecordDto dto = new ProductionBucketRecipeRecordDto();
				Integer weightRatio = temp.getWeightRatio();
				if (weightRatio == 0) {
					break;
				}
				Map<String, Integer> map2 = calculateWeight(weightRatio, weight);
				dto.setId(temp.getId());
				dto.setWeight(map2.get("weight"));
				dto.setBucketForty(map2.get("bucketForty"));
				dto.setBucketTen(map2.get("bucketTen"));
				dto.setRecipeKind(temp.getRecipeKind());
				dto.setSuppliesName(temp.getSuppliesName());
				dto.setSuppliesType(temp.getSuppliesType());
				dto.setGross(Integer.valueOf(weight.toString()));
				dto.setSuppliesCode(temp.getSuppliesCode());
				dto.setSuppliesDopant(temp.getSuppliesDopant());
				dto.setSuppliesGrainMax(temp.getSuppliesGrainMax());
				dto.setSuppliesGrainMin(temp.getSuppliesGrainMin());
				dto.setSuppliesResistanceMax(temp.getSuppliesResistanceMax());
				dto.setSuppliesResistanceMin(temp.getSuppliesResistanceMin());
				dto.setPriority(temp.getPriority());
				productionBucketRecipeRecordDtos.add(dto);
			}
			if(productionBucketRecipeRecordDtos.size()>0) {
				map1.put(key, productionBucketRecipeRecordDtos);
			}
		}


//		List<ProductionCircleRecipeDetailDto> dtos = productionCircleRecipeDetails.stream().map(temp-> modelMapper.map(temp, ProductionCircleRecipeDetailDto.class)).collect(Collectors.toList());
//		List<ProductionBucketRecipeRecordDto> productionBucketRecipeRecordDtos = new ArrayList<>();
//		for(ProductionCircleRecipeDetailDto temp:dtos){
//			ProductionBucketRecipeRecordDto dto = new ProductionBucketRecipeRecordDto();
//			Integer weightRatio = temp.getWeightRatio();
//			if (weightRatio == 0){
//				continue;
//			}
//			Map<String,Integer> map = calculateWeight(weightRatio,weight);
//			dto.setWeight(map.get("weight"));
//			dto.setBucketForty(map.get("bucketForty"));
//			dto.setBucketTen(map.get("bucketTen"));
//			dto.setRecipeKind(temp.getRecipeKind());
//			dto.setSuppliesName(temp.getSuppliesName());
//			dto.setSuppliesType(temp.getSuppliesType());
//			dto.setGross(Integer.valueOf(weight.toString()));
//			dto.setSuppliesCode(temp.getSuppliesCode());
//			dto.setSuppliesDopant(temp.getSuppliesDopant());
//			dto.setSuppliesGrainMax(temp.getSuppliesGrainMax());
//			dto.setSuppliesGrainMin(temp.getSuppliesGrainMin());
//			dto.setSuppliesResistanceMax(temp.getSuppliesResistanceMax());
//			dto.setSuppliesResistanceMin(temp.getSuppliesResistanceMin());
//			dto.setPriority(temp.getPriority());
//			productionBucketRecipeRecordDtos.add(dto);
//		}
		return map1;
	}

	@Override
	public  Map<String, Object>  findCrucibleInfoByLotNo(String lotNo) {
		return dao.findCrucibleInfoByLotNo(lotNo);
	}

	/** 多次叫料验证 **/
	private boolean doubleTaskValidate(LoadingTask task) {
		boolean isDoubleTask = false;
		List<LoadingTask> allLotNoTask = this.findByLotNo(task.getLotNo());
		for (LoadingTask againTask : allLotNoTask) {
			if(!againTask.getRawStatus().equals(LoadingTaskDto.rawStatus_2) && !againTask.getRawStatus().equals(LoadingTaskDto.rawStatus_5)) {
				isDoubleTask = true;
				break;
			}
		}
		return isDoubleTask;
	}

	private Map<String, Integer> calculateWeight(Integer weightRatio, BigDecimal weightBucket) {
		Map<String, Integer> map = new HashMap<>();
		//比例
		BigDecimal ratio = new BigDecimal(Integer.parseInt(weightRatio.toString()));
		BigDecimal tempRatio = ratio.divide(new BigDecimal("1000"));
		//算出配料重量(五舍六入)
		BigDecimal weight = weightBucket.multiply(tempRatio).setScale(0,BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal("10"));
		//取余
		BigDecimal[] result1 = weight.divideAndRemainder(new BigDecimal("40"));
		Integer bucketForty = Integer.parseInt(result1[0].toString());
		BigDecimal remainder = result1[1];
		BigDecimal[] result2 = remainder.divideAndRemainder(new BigDecimal("10"));
		Integer bucketTen = Integer.parseInt(result2[0].toString());
		map.put("weight",Integer.parseInt(weight.toString()));
		map.put("bucketForty",bucketForty);
		map.put("bucketTen",bucketTen);
		return map;
	}

	@Override
	public List<LoadingTask> findByLotNoList(List<String> lotNo) {
		return dao.findByLotNoList(lotNo);
	}

	@Jinko(value = "配料部分退料", author = "wxl")
	@Override
	public void materialReturn(PartReturnMaterialDto dto) {
		String reason = dto.getReason();
		List<ProductionMaterialReturnRecordDto> list  = dto.getList();
		List<ProductionMaterialReturnRecord> productionMaterialReturnRecords = new ArrayList<>();
		BigDecimal allWeight = BigDecimal.ZERO;
		String  receiverName = BaseContextHandler.getUsername();
		//1扣减配料记录2记录退料信息3生成线边仓记录4扣减总数
		if(CollectionUtil.isNotEmpty(list)){
			for(ProductionMaterialReturnRecordDto recordDto:list){
				//保存记录
				ProductionMaterialReturnRecord record = toLazy(recordDto);
				record.setReason(reason);
				record.setCreateTime(new Date());
				record.setCreateUser(receiverName);
				productionMaterialReturnRecords.add(record);
				//扣减配料表
				BlastFurnaceDetail blastFurnaceDetail = blastFurnaceDetailService.get(recordDto.getTaskRecordId());
				BigDecimal weight = blastFurnaceDetail.getWeight();
				BigDecimal weight1 = recordDto.getWeight();
				if(!recordDto.getMaterialName().contains("坩埚")){
					allWeight = allWeight.add(weight1);
				}
				if(weight.compareTo(weight1) < 0){
					throw new BusinessException("退料重量大于配料重量！");
				}
				weight = weight.subtract(weight1);
				blastFurnaceDetail.setWeight(weight);
				if(weight.compareTo(BigDecimal.ZERO) == 0){
					blastFurnaceDetailService.delete(blastFurnaceDetail.getId());
				}else{
					blastFurnaceDetailService.saveOrUpdate(blastFurnaceDetail);
				}
			}
		}else{
			throw new BusinessException("无数据！");
		}
		LoadingTask loadingTask = this.get(list.get(0).getTaskId());
		BigDecimal realWeight = loadingTask.getRealWeight();
		realWeight = realWeight.subtract(allWeight);
		loadingTask.setRealWeight(realWeight);
		List<BlastFurnaceDetail> blastFurnaceDetails = blastFurnaceDetailService.getBlastFurnaceDetailList(loadingTask.getId());
		if(CollectionUtil.isEmpty(blastFurnaceDetails) && (loadingTask.getRawStatus().equals(LoadingTaskDto.rawStatus_3) || loadingTask.getRawStatus().equals(LoadingTaskDto.rawStatus_4))){
			loadingTask.setRawStatus(LoadingTaskDto.rawStatus_5);
			loadingTask.setOperationCause(reason);
			loadingTask.setUserName(BaseContextHandler.getUsername());
			loadingTask.setOperationTime(new Date());

			LoadingTaskLog loadingTaskLog = loadingTaskLogService.getByLoadingTaskId(loadingTask.getId());
			if(loadingTaskLog != null){
				loadingTaskLog.setRawStatus(LoadingTaskDto.rawStatus_5);
				loadingTaskLog.setOperationCause(reason);
				loadingTaskLog.setUserName(BaseContextHandler.getUsername());
				loadingTaskLog.setOperationTime(new Date());
				loadingTaskLogService.saveOrUpdate(loadingTaskLog);
			}
		}
		this.saveOrUpdate(loadingTask);
		//生成退料记录
		productionMaterialReturnRecordService.saveAll(productionMaterialReturnRecords);
	}

	@Jinko(value = "配料部分退料", author = "wxl")
	@Override
	public List<ProductionMaterialReturnRecordDto> findMaterialList(Long id) {
		List<ProductionMaterialReturnRecordDto> list = new ArrayList<>();
		LoadingTask loadingTask = this.get(id);
		String equipmentNo = loadingTask.getEquipmentCode();
		String lotNo = loadingTask.getLotNo();
		String sapNo = loadingTask.getSapNo();
		List<BlastFurnaceDetail> blastFurnaceDetails = blastFurnaceDetailService.getBlastFurnaceDetailList(id);
		if(CollectionUtil.isNotEmpty(blastFurnaceDetails)){
			for(BlastFurnaceDetail detail:blastFurnaceDetails){
				ProductionMaterialReturnRecordDto dto = new ProductionMaterialReturnRecordDto();
				dto.setTaskId(id);
				dto.setTaskRecordId(detail.getId());
				dto.setEquipmentNo(equipmentNo);
				dto.setLotNo(lotNo);
				dto.setAgainNum(0);
				dto.setProductCode(detail.getProductCode());
				dto.setMaterialCode(detail.getMaterialCode());
				dto.setMaterialName(detail.getMaterialName());
				dto.setBatchNo(detail.getBatchNo());
				dto.setWeight(detail.getWeight());
				dto.setMaterialTypeName(detail.getMaterialTypeName());
				dto.setSupplierName(detail.getFactoryBrand());
				dto.setInstallTime(detail.getInstallTime());
				dto.setInstallUser(detail.getUserName());
				dto.setSapOrderNo(sapNo);
				list.add(dto);
			}
		}
		return list;
	}

	@Override
	public LoadingTask findUnconfirmedTask(String lotNo) {
		return dao.findUnconfirmedTask(lotNo);
	}

	@Override
	public Result confirmMaterials(Long id) {
		LoadingTask task = dao.getOne(id);
		ProductionSchedule schedule = scheduleService.get(task.getScheduleId());
		if (task.getConfirm() == 1){
			return ResultGenerator.fail("已完成确认投料，请勿重复操作");
		}
		if (schedule.getStatus() != EnumValuesServer.ProductionScheduleStatus.已备料.getKey()){
			return ResultGenerator.fail("排程不是【已备料】状态，请检查执行流程");
		}

		// 修改装料任务信息
		task.setConfirm(1);
		task.setConfirmTime(new Date());
		dao.save(task);

		// 修改排程状态
		schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.进行中.getKey());
		schedule.setStatusInfo("配料投料完成");
		scheduleService.saveOrUpdate(schedule);

		// 查询投料明细
		List<BlastFurnaceDetail> detailList = blastFurnaceDetailService.getBlastFurnaceDetailList(id);

		// 线边仓出库
		WarehouseOutputBillBo outputBillBo = new WarehouseOutputBillBo();
		outputBillBo.setType("生产领用");
		outputBillBo.setAutoAudit(true);
		outputBillBo.setDestination("车间");
		outputBillBo.setCreateUserId(1);
		outputBillBo.setCreateUserName(task.getUserName());

		// 线边仓回滚
		StoreDataBo rollBackBo = new StoreDataBo();
		rollBackBo.setReturnType(0);
		rollBackBo.setType("装灌料回滚入库");
		rollBackBo.setCreateUserId(1);
		rollBackBo.setCreateUserName(task.getUserName());

		List<WarehouseOutputBillDetailBo> boList = new ArrayList<>();
		List<StoreDataDetailsBo> rollBackList = new ArrayList<>();
		for (BlastFurnaceDetail detail : detailList) {
			MaterialModel model = materialModelService.findByCode(detail.getMaterialCode());
			WarehouseOutputBillDetailBo bo = new WarehouseOutputBillDetailBo();
			bo.setMaterialModelId(model.getId().longValue());
			bo.setMaterialModelCode(model.getCode());
			bo.setMaterialModelName(model.getName());
			bo.setMaterialTypeName(model.getMaterialType().getName());
			bo.setBatchNo(detail.getBatchNo());
			bo.setUniqueCode(detail.getUniqueCode());
			bo.setSupplier(model.getSupplier());
			bo.setSpecification(model.getSpecification());
			bo.setMaterialTh(model.getNumberOfDrawings());
			bo.setRequireCount(detail.getWeight());
			bo.setUnitName(detail.getUnit());
			bo.setWarehouseId(detail.getStoreLocationId().longValue());
			bo.setWarehouseName(detail.getStoreLocationName());
			bo.setCreateUserId(1);
			bo.setCreateUserName(task.getUserName());
			bo.setLockInventory(true);

			boList.add(bo);

			StoreDataDetailsBo rbBo = new StoreDataDetailsBo();
			BeanUtils.copyProperties(bo, rbBo);
			rbBo.setCount(detail.getWeight());
			rollBackList.add(rbBo);
		}
		outputBillBo.setOutputBillDetails(boList);
		rollBackBo.setDetailsBos(rollBackList);

		Result<String> result = storeFeignClients.outputApply(outputBillBo);
		if (result.getCode() != ResultCode.SUCCESS.getCode()){
			throw new RuntimeException("线边仓出库失败：" + result.getMessage());
		}

		try{
			// SAP报消耗
			for (BlastFurnaceDetail detail : detailList) {
				ReportSapGoodsmvt reportSap = new ReportSapGoodsmvt();
				reportSap.setBwart("261");		// 移动类型
				reportSap.setKostl(null);		// 成本中心
				reportSap.setProcName("拉晶");	// 工序
				reportSap.setAufnr(task.getSapNo());		// SAP生产订单
				reportSap.setMatnr(detail.getMaterialCode());	// 物料编码
				reportSap.setCharg(StringUtils.isEmpty(detail.getCrystalNo())? detail.getBatchNo(): detail.getCrystalNo());		// 批次号
				reportSap.setMenge(detail.getWeight().toString());	// 数量
				reportSap.setMeins(detail.getUnit());		// 单位
				reportSap.setDeviceNo(task.getEquipmentCode());		// 设备号
				reportSap.setOther1("0");		// 加次
				reportSap.setRemark("0-" + detail.getId());		// 对账使用
				Result<WarehouseModelDto> result1 = storeFeignClients.getById(detail.getStoreLocationId().longValue());
				if (result1.getCode() == ResultCode.SUCCESS.getCode()){
					WarehouseModelDto dto = result1.getData();
					if (dto != null){
						reportSap.setLgort(dto.getCode());	// 库存地点
					}
				}
				reportSapGoodsmvtService.saveOrUpdate(reportSap);
			}
		}catch (Exception e){
			log.error("配料确认投料：", e);
			storeFeignClients.rollBackStore(rollBackBo);
			throw new RuntimeException("保存SAP记录异常");
		}

		// 石墨件消耗创建
		AccessoryProductionOrderDto dto = new AccessoryProductionOrderDto();
		dto.setOrderNoId(task.getScheduleId());
		dto.setProductionNo(task.getSapNo());
		dto.setDeviceCode(task.getEquipmentCode());
		dto.setMaterialCode(task.getProductCode());
		dto.setStartTime(new Date());
		dto.setCreateUser(BaseContextHandler.getUsername());
		Result<String> resultAccessory = accessoryFeignClients.create(dto);
		if (resultAccessory.getCode() != ResultCode.SUCCESS.getCode()){
			log.error("创建石墨件消耗异常: " + resultAccessory.getMessage());
			log.error("创建石墨件消耗异常报文: " + JSON.toJSONString(dto));
		}

		return ResultGenerator.success();
	}

	@Override
	public List<LoadingTask> findRealWeightByLotNo(String lotNo) {
		if (StringUtils.isEmpty(lotNo)){
			return null;
		}
		return dao.findRealWeightByLotNo(lotNo);
	}

	@Override
	public  List<BlastFurnaceDetail> findByLotNoAndProductCode(String lotNo, String code) {
		return dao.findByLotNoAndProductCode(lotNo,code);
	}

	@Override
	public LoadingTask findSuccessByLotNo(String lotNo) {
		return dao.findSuccessByLotNo(lotNo);
	}
	@Autowired
	private FormulaSchemeService formulaSchemeService;
	@Autowired
	private BlastFurnaceDetailLogService blastFurnaceDetailLogService;
	@Override
	public IngredientInfoDto findIngredientInfoById(Long id) {
		FormulaScheme formulaScheme = null;
		LoadingTask loadingTask = super.get(id);
		Assert.notNull(loadingTask, "配料任务不存在");
		LoadingTaskLog loadingTaskLog = loadingTaskLogService.getByLoadingTaskId(loadingTask.getId());
		Assert.notNull(loadingTaskLog, "配料记录不存在");
		if (Objects.nonNull(loadingTask.getRecipeId())) {
			formulaScheme = formulaSchemeService.get(loadingTask.getRecipeId());
		}
		List<BlastFurnaceDetailLog> blastFurnaceDetailLogList = blastFurnaceDetailLogService.findByBlastFurnaceId(loadingTask.getId());
		return buildLoadingTaskIngredientInfoDto(loadingTaskLog, formulaScheme, blastFurnaceDetailLogList);
	}

	@Override
	public List<Map<String, Object>> findTaskAndDetails(InputFurnaceBurdenExportParam param) {
		return dao.findTaskAndDetails(
				param.getSearch_GTE_operationTime(),
				param.getSearch_LTE_operationTime(),
				param.getSearch_LIKE_equipmentCode(),
				param.getSearch_LIKE_lotNo()
		);
	}

	@Override
	public BigDecimal findLoadingSumWeightBySapNoAndInRawStatus(String orderNo) {
		return dao.findLoadingSumWeightBySapNoAndInRawStatus(orderNo);
	}

	@Override
	public void addMaterialInfoFromWarehouse(List<TaskDetailExportDto> list) {
		Map<String, WarehouseInventoryBo> inventoryMap = new HashMap<>();
		for (TaskDetailExportDto dto : list) {
			if (!ObjectUtils.isEmpty(dto.getMaterialGear()) || !ObjectUtils.isEmpty(dto.getMaterialLevel()) || !ObjectUtils.isEmpty(dto.getSuppliesGrain())){
				continue;
			}

			Equipment equipment = equipmentService.findByCode(dto.getEquipmentCode());
			// 原料仓
			DictionaryItem dictionaryItem = dictionaryItemService.findByThemeValueAndNameAndValueAndEnable("WarehouseLocation",
					equipment.getArea(), equipment.getSeries(), true);
			if (ObjectUtils.isEmpty(dictionaryItem)) continue;
			String warehouseLocation = dictionaryItem.getExtendValue();

			String key = warehouseLocation + "-" + dto.getBatchNo();

			// 没有缓存，则查询添加缓存
			if (ObjectUtils.isEmpty(inventoryMap.get(key))){
				// 库存信息
				Result<WarehouseInventoryBo> result = storeFeignClients.getByBatchNoAndWarehouseCode(dto.getBatchNo(), warehouseLocation);
				WarehouseInventoryBo inventory = result.getData();
				if (ObjectUtils.isEmpty(inventory)) continue;
				inventoryMap.put(key, inventory);
			}
			WarehouseInventoryBo inventoryBo = inventoryMap.get(key);
			if (ObjectUtils.isEmpty(inventoryBo)) continue;

			// 设置需要补充的信息
			dto.setMaterialLevel(inventoryBo.getMaterialLevel());
			dto.setMaterialGear(inventoryBo.getMaterialGear());
			dto.setSuppliesGrain(inventoryBo.getSuppliesGrain());
		}
	}

	@Override
	public List<LoadingTask> findByConfirmTime(String startTime, String endTime) {
		return dao.findByConfirmTime(startTime, endTime);
	}

	/**
	 * 构建配料任务
	 */
	private static IngredientInfoDto buildLoadingTaskIngredientInfoDto(LoadingTaskLog loadingTaskLog, FormulaScheme formulaScheme, List<BlastFurnaceDetailLog> blastFurnaceDetailLogList) {
		ArrayList<FeedingInformationDto> informationDtoArrayList = new ArrayList<>();
		IngredientInfoDto ingredientInfoDto = new IngredientInfoDto();
		ingredientInfoDto.setIngredientUser(loadingTaskLog.getRecipeUserName());
		ingredientInfoDto.setIngredientDate(loadingTaskLog.getRecipeTime());
		ingredientInfoDto.setMissionType("初始装料");
		ingredientInfoDto.setArea(loadingTaskLog.getArea());
		ingredientInfoDto.setEquipmentCode(loadingTaskLog.getEquipmentCode());
		if (Objects.nonNull(formulaScheme) && Objects.nonNull(formulaScheme.getId())) {
			ingredientInfoDto.setProcessPlan(formulaScheme.getName());
		}
		if (!CollectionUtils.isEmpty(blastFurnaceDetailLogList)) {
			List<BlastFurnaceDetailLog> crucibleList = blastFurnaceDetailLogList.stream()
					.filter(item -> item.getMarkCrucible()==true)
					.collect(Collectors.toList());
			List<BlastFurnaceDetailLog> list = blastFurnaceDetailLogList.stream()
					.filter(blastFurnaceDetailLog -> blastFurnaceDetailLog.getMarkCrucible() == false)
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(crucibleList)) {
				BlastFurnaceDetailLog blastFurnaceDetailLog = crucibleList.get(0);
				ingredientInfoDto.setCrucibleManufacturer(blastFurnaceDetailLog.getFactoryBrand());
				ingredientInfoDto.setCrucibleBatch(blastFurnaceDetailLog.getMaterialName());
				String crucibleDimension = blastFurnaceDetailLog.getMaterialName().substring(blastFurnaceDetailLog.getMaterialName().lastIndexOf("/") + 1);
				ingredientInfoDto.setCrucibleDimension(crucibleDimension);
			}
			if (!CollectionUtil.isEmpty(list)){
				BigDecimal totalWeight = list.stream()
						.map(BlastFurnaceDetailLog::getWeight)
						.reduce(BigDecimal.ZERO, BigDecimal::add);
				list.forEach(item->{
					FeedingInformationDto feedingInformationDto = new FeedingInformationDto();
					feedingInformationDto.setBarrelCount(0);
					feedingInformationDto.setBarrelNumber(item.getMaterialCode());
					feedingInformationDto.setMaterialCode(item.getMaterialCode());
					feedingInformationDto.setMaterialName(item.getMaterialName());
					feedingInformationDto.setSupplier(item.getFactoryBrand());
					feedingInformationDto.setBatchNumber(item.getBatchNo());
					feedingInformationDto.setWeight(item.getWeight());
					feedingInformationDto.setTotalWeight(totalWeight);
					informationDtoArrayList.add(feedingInformationDto);
				});
			}
		}

		ingredientInfoDto.setFeedingInformationDtoList(informationDtoArrayList);
		return ingredientInfoDto;
	}

	private ProductionMaterialReturnRecord toLazy(ProductionMaterialReturnRecordDto recordDto) {
		return modelMapper.map(recordDto,ProductionMaterialReturnRecord.class);
	}
}
