/***文档注释***********************************************
 * 作者               :                  panbin
 * 创建日期      :                   2018.06.55
 * 描述               :                  Mes计划提供生产关于横剪方面的接口
 * 注意事项      :                   
 * 遗留BUG :                   
 * 修改日期      :                   
 * 修改人员      :                   
 * 修改内容      :                   
***********************************************************/
package market.Api.Mes.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import market.Api.Mes.service.MesApiCrCrossCuttingMService;
import market.Com.impl.PbModelDbServiceImpl;
import market.Com.mapper.ComBaseInfoMapper;
import market.Com.mapper.ComDsnPltlmtMapper;
import market.Com.vo.ComBaseInfo;
import market.Com.vo.ComDsnPltlmt;
import market.Com.vo.PbModelDb;
import market.Com.vo.ResultModel;
import market.Lms.Warehouse.mapper.YdmProductDetailMapper;
import market.Lms.Warehouse.vo.YdmProductDetail;
import market.Mes.Cuttolength.Design.mapper.PlnCuttolengthDsnMainMapper;
import market.Mes.Cuttolength.Design.mapper.PlnCuttolengthDsnMultinfoMapper;
import market.Mes.Cuttolength.Design.vo.ClRestrict;
import market.Mes.Cuttolength.Design.vo.PlnCuttolengthDsnMain;
import market.Mes.Cuttolength.Design.vo.PlnCuttolengthDsnMultinfo;
import market.Mes.Cuttolength.Plan.mapper.PlnClPlanStatisticMapper;
import market.Mes.Cuttolength.Plan.mapper.PlnCuttolengthPlanDetailMapper;
import market.Mes.Cuttolength.Plan.mapper.PlnCuttolengthPlanMapper;
import market.Mes.Cuttolength.Plan.vo.PlnClPlanStatistic;
import market.Mes.Cuttolength.Plan.vo.PlnCuttolengthPlan;
import market.Mes.Cuttolength.Plan.vo.PlnCuttolengthPlanDetail;
import market.Mes.Lengthwise.Design.mapper.PlnDsnOrderInfoMapper;
import market.Mes.Lengthwise.Design.vo.PlnDsnOrderInfo;
import market.Mes.Lengthwise.Performance.mapper.MesCrSlittingDMapper;
import market.Mes.Lengthwise.Performance.vo.MesCrSlittingD;
import market.Mes.Lengthwise.Plan.mapper.PlnMaterielDetailMapper;
import market.Mes.Lengthwise.Plan.mapper.PlnMaterielInvalidMapper;
import market.Mes.Lengthwise.Plan.mapper.PlnProcessPlanMapper;
import market.Mes.Lengthwise.Plan.vo.MesCrCrossCuttingM;
import market.Mes.Lengthwise.Plan.vo.PlnMaterielDetail;
import market.Mes.Lengthwise.Plan.vo.PlnMaterielInvalid;
import market.Mes.Lengthwise.Plan.vo.PlnProcessPlan;
import market.Mes.MaterielTrack.mapper.PrcMaterielExtinfoMapper;
import market.Mes.MaterielTrack.mapper.PrcMaterielRelationMapper;
import market.Mes.MaterielTrack.mapper.PrcMaterielVtProcessMapper;
import market.Mes.MaterielTrack.vo.PrcMaterielProcess;
import market.Mes.MaterielTrack.vo.PrcMaterielRelation;
import market.Mes.MaterielTrack.vo.PrcMaterielVtProcess;
import market.Mes.OrderManager.Plan.mapper.PlnOrderStatisticMapper;
import market.Mes.OrderManager.Plan.mapper.PlnProdorderMapper;
import market.Mes.OrderManager.Plan.mapper.PlnProdorderStatisticMapper;
import market.Mes.OrderManager.Plan.vo.PlnOrderStatistic;
import market.Mes.OrderManager.Plan.vo.PlnProdorder;
import market.Mes.OrderManager.Plan.vo.PlnProdorderStatistic;

import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import com.hnshituo.basic.service.impl.BaseServiceImpl;
import com.hnshituo.basic.spring.remoting.annotation.RemoteService;
import com.hnshituo.core.auth.service.HomeService;

@RemoteService(path = "MesApiCrCrossCuttingMService")
public class MesApiCrCrossCuttingMServiceImpl extends BaseServiceImpl implements MesApiCrCrossCuttingMService {

	
	// --------------------------------开平上料、下PDI Start----------------------------------------------------
	/**
	 * 开平上料接口 下PDI 验证 
	 * 
	 * 开平计划号数组、 计划内序号数组
	 * @throws Exception
	 * 其实都是单条操作
	 */
	// 循环 根据(开平计划号数组，虚拟物料号数组) 读取 开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】
	public void MesCrCrossCuttingMAddValid(List<MesCrCrossCuttingM> oci) throws Exception {
		for (MesCrCrossCuttingM mcsm : oci) {
			PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
			// 开平计划号
			plpd.setCl_plan_no(mcsm.getSchedule_no());
			// 计划内序号
			plpd.setCl_seq(mcsm.getInner_seq().intValue());
			// 1、读取横剪计划明细表 如果不存在，则报错退出“开平计划[xxxxx][xx]信息不存在！”
			List<PlnCuttolengthPlanDetail> lppd = this.getMapper(PlnCuttolengthPlanDetailMapper.class).find(plpd, 0, 0);
			if (lppd == null || lppd.size() == 0) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getInner_seq() + "]信息不存在！");
			}
			PlnMaterielDetail M1 = new PlnMaterielDetail();
			// 2、读取根据计划明细表中的虚拟物料号(母卷号)，查找虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息 M1
			M1.setObject_no_vt(lppd.get(0).getObject_no_vt());
			List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(M1, 0, 0);
			if (lpmd == null || lpmd.size() == 0) {
				throw new Exception("虚拟物料[" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			// 3、判断虚拟母卷信息里的 物料号【OBJECT_NO】，如果为空，则报错退出
			M1 = lpmd.get(0);
			if (M1.getObject_no() == null || "".equals(M1.getObject_no())) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" +mcsm.getInner_seq() + "]尚未挂料！");
			}

			// 实际上只有一条
			for (PlnCuttolengthPlanDetail ppdc : lppd) {
				// 4、 判断开平计划明细的状态【STATUS】
				if (ppdc.getStatus().compareTo("5BCL02") > 0) {
					throw new Exception(
							"开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getInner_seq() + "]已下发PDI/上料，不能再次操作！");
				}
			}
		}
	}

	/**
	 * 开平上料接口 下PDI
	 * 修改时间--2018-06-12
	 * 开平计划号数组、 计划内序号数组
	 * @throws Exception
	 * 其实都是单条操作
	 */
	public void MesCrCrossCuttingMAdd(List<MesCrCrossCuttingM> oci) throws Exception {
		
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		// 1、循环根据(开平计划号数组，计划内序号数组) 读取 开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】
		for (MesCrCrossCuttingM mcsm : oci) {
			PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
			// 开平计划号
			plpd.setCl_plan_no(mcsm.getSchedule_no());
			// 计划内序号
			plpd.setCl_seq(mcsm.getInner_seq()==null ? 1 : mcsm.getInner_seq().intValue());
			Date createtime= new Date();
			// 如果不存在，则报错退出“开平计划[xxxxx][xx]信息不存在！”
			List<PlnCuttolengthPlanDetail> lppd = this.getMapper(PlnCuttolengthPlanDetailMapper.class).find(plpd, 0, 0);
			if (lppd == null || lppd.size() == 0) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getInner_seq() + "]信息不存在！");
			}
			PlnMaterielDetail M1 = new PlnMaterielDetail();
			// 2、读取根据计划明细表中的虚拟物料号(母卷号)，查找虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息 M1
			M1.setObject_no_vt(lppd.get(0).getObject_no_vt());
			List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(M1, 0, 0);
			if (lpmd == null || lpmd.size() == 0) {
				throw new Exception("虚拟物料[" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			// 3、判断虚拟母卷信息里的 物料号【OBJECT_NO】，如果为空，则报错退出
			M1 = lpmd.get(0);
			if (M1.getObject_no() == null || "".equals(M1.getObject_no())) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" +mcsm.getInner_seq() + "]尚未挂料！");
			}
			// 实际上只有一条
			for (PlnCuttolengthPlanDetail ppdc : lppd) {
				// 4、判断开平计划明细的状态【STATUS】
				if (ppdc.getStatus().compareTo("5BCL02") > 0) {
					throw new Exception(
							"开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getInner_seq() + "]已上料，不能再次操作！");
				}
				// 修改开平计划明细表
				PlnCuttolengthPlanDetail plpdu = new PlnCuttolengthPlanDetail();
				plpdu.setStatus("5BCL03");
				plpdu.setSerial_no(ppdc.getSerial_no());
				this.getMapper(PlnCuttolengthPlanDetailMapper.class).update(plpdu);
			}
				PrcMaterielProcess pmp = new PrcMaterielProcess();
				pmp.setPrc_code("5BCL03");// 新增的状态
				
				// 这里的格式要和字符串日期的格式匹配，不然会抛出转换异常
				SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
				if (mcsm.getMemo() != null && !"".equals(mcsm.getMemo())) {
					Date createdate = dateFormat.parse(mcsm.getMemo());
					pmp.setCreate_time(createdate);
				} else {
					pmp.setCreate_time(new Date());
				}
				pmp.setObject_no(M1.getObject_no());
				pmp.setCreate_man_name(userName);
				pmp.setRemark("");
				// 5、新增物料跟踪：
				this.getBean(MesApiServiceImpl.class).INSERT_OBJ_PROCESS(pmp);
				// a、修改开平计划主表
				doUpdatePlnCuttolengthPlan(mcsm.getSchedule_no());
			// b、根据母卷号，查询对应的所有板垛信息
			PlnMaterielDetail pmdq = new PlnMaterielDetail();
			pmdq.setMat_object_no_vt(lpmd.get(0).getObject_no_vt());
			List<PlnMaterielDetail> lpmdc = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdq,
					"  nvl (invalid_flg, '0') <> 1 ", "", 0, 0);
			if(Utils.isNotEmpty(lpmdc)) {
				for (PlnMaterielDetail ppdc : lpmdc) {
					// c、修改各板垛的 状态 STATUS= 0PCL03;
					PlnMaterielDetail pmdu = new PlnMaterielDetail();
					pmdu.setSerial_no(ppdc.getSerial_no());
					pmdu.setStatus("0PCL03");
					this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);
	
					// 增加板垛的 虚拟物料履历表
					this.getBean(MesApiServiceImpl.class).InsertMatVtProc(ppdc.getObject_no_vt(), "0PCL03", userName,
							new Date());
				}
			}
			PlnMaterielDetail pmdu = new PlnMaterielDetail();
			// d、修改(母卷)虚拟物料表【PLN_MATERIEL_DETAIL】
			pmdu.setSerial_no(lpmd.get(0).getSerial_no());
			pmdu.setStatus("0PCL03");
			this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);

			// 写虚拟物料履历，状态填:母卷
			this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCL03", userName,
					new Date());
		}
	}

	/**
	 * 撤销开平上料接口 下PDI 验证
	 * @param 虚拟物料号
	 * @throws Exception
	 * 其实都是单条操作
	 */
	public void MesCrCrossCuttingMCancelValid(List<MesCrCrossCuttingM> oci) throws Exception {
		// 循环 根据(开平计划号数组，虚拟物料号数组) 读取 开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】
		for (MesCrCrossCuttingM mcsm : oci) {
			PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
			plpd.setCl_plan_no(mcsm.getSchedule_no());
			plpd.setObject_no_vt(mcsm.getMaterial_no_vt());
			// 如果不存在，则报错退出“开平计划[xxxxx][xx]信息不存在！”
			List<PlnCuttolengthPlanDetail> lppd = this.getMapper(PlnCuttolengthPlanDetailMapper.class).find(plpd, 0, 0);
			if (lppd == null || lppd.size() == 0) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			PlnMaterielDetail M1 = new PlnMaterielDetail();
			// 读取 根据计划明细表中的虚拟物料号(母卷号)，查找虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息 M1
			M1.setObject_no_vt(mcsm.getMaterial_no_vt());
			List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(M1, 0, 0);
			if (lpmd == null || lpmd.size() == 0) {
				throw new Exception("虚拟物料[" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			// 判断虚拟母卷信息里的 物料号【OBJECT_NO】，如果为空，则报错退出
			M1 = lpmd.get(0);
			if (M1.getObject_no() == null || "".equals(M1.getObject_no())) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]尚未挂料！");
			}

			// 实际上只有一条
			for (PlnCuttolengthPlanDetail ppdc : lppd) {
				// 判断开平计划明细的状态【STATUS】
				if (!"5BCL03".equals(ppdc.getStatus())) {
					throw new Exception(
							"开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]上料后，经过其他操作，不允许撤销！");
				}
			}
		}
	}

	/**
	 * 撤销开平上料接口 下PDI
	 * @param 虚拟子堆垛号
	 * @throws Exception
	 * 其实都是单条操作
	 */
	public void MesCrCrossCuttingMCancel(List<MesCrCrossCuttingM> oci) throws Exception {
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);

		// 循环 根据(开平计划号数组，虚拟物料号数组) 读取 开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】
		for (MesCrCrossCuttingM mcsm : oci) {
			PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
			plpd.setCl_plan_no(mcsm.getSchedule_no());
			plpd.setObject_no_vt(mcsm.getMaterial_no_vt());
			// 如果不存在，则报错退出“开平计划[xxxxx][xx]信息不存在！”
			List<PlnCuttolengthPlanDetail> lppd = this.getMapper(PlnCuttolengthPlanDetailMapper.class).find(plpd, 0, 0);
			if (lppd == null || lppd.size() == 0) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			PlnMaterielDetail M1 = new PlnMaterielDetail();
			// 读取 根据计划明细表中的虚拟物料号(母卷号)，查找虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息 M1
			M1.setObject_no_vt(mcsm.getMaterial_no_vt());
			List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(M1, 0, 0);
			if (lpmd == null || lpmd.size() == 0) {
				throw new Exception("虚拟物料[" + mcsm.getMaterial_no_vt() + "]信息不存在！");
			}

			// 判断虚拟母卷信息里的 物料号【OBJECT_NO】，如果为空，则报错退出
			M1 = lpmd.get(0);
			if (M1.getObject_no() == null || "".equals(M1.getObject_no())) {
				throw new Exception("开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]尚未挂料！");
			}

			// 实际上只有一条
			for (PlnCuttolengthPlanDetail ppdc : lppd) {
				// 判断开平计划明细的状态【STATUS】
				if (!"5BCL03".equals(ppdc.getStatus())) {
					throw new Exception(
							"开平计划[" + mcsm.getSchedule_no() + "][" + mcsm.getMaterial_no_vt() + "]上料后，经过其他操作，不允许撤销！");
				}

				PrcMaterielProcess pmp = new PrcMaterielProcess();
				pmp.setObject_no(M1.getObject_no());
				pmp.setPrc_code("5BCL03");
				pmp.setRemark("回退上料");
				pmp.setKeep_sametime_status(0);

				ResultModel al = this.getBean(MesApiServiceImpl.class).ARRAYLIST(pmp);
				// 撤销实物物料状态跟踪
				if (!"0".equals(al.getState())) {
					throw new Exception("物料状态不是已上料状态，不允许撤销！");
				}

				// 修改开平计划明细表
				PlnCuttolengthPlanDetail plpdu = new PlnCuttolengthPlanDetail();
				// "0PCL02"
				plpdu.setStatus("5BCL02");// ((PrcMaterielProcess)al.getData()).getPrc_code());
				plpdu.setSerial_no(ppdc.getSerial_no());
				this.getMapper(PlnCuttolengthPlanDetailMapper.class).update(plpdu);
			}

			// 根据母卷号，查询对应的所有板剁信息
			PlnMaterielDetail pmdq = new PlnMaterielDetail();
			pmdq.setMat_object_no_vt(lpmd.get(0).getObject_no_vt());
			List<PlnMaterielDetail> lpmdc = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdq,
					"  nvl (invalid_flg, '0') <> 1 ", "", 0, 0);
			if(Utils.isNotEmpty(lpmdc)) {
				for (PlnMaterielDetail ppdc : lpmdc) {
					// 修改各板垛的 状态 STATUS= 0PCL02;
					PlnMaterielDetail pmdu = new PlnMaterielDetail();
					pmdu.setSerial_no(ppdc.getSerial_no());
					pmdu.setStatus("0PCL02");
					this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);
					
					// 增加板垛的 虚拟物料履历表
					this.getBean(MesApiServiceImpl.class).InsertMatVtProc(ppdc.getObject_no_vt(), "0PCL02", userName,
							new Date());
				}
			}

			// 修改开平计划主表
			doUpdatePlnCuttolengthPlan(mcsm.getSchedule_no());

			PlnMaterielDetail pmdu = new PlnMaterielDetail();
			// 修改(母卷)虚拟物料表【PLN_MATERIEL_DETAIL】
			pmdu.setSerial_no(lpmd.get(0).getSerial_no());
			pmdu.setStatus("0PCL02");
			this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);

			// 写虚拟物料履历，状态填:母卷
			this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCl02", userName,
					new Date());
		}
	}
	// --------------------------------开平上料、下PDI End----------------------------------------------------

	// --------------------------------公共函数 Start----------------------------------------------------

	/**
	 * 公共函数1 修改横剪计划主表状态
	 * @param 开平计划号
	 * @throws Exception
	 */
	public void doUpdatePlnCuttolengthPlan(String clPlanNo) throws Exception {
		PlnCuttolengthPlan plp = new PlnCuttolengthPlan();
		plp.setCl_plan_no(clPlanNo);
		String MIN_STATUS = "";
		boolean flag = false;
		PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
		plpd.setCl_plan_no(clPlanNo);
		List<PlnCuttolengthPlanDetail> lplpd = this.getMapper(PlnCuttolengthPlanDetailMapper.class)
				.findWithCondition(plpd, "status <> '0PCLXX'", "status asc", 0, 0);
		if (lplpd == null || lplpd.size() == 0) {
			throw new Exception("未找到开平计划明细数据!");
		}
		MIN_STATUS = lplpd.get(0).getStatus();

		// 计划状态
		// 0PCL01开平计划已编制
		// 0PCL02开平计划已下发
		// 0PCL03开始开平作业
		// 0PCL09开平剪废
		// 0PCL10开平作业完成
		// 0PCLXX开平计划已失效

		// 实物状态
		// 5BCL01开平计划已编制
		// 5BCL02开平计划已下发
		// 5BCL03开始开平作业
		// 5BCL09开平剪废
		// 5BCL10开平作业完成
		// 5BCL33等待开平判定
		// 5BCL40开平判定完成
		// 2018-06-11
		// 如果明细记录中有卷开始作业,主表状态改为开始作业
		for (PlnCuttolengthPlanDetail plnL : lplpd) {
			if ("5BCL03".equals(plnL.getStatus())) {
				flag = true;
				break;
			}
		}
		if (flag) {
			plp.setStatus("0PCL03");
		} else if ("5BCL01".equals(MIN_STATUS)) {
			plp.setStatus("0PCL01");
		} else if (MIN_STATUS.compareTo("5BCL02") <= 0) {
			plp.setStatus("0PCL02");
		} else if (MIN_STATUS.compareTo("5BCL03") <= 0) {
			plp.setStatus("0PCL03");
		} else if (MIN_STATUS.compareTo("5BCL10") <= 0) {
			plp.setStatus("0PCL10");
		}
		this.getMapper(PlnCuttolengthPlanMapper.class).doUpdate(plp);
	}

	// --------------------------------开平完成 Start----------------------------------------------------
	/**
	 * 完成 实物 生成接口 产生实物，未挂上单时调用
	 * 修改时间--2018-06-12
	 * @param OBJECT_NO
	 *            实物母卷号
	 * @param SUB_OBJECT_NO
	 *            实物子堆垛号
	 * @param RELATION_TYPE
	 *            关系类型 1:改号(原-现号码对应)；2:轧制(板坯-钢板对应)；3:剪切/切割(母-子对应)
	 * @throws Exception
	 */
	public void CuttoLengthFinsh_PrcMatRelAdd(PrcMaterielRelation pmr) throws Exception {
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		Date createtime = new Date();
		// 调用 新增实物物料状态跟踪: 传入（实物子堆垛号,5BCL10，操作时间，操作人，""）
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setObject_no(pmr.getSub_object_no());
		pmp.setPrc_code("5BCL10");// 新增的状态
		pmp.setCreate_time(createtime);
		pmp.setCreate_man_name(userName);
		pmp.setRemark("");
		// 新增物料跟踪：
		this.getBean(MesApiServiceImpl.class).INSERT_OBJ_PROCESS(pmp);

		// 调用公共函数2 建立物料母子对应关系
		pmr.setCreate_man_name(userName);
		pmr.setCreate_time(createtime);
		pmr.setRemark("子垛生成，未挂上单");
		pmr.setRelation_type(3);
		this.getBean(MesApiServiceImpl.class).doBuildRelation(pmr);
	}

	/**
	 * 撤销开平 实物 撤销生成接口 产生实物，未挂上单时调用
	 * @param OBJECT_NO
	 *            实物母卷号
	 * @param SUB_OBJECT_NO
	 *            实物子堆垛号
	 * @throws Exception
	 */
	public void CuttoLengthFinsh_PrcMatRelRemove(PrcMaterielRelation pmr) throws Exception {
		// 回退子堆垛物料跟踪：
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setObject_no(pmr.getSub_object_no());
		pmp.setPrc_code("5BCL10");
		pmp.setKeep_sametime_status(0);
		pmp.setRemark("撤销开平实物生成");
		ResultModel al = this.getBean(MesApiServiceImpl.class).ARRAYLIST(pmp);
		// 撤销实物物料状态跟踪
		if (!"0".equals(al.getState())) {
			throw new Exception("实物[" + pmp.getObject_no() + "]状态已发生改变，不能撤销！");
		}

		// 调用公共函数3 断开物料母子对应关系
		PrcMaterielRelation pmrd = new PrcMaterielRelation();
		pmrd.setObject_no(pmr.getObject_no());
		pmrd.setSub_object_no(pmr.getSub_object_no());
		this.getBean(MesApiServiceImpl.class).doBuildRelationRemove(pmrd);
	}

	/**
	 * 开平完成 虚拟子堆垛 挂料接口
	 * 修改时间--2018-06-12
	 * @param OBJECT_NO  实物母堆垛号
	 * @param object_no_vt  虚拟子堆垛号
	 * @param sub_object_no 实物子堆垛号
	 * @throws Exception
	 */
	public void CuttoLengthFinsh_Relation(PlnMaterielDetail pmd) throws Exception {
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		// 新增物料附加信息
		this.getBean(MesApiDesignInfoImpl.class).addChildMaterielExinfo(pmd.getObject_no(), pmd.getSub_object_no(), pmd.getObject_no_vt(), processpoint.cross_cutting_code);
		
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		Date createTime = new Date();
		// 1、调用物流接口，获取实物子堆垛信息。
		YdmProductDetail ypd = new YdmProductDetail();
		ypd.setCoilno(pmd.getSub_object_no());
		List<YdmProductDetail> lypd = this.getMapper(YdmProductDetailMapper.class).find(ypd, 0, 0);
		if (lypd == null || lypd.size() == 0) {
			throw new Exception("库存中无[" + pmd.getSub_object_no() + "]实物堆垛!");
		}
		// 2、读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟子堆垛信息
		PlnMaterielDetail pmdq = new PlnMaterielDetail();
		pmdq.setObject_no_vt(pmd.getObject_no_vt());
		List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(pmdq, 0, 0);
		// 3、判断实物堆垛和虚拟堆垛的 牌号、厚、宽、长 是否相等（考虑公差）
		// 长和宽考虑公差 2018-06-13
		// 开平成品长度允许公差(mm) (base_code)386201上-386202下,宽度允许公差386301-386302
		// 定义变量wUpper=0,wLower=0,lUpper,lLower（数值型，实数），分别从基础信息表（COM_BASE_INFO）获取编号（BASE_CODE）=“386201”、“386102”的值（MEMO）并验证，
		// 只有当记录存在，且值（MEMO）为有效数值时，对应进行赋值：其中dUpper对应381601、dLower对应386102；当381601的值无效时
		// （无此记录或为空或不是有效数值），dUpper = 5（缺省值）；，当381602的值无效时（无此记录或为空或不是有效数值），dLower= -5（缺省值）；
		double wUpper = 0, wLower = 0, lUpper = 0, lLower = 0;
		ResultModel rmDb = this.getBean(PbModelDbServiceImpl.class).findMesProductWidthCmbDb();
		if ("200".equals(rmDb.getState())) {
			if (rmDb.getData() != null) {
				// 宽上限
				wUpper = 5;
				wLower = -5;
				// 长上限
				lUpper = 5;
				lLower = 5;
				try {
					@SuppressWarnings("unchecked")
					List<PbModelDb> pmdb = (List<PbModelDb>) rmDb.getData();
					for (PbModelDb model : pmdb) {
						if ("386201".equals(model.getId())) {
							wUpper = Double.parseDouble(model.getRegionkey());
						} else if ("386202".equals(model.getId())) {
							wLower = Double.parseDouble(model.getRegionkey());
						} else if ("386301".equals(model.getId())) {
							lUpper = Double.parseDouble(model.getRegionkey());
						} else if ("386302".equals(model.getId())) {
							lLower = Double.parseDouble(model.getRegionkey());
						}
					}
				} catch (Exception e) {
				}
			}
		}
		if (lpmd == null || lpmd.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]堆垛!");
		}

		if (!lypd.get(0).getSteelcode().equals(lpmd.get(0).getSteel_code())) {
//			throw new Exception("实物堆垛[" + pmd.getSub_object_no() + "]和虚拟堆垛[" + pmd.getObject_no_vt() + "]的牌号不匹配，不能绑定");
		}
//		if (lypd.get(0).getThick().doubleValue() != lpmd.get(0).getThick().doubleValue()) {
//			throw new Exception("实物堆垛[" + pmd.getSub_object_no() + "]和虚拟堆垛[" + pmd.getObject_no_vt() + "]的厚不匹配，不能绑定");
//		}
		if ((lypd.get(0).getWidth().doubleValue() - lpmd.get(0).getWidth().doubleValue() > wUpper)
				|| (lypd.get(0).getWidth().doubleValue() - lpmd.get(0).getWidth().doubleValue() < wLower)) {
			throw new Exception("实物堆垛[" + pmd.getSub_object_no() + "]和虚拟堆垛[" + pmd.getObject_no_vt() + "]的宽不匹配，不能绑定");
		}
		if ((lypd.get(0).getLength().doubleValue() - lpmd.get(0).getLength().doubleValue()>lUpper) ||
				(lypd.get(0).getLength().doubleValue() - lpmd.get(0).getLength().doubleValue()< lLower)){
			throw new Exception("实物堆垛[" + pmd.getSub_object_no() + "]和虚拟堆垛[" + pmd.getObject_no_vt() + "]的长不匹配，不能绑定");
		}
		if (lpmd.get(0).getSub_object_no() != null && !"".equals(lpmd.get(0).getSub_object_no())) {
			throw new Exception("实物堆垛[" + pmd.getSub_object_no() + "]已绑定其他计划, 不能再次绑定！");
		}

		// 5、修改数据
		// a 修改虚拟物料表
		pmdq.setSerial_no(lpmd.get(0).getSerial_no());
		pmdq.setObject_no(pmd.getSub_object_no());
		pmdq.setStatus("0PCL10");
		pmdq.setIs_finished("1");
		// 横剪工序代码
//		pmdq.setPrev_process_code(processpoint.cross_cutting_code); 
		// TODO (根据加工计划判断，下一工序是12mm还是包装，填写对应的工序代码,没有则填空)
		// pmdq.setNext_process_code("60001"); 暂时不填将来加工序再改
		this.getMapper(PlnMaterielDetailMapper.class).update(pmdq);

		// b 新增虚拟子物料履历
		this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCL10", userName,createTime);
		
		// 4、调用 新增实物物料状态跟踪: 传入（实物子堆垛号,5BCL10，操作时间，操作人，""）
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setObject_no(pmd.getSub_object_no());
		pmp.setPrc_code("5BCL10");// 新增的状态
		pmp.setCreate_time(createTime);
		pmp.setCreate_man_name(userName);
		pmp.setRemark("");
		// 新增物料跟踪：
		this.getBean(MesApiServiceImpl.class).INSERT_OBJ_PROCESS(pmp);
				
		// c ----------------------------2018-06-19 去掉判断虚拟子物料是否有其他子料的原料-------------------------------
			// 修改改虚拟子物料对应的 订单进程表[PLN_ORDER_STATISTIC]
			PlnOrderStatistic pos = new PlnOrderStatistic();
			pos.setOrder_no(lpmd.get(0).getOrder_no());
			pos.setCl(lpmd.get(0).getSingle_weight());
			pos.setCl_cnt(1);
			this.getMapper(PlnOrderStatisticMapper.class).doUpdateClPlaned(pos);

			// 生产订单进程表[PLN_PRODORDER_STATISTIC]信息
			PlnProdorderStatistic pps = new PlnProdorderStatistic();
			pps.setProd_order_no(lpmd.get(0).getProd_order_no());
			pps.setCl(lpmd.get(0).getSingle_weight());
			pps.setCl_cnt(1);
			this.getMapper(PlnProdorderStatisticMapper.class).doUpdatePlaned(pps);

		// ----------------------------------------------------------------
		// d 修改虚拟物料对应的 开平计划进程表
		PlnMaterielDetail pmdmq = new PlnMaterielDetail();
		pmdmq.setObject_no_vt(lpmd.get(0).getMat_object_no_vt());
		List<PlnMaterielDetail> lpmdm = this.getMapper(PlnMaterielDetailMapper.class).find(pmdmq, 0, 1);
		if (lpmdm != null && lpmdm.size() > 0) {
			PlnClPlanStatistic plps = new PlnClPlanStatistic();
			plps.setCl_plan_no(lpmdm.get(0).getCl_plan_no());
			plps.setCl(lpmd.get(0).getSingle_weight());
			plps.setCl_cnt(1);
			this.getMapper(PlnClPlanStatisticMapper.class).doUpdatePlaned(plps);
		}

		// 6、调用公共函数2 建立物料母子对应关系
		PrcMaterielRelation pmr = new PrcMaterielRelation();
		pmr.setObject_no(pmd.getObject_no());
		pmr.setSub_object_no(pmd.getSub_object_no());
		pmr.setCreate_man_name(userName);
		pmr.setCreate_time(createTime);
		pmr.setRemark("");
		pmr.setRelation_type(3);
		this.getBean(MesApiServiceImpl.class).doBuildRelation(pmr);
		
	}
	
	/**
	 * 开平完成 不符合计划
	 * 实物生成, 新增虚拟子堆垛挂料
	 * @param sub_object_no 实物子堆垛号
	 * @param material_no 实物母卷号
	 * @param create_time 操作时间
	 * 注意 传入操作时间 新增履历表和实物进程表的创建时间，使用传入的操作时间
	 * @throws Exception 
	 * 2018-06-19
	 */
	public ResultModel CuttolengthFinsh_No_Plan(PlnMaterielDetail pmd) throws Exception {
		ResultModel rm = new ResultModel("200", "");
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		Date createTime = new Date();
		//调用物流接口，获取实物子堆垛信息。
		YdmProductDetail ypd=new YdmProductDetail();
		ypd.setCoilno(pmd.getSub_object_no());
		List<YdmProductDetail> lypd=this.getMapper(YdmProductDetailMapper.class).find(ypd, 0, 0);
		if(lypd==null||lypd.size()==0){
			throw new Exception("库存中无["+pmd.getObject_no()+"]实物堆垛!");
		}
		// 获取母卷虚拟物料信息
		PlnMaterielDetail pmdcm=new PlnMaterielDetail();
		pmdcm.setObject_no(pmd.getObject_no());
		List<PlnMaterielDetail> pmdpp = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdcm, " nvl(invalid_flg,0) = 0 ", "", 0, 1);
		if (pmdpp == null || pmdpp.size()==0) {
			rm.setState("500");
			rm.setMsgInfo("实物["+pmd.getObject_no()+"]的虚拟物料信息不存在!");
			return rm;
		}
		// 获取生产订单信息
		PlnProdorder pp=new PlnProdorder();
		pp.setProd_order_no(pmdpp.get(0).getProd_order_no());
		List<PlnProdorder> lpp=this.getMapper(PlnProdorderMapper.class).find(pp, 0, 1);
		if(lpp==null||lpp.size()==0){
			rm.setState("500");
			rm.setMsgInfo("生产订单["+pp.getProd_order_no()+"]不存在!");
			return rm;
		}
		
		// 获取下一个工序
		String temp = this.getBean(MesApiDesignInfoImpl.class)
				.getPath(lpp.get(0).getWhole_process_codes(), processpoint.cross_cutting_code, pmdpp.get(0).getProc_repeat_index());
		String[] path =  temp.split("-");
		ArrayList<String> validpath = this.getBean(MesApiDesignInfoImpl.class).getProcessPath(path);
				
				
		// 新建虚拟物料表【PLN_MATERIEL_DETAIL】虚拟子堆垛信息
		PlnMaterielDetail pmdc=new PlnMaterielDetail();
		// 获取序列号
		List<PlnMaterielDetail> lpmd=this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(null, null, " serial_no desc ", 0, 1);
		long PMDNo=lpmd==null?1:(lpmd.size()==0?1:(lpmd.get(0).getSerial_no()+1));
		// 6位日期
		String sDate=new SimpleDateFormat("yyMMdd").format(new Date());
		// 6位流水号
		int objectnoVtNo=this.getMapper(PlnMaterielDetailMapper.class).getObjectVtMaxNoForDate(sDate)+1;
		pmdc.setSerial_no(PMDNo++);
		// 年月日(6位)+6位流水
		pmdc.setObject_no_vt(sDate+String.format("%06d", objectnoVtNo));
		pmdc.setOrder_no(lpp.get(0).getOrder_no());
		pmdc.setObject_no(pmd.getSub_object_no());
		pmdc.setPline_code(lpp.get(0).getPline_code());
		pmdc.setStatus("0PCL10");
		pmdc.setIs_finished("1");
		pmdc.setPrev_dsn_process_code(processpoint.cross_cutting_code);
		pmdc.setPrev_process_code(processpoint.cross_cutting_code);
		// 获取下个工序代码暂时方法,将来从质量取值
//		String process_code = this.getBean(MesApiCrCrossCuttingMServiceImpl.class).getNext_process("2",
//				pmd.getObject_no_vt());
//		if (process_code != null && !"".equals(process_code)) {
//			pmdc.setNext_process_code(process_code);
//			pmdc.setNext_dsn_process_code(process_code);
//		}
		if (Utils.isNotEmpty(validpath)) {
			pmdc.setNext_dsn_process_code(validpath.get(0));
			pmdc.setNext_process_code(validpath.get(0));
		}
		pmdc.setIs_prev_dsn_finished("1");//母卷：0
		pmdc.setCreate_design_no(pmdpp.get(0).getCl_design_no());
		pmdc.setCreate_process_code(processpoint.cross_cutting_code);
		pmdc.setIs_mat(0);//母卷：1
		pmdc.setOrder_no(lpp.get(0).getOrder_no());
		pmdc.setProd_order_no(lpp.get(0).getProd_order_no());
		pmdc.setCl_design_no(pmdpp.get(0).getCl_design_no());
		pmdc.setCl_plan_no(pmdpp.get(0).getCl_plan_no());
		pmdc.setPline_code(lpp.get(0).getPline_code());
		pmdc.setMat_object_no_vt(pmdpp.get(0).getObject_no_vt());
		pmdc.setIs_multi("0");
		pmdc.setSteel_code(lpp.get(0).getSteel_code());
		pmdc.setWidth(lypd.get(0).getWidth());
		pmdc.setThick(lypd.get(0).getThick());
		pmdc.setLength(lypd.get(0).getLength());
		pmdc.setDiameter_inn(lypd.get(0).getDiameter_inn());
		pmdc.setDiameter_out(lypd.get(0).getDiameter_out());
		pmdc.setSingle_weight(lypd.get(0).getFactweight());
		pmdc.setFixed_length_type_no(lpp.get(0).getFixed_length_type_no());
		pmdc.setCut_edge_type_no(lpp.get(0).getCut_edge_type_no());
		pmdc.setOrd_flg("2");
		pmdc.setCreate_man_name(userName);
		pmdc.setCreate_time(createTime);
		pmdc.setDeliver_date_earliest(lpp.get(0).getDeliver_date());
		pmdc.setDeliver_date_latest(lpp.get(0).getDeliver_date());
		this.getMapper(PlnMaterielDetailMapper.class).insert(pmdc);
		
		// 新增物料附加信息
				this.getBean(MesApiDesignInfoImpl.class).addChildMaterielExinfo(pmd.getObject_no(), pmd.getSub_object_no(), pmdc.getObject_no_vt(), processpoint.cross_cutting_code);
		// 子卷存在下一个工序
		if (Utils.isNotEmpty(validpath)) {
			// 调用设计信息接口
			List<DesignInfo> infos = new ArrayList<>();
			DesignInfo infor = new DesignInfo();
			infor.setCurrentProcIndex(0);
			infor.setObject_no(pmd.getSub_object_no());
			infor.setObject_no_vt(pmdc.getObject_no_vt());
			infor.setProcess(validpath);
			infor.setProd_order_no(pmdpp.get(0).getProd_order_no());
			infor.setSingle_wgt(lypd.get(0).getFactweight());
			infos.add(infor);
			ResultModel result = this.getBean(MesApiDesignInfoImpl.class)
					.Design_Plan_Info(infos, null);
			if (!"200".equals(result.getState())) {
				throw new Exception("生产设计信息失败" + result.getMsgInfo());
			}
		}
		
		// 反写子卷实绩的虚拟物料号 2018-09-20
		MesCrSlittingD mcd = new MesCrSlittingD();
		mcd.setCoil_no(pmd.getSub_object_no());
		mcd.setCoil_no_vt(pmdc.getObject_no_vt());
		this.getMapper(MesCrSlittingDMapper.class).update(mcd);
		
		// 反写实物虚拟卷号 2018-11-08
		ypd.setObject_no_vt(pmdc.getObject_no_vt());
		this.getMapper(YdmProductDetailMapper.class).update(ypd);
					
		//调用 新增实物物料状态跟踪:  传入（实物子堆垛号,5BCl10，操作时间，操作人，""）
		PrcMaterielProcess pmp=new PrcMaterielProcess();
		pmp.setObject_no(pmd.getSub_object_no());
		pmp.setPrc_code("5BCL10");
		pmp.setCreate_time(createTime);
		pmp.setCreate_man_name(userName);
		pmp.setRemark("");
		// 新增物料跟踪：
		this.getBean(MesApiServiceImpl.class).INSERT_OBJ_PROCESS(pmp);
		
		// 新增虚拟子物料履历																			
		this.getBean(MesApiServiceImpl.class).InsertMatVtProc(pmdc.getObject_no_vt(),"0PCL10",userName,createTime);
		
		// 修改改虚拟子物料对应的 订单进程表[PLN_ORDER_STATISTIC]
		PlnOrderStatistic pos = new PlnOrderStatistic();
		pos.setOrder_no(lpp.get(0).getOrder_no());
		pos.setCl(pmdc.getSingle_weight());
		pos.setCl_cnt(1);
		this.getMapper(PlnOrderStatisticMapper.class).doUpdatePlaned(pos);

		// 生产订单进程表[PLN_PRODORDER_STATISTIC]信息
		PlnProdorderStatistic pps = new PlnProdorderStatistic();
		pps.setProd_order_no(pmdc.getProd_order_no());
		pps.setCl(pmdc.getSingle_weight());
		pps.setCl_cnt(1);
		this.getMapper(PlnProdorderStatisticMapper.class).doUpdatePlaned(pps);
		
		//修改虚拟物料对应的 开平计划进程表
		PlnMaterielDetail pmdmq=new PlnMaterielDetail();
		pmdmq.setObject_no_vt(pmdc.getMat_object_no_vt());
		List<PlnMaterielDetail> lpmdm=this.getMapper(PlnMaterielDetailMapper.class).find(pmdmq, 0, 1);
		PlnClPlanStatistic plps=new PlnClPlanStatistic();
		plps.setCl_plan_no(lpmdm.get(0).getCl_plan_no());
		plps.setCl(pmdc.getSingle_weight());
		plps.setCl_cnt(1);
		this.getMapper(PlnClPlanStatisticMapper.class).doUpdatePlaned(plps);
		
		//调用公共函数2  建立物料母子对应关系 
		PrcMaterielRelation pmr=new PrcMaterielRelation();
		pmr.setObject_no(pmd.getMaterial_no());
		pmr.setSub_object_no(pmd.getSub_object_no());
		pmr.setCreate_man_name(userName);
		pmr.setCreate_time(createTime);
		pmr.setRemark("");
		pmr.setRelation_type(3);
		this.getBean(MesApiServiceImpl.class).doBuildRelation(pmr);
		return rm;
	}

	/**
	 * 撤销开平 虚拟子堆垛 挂料接口
	 * @param OBJECT_NO
	 *            实物子堆垛号
	 * @param object_no_vt
	 *            虚拟子堆垛号
	 * @throws Exception
	 */
	public void CuttoLengthFinsh_RelationCancel(PlnMaterielDetail pmd) throws Exception {
		
		if (pmd == null || pmd.getObject_no() ==null || "".equals(pmd.getObject_no())) {
			throw new Exception( "请传入子堆垛物料信息（实物子堆垛）!");
		}
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		Date createTime = new Date();
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		// 调用物流接口，获取实物子堆垛信息。
		YdmProductDetail ypd = new YdmProductDetail();
		ypd.setCoilno(pmd.getObject_no());
		List<YdmProductDetail> lypd = this.getMapper(YdmProductDetailMapper.class).find(ypd, 0, 0);
		if (lypd == null || lypd.size() == 0) {
			throw new Exception("库存中无[" + pmd.getObject_no() + "]实物堆垛!");
		}

		// 读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟子堆垛信息
		PlnMaterielDetail pmdq = new PlnMaterielDetail();
		pmdq.setObject_no(pmd.getObject_no());
		List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdq, " nvl(invalid_flg,0) = 0 "," create_time desc",0, 1);
		if (lpmd == null || lpmd.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]堆垛!");
		}
		// 如果没有传入虚拟子卷号，从虚拟物料信息中查询
		if (pmd.getObject_no_vt() == null || "".equals(pmd.getObject_no_vt())) {
						pmd.setObject_no_vt(lpmd.get(0).getObject_no_vt());
					}
		// 读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟子堆垛的母卷信息
		List<PlnMaterielDetail> lpmdm = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(null, "object_no_vt = '"+lpmd.get(0).getMat_object_no_vt()+"' and nvl(invalid_flg,0) = '0'", null, 0, 1);
		if (lpmdm == null || lpmdm.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]堆垛!");
		}

		if (lpmdm.get(0).getObject_no() == null || "".equals(lpmdm.get(0).getObject_no())) {
			throw new Exception("实物堆垛[" + pmd.getObject_no() + "]尚未绑定该计划，不能回退！");
		}
		
		// 物料充当脱单履历
//		this.getBean(MesApiDesignInfoImpl.class).createMatLog(lpmd.get(0), "厂内合同取消交工",userName, lpmd.get(0).getPrev_process_code() , "-1", pmd.getObject_no());
		
		// 下一个工序做了计划就不能回退
		if (Utils.isNotEmpty(pmd.getNext_dsn_process_code())) {
		this.getBean(MesApiDesignInfoImpl.class).JudgeIsOrNotPlan(lpmd.get(0));
		}

		// 回退子堆垛物料跟踪：
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setObject_no(pmd.getObject_no());
		pmp.setPrc_code("5BCL10");
		pmp.setKeep_sametime_status(0);
		pmp.setRemark("撤销子堆垛挂料");
		// 撤销实物物料状态跟踪
		ResultModel al = this.getBean(MesApiServiceImpl.class).ARRAYLIST(pmp);
		if (!"0".equals(al.getState())) {
			throw new Exception("开平完成后，实物[" + pmp.getObject_no() + "]状态已发生改变，不能撤销！");
		}

		// 修改虚拟物料表
		PlnMaterielDetail pmdu = new PlnMaterielDetail();
		pmdu.setObject_no_vt(pmd.getObject_no_vt());
		pmdu.setSerial_no(lpmd.get(0).getSerial_no());
		pmdu.setStatus("0PCL03");
		pmdu.setIs_finished("0");
		pmdu.setPrev_process_code(processpoint.cross_cutting_code);
		// TODO 将来再加判断"包装"or"12mm"
		this.getMapper(PlnMaterielDetailMapper.class).doUpdateCancelRelation(pmdu);

		// 新增虚拟子物料履历
		this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCL03", userName,createTime);

		// --------------------2018-06-19 去掉 判断虚拟子物料是否有其他子料的原料-------------
			// 修改改虚拟子物料对应的 订单进程表[PLN_ORDER_STATISTIC]
			PlnOrderStatistic pos = new PlnOrderStatistic();
			pos.setOrder_no(lpmd.get(0).getOrder_no());
			pos.setCl(lpmd.get(0).getSingle_weight() == null ? null : (-lpmd.get(0).getSingle_weight()));
			pos.setCl_cnt(-1);
			this.getMapper(PlnOrderStatisticMapper.class).doUpdateClPlaned(pos);

			// 生产订单进程表[PLN_PRODORDER_STATISTIC]信息
			PlnProdorderStatistic pps = new PlnProdorderStatistic();
			pps.setProd_order_no(lpmd.get(0).getProd_order_no());
			pps.setCl(lpmd.get(0).getSingle_weight() == null ? null : (-lpmd.get(0).getSingle_weight()));
			pps.setCl_cnt(-1);
			this.getMapper(PlnProdorderStatisticMapper.class).doUpdatePlaned(pps);
		// ------------------------------------------------------------------------------

		// 修改虚拟物料对应的 开平计划进程表
		PlnClPlanStatistic plps = new PlnClPlanStatistic();
		plps.setCl_plan_no(lpmdm.get(0).getCl_plan_no());
		plps.setCl(lpmd.get(0).getSingle_weight() == null ? null : (-lpmd.get(0).getSingle_weight()));
		plps.setCl_cnt(-1);
		this.getMapper(PlnClPlanStatisticMapper.class).doUpdatePlaned(plps);

		// 调用公共函数3 断开物料母子对应关系
		PrcMaterielRelation pmr = new PrcMaterielRelation();
		pmr.setObject_no(lpmdm.get(0).getObject_no());
		pmr.setSub_object_no(lpmd.get(0).getObject_no());
		this.getBean(MesApiServiceImpl.class).doBuildRelationRemove(pmr);
		
		// 厂内合同子卷生产完成时,清空库存信息订单信息
//		boolean flag_Ct = this.getBean(MesApiDesignInfoImpl.class).getContractType(lpmd.get(0).getProd_order_no());
//		boolean flag_Mf = this.getBean(MesApiDesignInfoImpl.class).matIsFinish(pmd.getObject_no());
//		if (flag_Mf && flag_Ct) {
//			YdmProductDetail ydm = new YdmProductDetail();
//			ydm.setCoilno(pmd.getObject_no());
//			ydm.setProdorderno(lpmd.get(0).getProd_order_no());
//			ydm.setOrderno(lpmd.get(0).getOrder_no());
//			ydm.setObject_no_vt(pmd.getObject_no_vt());
//			this.getMapper(YdmProductDetailMapper.class).update(ydm);
//		}
		// 删除物料附加信息
		this.getMapper(PrcMaterielExtinfoMapper.class).delete(pmd.getObject_no());
				
		// 判断虚拟子堆垛信息，是否是额外的成品(ORD_FLG = 2), 如果是，则需释放虚拟子堆垛，调用接口:横剪——虚拟子堆垛 释放接口
		if ("2".equals(lpmd.get(0).getOrd_flg())) {
			CuttoLengthFinsh_Release(pmd);
		}
	}

	/**
	 * 开平完成 虚拟子堆垛 释放接口
	 * @param object_no_vt 虚拟子堆垛号
	 * @throws Exception
	 * 2018-06-12
	 */
	public void CuttoLengthFinsh_Release(PlnMaterielDetail pmd) throws Exception {
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		Date createTime = new Date();
		
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		// 读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟子堆垛信息
		PlnMaterielDetail pmdq = new PlnMaterielDetail();
		pmdq.setObject_no_vt(pmd.getObject_no_vt());
		List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(pmdq, 0, 0);
		if (lpmd == null || lpmd.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]堆垛!");
		}

		// 判断虚拟子堆垛是否是开平的虚拟成品
		if (!processpoint.cross_cutting_code.equals(lpmd.get(0).getPrev_dsn_process_code())) {
			throw new Exception("虚拟子堆垛不是开平设计成品，无法释放！");
		}

		// ------------------------2018-06-19-------------------------
		// 判断虚拟子板信息，是否是额外的成品(ORD_FLG = 2), 如果不成立， 则报错退出，“虚拟物料[xxx]不是额外成品，不能释放！”
		if (!"2".equals(lpmd.get(0).getOrd_flg())) {
			throw new Exception("虚拟物料[" + pmd.getObject_no_vt() + "]不是额外成品，不能释放！");
		}
		
		PlnMaterielDetail pmdqd=new PlnMaterielDetail();
		pmdqd.setMat_object_no_vt(pmd.getObject_no_vt());
		List<PlnMaterielDetail> child = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(null, "mat_object_no_vt = '"+pmd.getObject_no_vt()+"' and nvl(invalid_flg,0) = '0'", null, 0, 0);
//		int count = this.getMapper(PlnMaterielDetailMapper.class).count(pmdqd);
		if (Utils.isNotEmpty(child)) {
			// 删除子卷
			this.getBean(MesApiDesignInfoImpl.class).deleteChildTrue(child);
//			throw new Exception("虚拟子卷["+pmd.getObject_no_vt()+"]作为后一工序的原料，已经挂单，无法释放！");
		}
		// ------------------------------------------------------------

		// 判断虚拟子堆垛是否是其他物料母卷: IF(NEXT_DSN_PROCESS_CODE == NULL)
		if (lpmd.get(0).getNext_dsn_process_code() == null || "".equals(lpmd.get(0).getNext_dsn_process_code())) {
			// 新增虚拟物料履历表【PRC_MATERIEL_VT_PROCESS】记录，状态标记为“0PCLXX”
			this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCLXX", userName,createTime);
			// 将虚拟物料信息 从虚拟物料表【PLN_MATERIEL_DETAIL】移动到 无效虚拟物料表【PLN_MATERIEL_INVALID】.
			// (两个表结构一样，移动后，保持serial_no不变，删除原表记录)
			List<PlnMaterielInvalid> pmin = this.getMapper(PlnMaterielInvalidMapper.class).findWithCondition(null, " serial_no = '"+lpmd.get(0).getSerial_no()+"' or object_no_vt = '"+lpmd.get(0).getObject_no_vt()+"'", "", 0, 0);
			if (pmin !=null && pmin.size()>0) {
				this.getMapper(PlnMaterielInvalidMapper.class).delete(lpmd.get(0).getSerial_no());
			}
			PlnMaterielInvalid pmi = new PlnMaterielInvalid();
			BeanUtils.copyProperties(lpmd.get(0), pmi);
			this.getMapper(PlnMaterielInvalidMapper.class).insert(pmi);
			this.getMapper(PlnMaterielDetailMapper.class).doDeleteId(lpmd.get(0));
		}
	}

	/**
	 * 开平完成 虚拟母卷统计
	 * @param object_no_vt
	 *            虚拟母卷号
	 * @param object_no
	 *            实物母卷号
	 * @throws Exception
	 */
	@Transactional(value = "tm", rollbackFor = Exception.class)
	public void CuttoLengthFinsh_Sum(PlnMaterielDetail pmd) throws Exception {
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		Date createTime = new Date();
		String plan_no = "";
		String object_no = "";
		
		// 工序点信息
				List<ComBaseInfo> infoi = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null,
						"sort_code = '2002' AND validflag = '1'", null, 0, 0);
				ProcessPoint processpoint = new ProcessPoint(infoi);
				
				// 修改物料附加信息
				this.getBean(MesApiDesignInfoImpl.class).updateMExInfo(pmd.getObject_no(), processpoint.cross_cutting_code,true);
				
		// 1、读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息
		PlnMaterielDetail pmdq = new PlnMaterielDetail();
		pmdq.setObject_no_vt(pmd.getObject_no_vt());
		List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdq, "nvl(invalid_flg , 0) <> 1", null, 0, 1);
		plan_no = lpmd.get(0).getCl_plan_no();
		if (lpmd == null || lpmd.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]堆垛!");
		}
		if (lpmd.get(0).getObject_no() == null || "".equals(lpmd.get(0).getObject_no())) {
			throw new Exception("计划母卷[" + pmd.getObject_no() + "]未上料, 不能开平！");
		}
		// 2、新增母卷物料跟踪：调用 新增实物物料状态跟踪
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setPrc_code("5BCL10");// 新增的状态
		pmp.setCreate_time(createTime);
		pmp.setObject_no(pmd.getObject_no());
		pmp.setCreate_man_name(userName);
		pmp.setRemark("");
		// 新增物料跟踪：
		this.getBean(MesApiServiceImpl.class).INSERT_OBJ_PROCESS(pmp);
		///3、判断虚拟母卷对应的虚拟子堆垛是否 挂料完成
		PlnMaterielDetail pmdc = new PlnMaterielDetail();
		pmdc.setMat_object_no_vt(lpmd.get(0).getObject_no_vt());
		List<PlnMaterielDetail> lpmdc = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(pmdc, "nvl(invalid_flg , 0) <> 1", null, 0, 0);
		int isum = 0;
		if (lpmdc != null && lpmdc.size() > 0) {
			for (PlnMaterielDetail pmdcc : lpmdc) {
				// a 2018-06-13 无论是否挂单,横剪都已经完成
				PlnMaterielDetail pmdcu = new PlnMaterielDetail();
				pmdcu.setSerial_no(pmdcc.getSerial_no());
				pmdcu.setIs_finished("1");
				this.getMapper(PlnMaterielDetailMapper.class).update(pmdcu);
				// b 统计 (OBJECT_NO=NULL的子堆垛数量)、虚拟子堆垛总数量
				if (pmdcc.getObject_no() == null || "".equals(pmdcc.getObject_no())) {
					isum += 1;
				}
			}
			// 4、如果（OBJECT_NO为NULL的数量==子堆垛总数
			if (isum == lpmdc.size()) {
				// 读取物料关系表【PRC_MATERIEL_RELATION】(where OBJECT_NO=实物母卷号 AND RELATION_TYPE=3)的记录
				PrcMaterielRelation pmr = new PrcMaterielRelation();
				pmr.setObject_no(lpmd.get(0).getObject_no());
				pmr.setRelation_type(3);
				List<PrcMaterielRelation> lpmr = this.getMapper(PrcMaterielRelationMapper.class).find(pmr, 0, 0);
				if (lpmr == null || lpmr.size() == 0) {
					// 如果 关系表记录为空（说明实物卷未切割，计划未执行）,直接报错退出“母卷xxxx尚未进行切割操作！”；
					throw new Exception("母卷[" + pmr.getObject_no() + "]尚未进行切割操作！");
				} else {
					// 脱掉 虚拟母卷和实物卷的关系
					// 修改虚拟物料表的母卷记录：IS_NEXT_FINISHED=0;OBJECT_NO=NULL; NEED_EXTOPT=1;CL_PLAN_NO=NULL
					PlnMaterielDetail pmdu = new PlnMaterielDetail();
					pmdu.setObject_no_vt(lpmd.get(0).getObject_no_vt());
					pmdu.setNeed_extopt("1");
					pmdu.setIs_next_finished("0");
					this.getMapper(PlnMaterielDetailMapper.class).doUpdateCuttoLengthFinshSum(pmdu);
				}
			}else {
				// 2018-10-16 挂单的时候一起修改了
//				this.getBean(MesApiDesignInfoImpl.class).updatePlnStatic(lpmd.get(0).getProd_order_no(), lpmd.get(0).getOrder_no(), lpmd.get(0).getNext_dsn_process_code(), lpmd.get(0).getSingle_weight(), true);
			}
		}
		// 5、修改虚拟物料表OPT_TIMES+=1; STATUS= 0PCL10；Is_next_finished("1") （同步修改S1的[OPT_TIMES]、[STATUS]
		PlnMaterielDetail pmdu = new PlnMaterielDetail();
		pmdu.setSerial_no(lpmd.get(0).getSerial_no());
		pmdu.setOpt_times((lpmd.get(0).getOpt_times() == null ? 0 : lpmd.get(0).getOpt_times()) + 1);
		pmdu.setStatus("0PCL10");
		pmdu.setIs_next_finished("1");//下一个工序是否完成 2016-06-13
		this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);

		// 新增虚拟物料履历表【PRC_MATERIEL_VT_PROCESS】记录
		// 2018-06-12 这个虚拟物料号对应的虚拟物料记录实物号和开平计划号可能为空,所以不调用公共函数.
		PlnMaterielDetail pmdcq = new PlnMaterielDetail();
		pmdcq.setObject_no_vt(lpmd.get(0).getObject_no_vt());
		List<PlnMaterielDetail> lpmdq = this.getMapper(PlnMaterielDetailMapper.class).find(pmdcq, 0, 0);
		// 6、写虚拟物料履历，状态填: 0PCL10 
		PrcMaterielVtProcess pmvpc = new PrcMaterielVtProcess();
		
		// 20191001
		long serial_no = 0l;
		List<PrcMaterielVtProcess> pmpQ = this.getMapper(PrcMaterielVtProcessMapper.class).findWithCondition(null, "", "serial_no desc", 0, 1);
		if (Utils.isNotEmpty(pmpQ)) {
			serial_no = pmpQ.get(0).getSerial_no()+1;
		}
		pmvpc.setSerial_no(serial_no);
		// end
		
		pmvpc.setObject_no_vt(lpmdq.get(0).getObject_no_vt());
		pmvpc.setObject_no(object_no);
		pmvpc.setObject_type(lpmdq.get(0).getObject_type());
		pmvpc.setPline_code(lpmdq.get(0).getPline_code());
		pmvpc.setStatus("0PCL10");
		pmvpc.setOrder_no(lpmdq.get(0).getOrder_no());
		pmvpc.setProd_order_no(lpmdq.get(0).getProd_order_no());
		pmvpc.setCl_design_no(lpmdq.get(0).getCl_design_no());
		pmvpc.setCl_design_no(lpmdq.get(0).getCl_design_no());
		pmvpc.setRl_design_no(lpmdq.get(0).getRl_design_no());
		pmvpc.setCl_plan_no(plan_no);
		pmvpc.setCl_plan_no(lpmdq.get(0).getCl_plan_no());
		pmvpc.setRl_plan_no(lpmdq.get(0).getRl_plan_no());
		pmvpc.setBatch_no(lpmdq.get(0).getBatch_no());
		pmvpc.setCreate_man_name(userName);
		pmvpc.setCreate_time(createTime);
		this.getMapper(PrcMaterielVtProcessMapper.class).doAdd(pmvpc);
		// ----------------------------------------------------------------------

		// 7、修改虚拟物料对应的 开平计划进程表
		PlnClPlanStatistic plps = new PlnClPlanStatistic();
		plps.setMat_cl(lpmd.get(0).getSingle_weight());// mcsd.getCoil_act_wgt());
		plps.setMat_cl_cnt(1);
		plps.setCl_plan_no(plan_no);
		this.getMapper(PlnClPlanStatisticMapper.class).doUpdatePlaned(plps);

		// 8、开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】：STATUS= 5BCL10
		PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
		plpd.setCl_plan_no(plan_no);
		plpd.setStatus("5BCL10");
		plpd.setObject_no_vt(pmd.getObject_no_vt());
		this.getMapper(PlnCuttolengthPlanDetailMapper.class).doUpdateWSum(plpd);

		// 9、开平计划主表【PLN_CuttoLength_PLAN】：调用公共函数1（开平计划号）;
		doUpdatePlnCuttolengthPlan(plan_no);
		
//		this.getBean(MesApiDesignInfoImpl.class).updatePlnStatic(lpmd.get(0).getProd_order_no(), lpmd.get(0).getOrder_no(), lpmd.get(0).getNext_dsn_process_code(), lpmd.get(0).getSingle_weight(), true);
		
		// 将未挂单的子卷 置为无效
//		List<PlnMaterielDetail> child = this.getMapper(
//				PlnMaterielDetailMapper.class).findWithCondition(
//				null,
//				"mat_object_no_vt = '" + lpmd.get(0).getObject_no_vt()
//						+ "' and nvl(invalid_flg,0) =0 and object_no is null",
//				"", 0, 0);
//		if (Utils.isNotEmpty(child)) {
//			this.getBean(MesApiDesignInfoImpl.class).deleteChild(child);
//		}
	}

	/**
	 * 撤销开平 撤销虚拟母卷统计
	 * @param object_no_vt
	 *            虚拟母卷号
	 * @param object_no
	 *            实物母卷号
	 * @throws Exception
	 */
	@Transactional(value = "tm", rollbackFor = Exception.class)
	public void CuttoLengthFinsh_SumCancel(PlnMaterielDetail pmd) throws Exception {
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		Date createTime = new Date();
		// 读取虚拟物料表【PLN_MATERIEL_DETAIL】，获取虚拟母卷信息
		PlnMaterielDetail pmdq = new PlnMaterielDetail();
		pmdq.setObject_no_vt(pmd.getObject_no_vt());
		List<PlnMaterielDetail> lpmd = this.getMapper(PlnMaterielDetailMapper.class).find(pmdq, 0, 0);
		if (lpmd == null || lpmd.size() == 0) {
			throw new Exception("虚拟物料无[" + pmd.getObject_no_vt() + "]卷!");
		}

		// 工序点信息
		List<ComBaseInfo> infoi = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null,
				"sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(infoi);
		
		// 修改物料附加信息
		this.getBean(MesApiDesignInfoImpl.class).updateMExInfo(pmd.getObject_no(), processpoint.cross_cutting_code,false);
		
		// 将无效的虚拟物料子卷恢复
//		List<PlnMaterielDetail> child = this.getMapper(
//				PlnMaterielDetailMapper.class).findWithCondition(
//				null,
//				"mat_object_no_vt = '" + lpmd.get(0).getObject_no_vt()
//						+ "' and invalid_flg = '1'", "", 0, 0);
//		if (Utils.isNotEmpty(child)) {
//			this.getBean(MesApiDesignInfoImpl.class).recoveryChild(child);
//		}
				
		// 读取虚拟物料履历表【PRC_MATERIEL_VT_PROCESS】，获取虚拟母卷最后一条
		PrcMaterielVtProcess pmvp = new PrcMaterielVtProcess();
		pmvp.setStatus("0PCL10");
		pmvp.setObject_no_vt(lpmd.get(0).getObject_no_vt());
		List<PrcMaterielVtProcess> lpmvp = this.getMapper(PrcMaterielVtProcessMapper.class).findWithCondition(pmvp, ""," create_time desc ", 0, 1);

		// 循环 (MAT_OBJECT_NO_VT=虚拟母卷号) 的所有虚拟子堆垛记录
		PlnMaterielDetail pmdc = new PlnMaterielDetail();
		pmdc.setMat_object_no_vt(lpmd.get(0).getObject_no_vt());
		List<PlnMaterielDetail> lpmdc = this.getMapper(PlnMaterielDetailMapper.class).find(pmdc, 0, 0);
		for (PlnMaterielDetail pmdcc : lpmdc) {
			PlnMaterielDetail pmdu = new PlnMaterielDetail();
			pmdu.setSerial_no(pmdcc.getSerial_no());
			pmdu.setIs_finished("0");
			// 修改虚拟物料表【PLN_MATERIEL_DETAIL】：IS_FINISHED=0;
			this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);
		}

		// 修改虚拟物料表_母卷信息
		PlnMaterielDetail pmdu = new PlnMaterielDetail();
		pmdu.setSerial_no(lpmd.get(0).getSerial_no());
		pmdu.setNeed_extopt("0");
		pmdu.setCl_plan_no(lpmvp.get(0).getCl_plan_no());
		pmdu.setIs_next_finished("0");
		pmdu.setStatus_desc("0PCL03");

		if (lpmd.get(0).getObject_no() == null || "".equals(lpmd.get(0).getObject_no())) {
			pmdu.setObject_no(lpmvp.get(0).getObject_no());
		}
		if (lpmd.get(0).getOpt_times() != null) {
			pmdu.setOpt_times(lpmd.get(0).getOpt_times() - 1);
		}
		this.getMapper(PlnMaterielDetailMapper.class).update(pmdu);

		// 新增虚拟物料履历表【PRC_MATERIEL_VT_PROCESS】记录
		this.getBean(MesApiServiceImpl.class).InsertMatVtProc(lpmd.get(0).getObject_no_vt(), "0PCL03", userName,createTime);

		// 修改虚拟物料对应的 开平计划进程表
		PlnClPlanStatistic plps = new PlnClPlanStatistic();
		plps.setMat_cl(-lpmd.get(0).getSingle_weight());
		plps.setMat_cl_cnt(-1);
		plps.setCl_plan_no(lpmd.get(0).getCl_plan_no());
		this.getMapper(PlnClPlanStatisticMapper.class).doUpdatePlaned(plps);
		
		// 回退实物母卷的物料跟踪
		PrcMaterielProcess pmp = new PrcMaterielProcess();
		pmp.setObject_no(lpmd.get(0).getObject_no());
		pmp.setPrc_code("5BCL10");
		pmp.setRemark("撤销母卷开平");
		pmp.setKeep_sametime_status(0);
		ResultModel rm = this.getBean(MesApiServiceImpl.class).ARRAYLIST(pmp);
		if (!"0".equals(rm.getState())) {
			throw new Exception("开平完成后，母卷状态已发生改变，不能撤销！");
		}
		
		// 开平计划明细表【PLN_CuttoLength_PLAN_DETAIL】：STATUS= 5BCL03
		PlnCuttolengthPlanDetail plpd = new PlnCuttolengthPlanDetail();
		plpd.setCl_plan_no(lpmd.get(0).getCl_plan_no());
		plpd.setStatus("5BCL03");
		plpd.setObject_no_vt(pmd.getObject_no_vt());
		this.getMapper(PlnCuttolengthPlanDetailMapper.class).doUpdateWSum(plpd);
		
		// 开平计划主表【PLN_CuttoLength_PLAN】：调用公共函数1（开平计划号）;
		doUpdatePlnCuttolengthPlan(lpmd.get(0).getCl_plan_no());
		
		// TODO 将来加上12mm 循环所有 object_no <> null 的虚拟子堆垛，累加统计： 子堆垛个数 T_NUM 和 重量 T_WGT
	}

	// --------------------------------开平完成 End----------------------------------------------------
	
	/**
	 * 传入虚拟物料当前工序,获取上一个工序
	 * 暂时从加工计划取,将来从质量取。
	 * @param str 1：横切；2：纵切；3：纵切并横切
	 * @param object_no_vt 虚拟物料号
	 * @return 工序代码
	 * 2018-06-13
	 */
	public  String getPrev_process(String str,String object_no_vt){
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		// 加工计划表获取工序字符串
		String process = this.getMapper(PlnMaterielDetailMapper.class).findProcess(object_no_vt);
		String process_code = "";
		if (str==null || "".equals(str)) {
			if ("1".equals(process) || "3".equals(process)) {
				// 横剪代码
				process_code=processpoint.cross_cutting_code;
			}else if ("2".equals(process) ) {
				// 纵剪代码
				process_code=processpoint.slitting_code;
			}
		}else if ("1".equals(str) && "3".equals(process)) {
			process_code=processpoint.slitting_code;
		}
		return process_code;
	}
	
	/**
	 * 传入虚拟物料当前工序,获取下一个工序
	 * 暂时从加工计划取,将来从质量取。
	 * @param str 1：横切；2：纵切；3：纵切并横切
	 * @param object_no_vt 虚拟物料号
	 * @return 工序代码
	 * 2018-06-13
	 */
	public String getNext_process(String str,String object_no_vt){
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		// 从加工计划表获取工序字符串
		String process = this.getMapper(PlnMaterielDetailMapper.class).findProcess(object_no_vt);
		String process_code = "";
		if (str == null || "".equals(str)) {
			if ("1".equals(process)) {
				// 横剪代码
				process_code = processpoint.cross_cutting_code;
			} else if ("2".equals(process) || "3".equals(process)) {
				// 纵剪代码
				process_code = processpoint.slitting_code;
			}
		} else if ("2".equals(str) && "3".equals(process)) {
			process_code = processpoint.cross_cutting_code;
		}
		return process_code;
	}
	
	// -------------------------------------------------------横剪挂单 2018-07-08-----------------------------------------------------
	
	/**
	 * 函数_建立虚拟物料信息
	 * @param prod_order_no 生产订单号
	 * @param ydm 库存信息
	 * @return 横剪设计号
	 * 2018-06-21 p b
	 * @throws Exception 
	 */
	@Transactional(value="tm", rollbackFor=Exception.class)
	public String BuildingVirtualMaterialInfo(String prod_order_no,YdmProductDetail ypd) throws Exception{
		Date createTime = new Date();
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		
		// 工序点信息
		List<ComBaseInfo> info = this.getMapper(ComBaseInfoMapper.class).findWithCondition(null, "sort_code = '2002' AND validflag = '1'", null, 0, 0);
		ProcessPoint processpoint = new ProcessPoint(info);

		String cl_plan_no = "";
		//建立虚拟物料表信息
		String sDate=new SimpleDateFormat("yyMMdd").format(new Date());
		List<PlnMaterielDetail> lpmd=this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(null, null, " serial_no desc ", 0, 1);
		long PMDNo=lpmd==null?1:(lpmd.size()==0?1:(lpmd.get(0).getSerial_no()+1));
		int objectnoVtNo=this.getMapper(PlnMaterielDetailMapper.class).getObjectVtMaxNoForDate(sDate)+1;
		//根据累加值，建立坯料设计订单组成表
		long pdoiNo=1;
		List<PlnDsnOrderInfo> lpdoiq=this.getMapper(PlnDsnOrderInfoMapper.class).findWithCondition(null, "", " serial_no desc", 0, 1);
		if(lpdoiq!=null&&lpdoiq.size()>0){
			pdoiNo=lpdoiq.get(0).getSerial_no()+1;
		}		
		// 虚拟母卷号
		String mat_object_no_vt = sDate+String.format("%06d", objectnoVtNo++);
		// 获取生产订单信息
		PlnProdorder pp=new PlnProdorder();
		pp.setProd_order_no(prod_order_no);
		List<PlnProdorder> lpp=this.getMapper(PlnProdorderMapper.class).find(pp, 0, 1);
		
		// 1、1 判断实物是否已经关联到某虚拟物料上
		List<PlnMaterielDetail> pmd = this.getMapper(PlnMaterielDetailMapper.class).findWithCondition(null, "NVL(INVALID_FLG,0)=0 AND OBJECT_NO = '"+ypd.getCoilno()+"'", "", 0, 1);
		// a、如果数据不存在 则建立母卷信息
		PlnMaterielDetail pmdM=new PlnMaterielDetail();
		if (pmd == null || pmd.size()==0) {
			//母卷虚拟物料数据
			pmdM.setSerial_no(PMDNo++);
			pmdM.setObject_no_vt(mat_object_no_vt);
			pmdM.setObject_no(ypd.getCoilno());
			pmdM.setOrder_no(lpp.get(0).getOrder_no());
			pmdM.setPline_code(lpp.get(0).getPline_code());
			pmdM.setStatus("0PDB10");
			pmdM.setIs_finished("1");//母卷,上一工序是否完成
			// 通过生产订单表关联加工计划表获取当前工序的上一个工序
			PlnProcessPlan ppp = new PlnProcessPlan();
			ppp.setProduce_no(lpp.get(0).getProduce_no());
			ppp.setValid_flag("1");
			List<PlnProcessPlan> process = this.getMapper(PlnProcessPlanMapper.class).findWithCondition(ppp, "cut_order_no = 1", "", 0, 1);
			if (process != null && "3".equals(process.get(0).getCut_style())) {
				pmdM.setPrev_dsn_process_code(processpoint.slitting_code);
				pmdM.setPrev_process_code(processpoint.slitting_code);
				pmdM.setIs_prev_dsn_finished("1");
			}else {
				pmdM.setPrev_dsn_process_code(null);
				pmdM.setPrev_process_code(null);
				pmdM.setIs_prev_dsn_finished("0");
			}
			pmdM.setNext_dsn_process_code(processpoint.cross_cutting_code);
			pmdM.setNext_process_code(processpoint.cross_cutting_code);
//			pmdM.setCreate_design_no(pld.getCl_design_no());
//			pmdM.setCl_design_no(pld.getCl_design_no());
			pmdM.setCreate_process_code(processpoint.cross_cutting_code);
			pmdM.setIs_mat(1);
			pmdM.setOrder_no(lpp.get(0).getOrder_no());
			pmdM.setProd_order_no(lpp.get(0).getProd_order_no());
			pmdM.setIs_multi("0");
			pmdM.setSteel_code(lpp.get(0).getSteel_code());
			//母卷厚度、宽度使用实际值
			pmdM.setWidth(ypd.getWidth());
			pmdM.setThick(ypd.getThick());
			pmdM.setLength(ypd.getLength());
			pmdM.setDiameter_inn(ypd.getDiameter_inn());
			pmdM.setDiameter_out(ypd.getDiameter_out());
			pmdM.setSingle_weight(ypd.getFactweight());
			pmdM.setFixed_length_type_no(lpp.get(0).getFixed_length_type_no());
			pmdM.setCut_edge_type_no(lpp.get(0).getCut_edge_type_no());
			pmdM.setOrd_flg("1");
			pmdM.setCreate_man_name(userName);
			pmdM.setCreate_time(createTime);
			pmdM.setDeliver_date_earliest(lpp.get(0).getDeliver_date());
			pmdM.setDeliver_date_latest(lpp.get(0).getDeliver_date());
			this.getMapper(PlnMaterielDetailMapper.class).insert(pmdM);
		}else {
			// b、否则，修改虚拟母卷信息
			
		}
		// 1、2根据横剪设计号，查找 横剪拼料信息表[PLN_CUTTOLENGTH_DSN_MULTINFO]，循环读取每一堆垛序号【SUB_SEQ】
		List<PlnCuttolengthDsnMultinfo> pldm = this.getMapper(PlnCuttolengthDsnMultinfoMapper.class).findWithCondition(null, "CL_PLAN_NO = ", "", 0, 1);
		double v_total_wgt=0;
		int v_total_num=0;
		if (pldm != null && pldm.size()>0) {
			for (PlnCuttolengthDsnMultinfo pldmc : pldm) {
				// a、 建立虚拟子堆垛信息
				PlnMaterielDetail pmdc=new PlnMaterielDetail();
				pmdc.setSerial_no(PMDNo++);
				pmdc.setObject_no_vt(sDate+String.format("%06d", objectnoVtNo++));
				pmdc.setOrder_no(lpp.get(0).getOrder_no());
				pmdc.setPline_code(lpp.get(0).getPline_code());
				pmdc.setStatus("0PDB10");
				pmdc.setIs_finished("0");
				pmdc.setPrev_dsn_process_code(processpoint.cross_cutting_code);
				pmdc.setPrev_process_code(processpoint.cross_cutting_code);
				pmdc.setIs_prev_dsn_finished("1");
//				pmdc.setCreate_design_no(pld.getCl_design_no());
				pmdc.setCreate_process_code(processpoint.cross_cutting_code);
				pmdc.setIs_mat(0);
				pmdc.setOrder_no(lpp.get(0).getOrder_no());
				pmdc.setProd_order_no(lpp.get(0).getProd_order_no());
//				pmdc.setCl_design_no(pld.getCl_design_no());
				pmdc.setMat_object_no_vt(mat_object_no_vt);
				pmdc.setIs_multi("0");
				pmdc.setSteel_code(lpp.get(0).getSteel_code());
				pmdc.setWidth(pldmc.getWidth());
				pmdc.setThick(pldmc.getThick());
				pmdc.setLength(pldmc.getLength());
				
				pmdc.setSingle_weight(pldmc.getWeight());
				pmdc.setSub_count((pldmc.getSub_count()));
				pmdc.setSub_weight(pldmc.getSub_weight());
				
				
				pmdc.setFixed_length_type_no(lpp.get(0).getFixed_length_type_no());
				pmdc.setCut_edge_type_no(lpp.get(0).getCut_edge_type_no());
				pmdc.setOrd_flg("1");
				pmdc.setCreate_man_name(userName);
				pmdc.setCreate_time(createTime);
				pmdc.setDeliver_date_earliest(lpp.get(0).getDeliver_date());
				pmdc.setDeliver_date_latest(lpp.get(0).getDeliver_date());
				this.getMapper(PlnMaterielDetailMapper.class).insert(pmdc);
				
				// b、 累加 虚拟子堆垛重量, 虚拟子堆垛个数 ---> v_total_wgt, v_total_num
				v_total_wgt+=pmdc.getSingle_weight().doubleValue();
				v_total_num+=1;
			}
			
			// 2、根据累加值，建立坯料设计订单组成表【PLN_DSN_ORDER_INFO】信息																			
			PlnDsnOrderInfo pdoi=new PlnDsnOrderInfo();
			pdoi.setSerial_no(pdoiNo++);
//			pdoi.setDesign_no(pld.getCl_design_no());
			pdoi.setProd_order_no(lpp.get(0).getProd_order_no());
			pdoi.setOrder_no(lpp.get(0).getOrder_no());
			pdoi.setWeight_in_one(v_total_wgt);
			pdoi.setQuantity_in_one(v_total_num);
			this.getMapper(PlnDsnOrderInfoMapper.class).insert(pdoi);
		}
		return null;
	}
	
	

	
	/**
	 * 函数_通过加工计划产生设计
	 * @param pro_order_no 生产订单号
	 * @param design_quantity 设计原料卷总数
	 * @param ypd 物料信息
	 * @throws Exception 
	 * */
	@Transactional(value="tm", rollbackFor=Exception.class)
	public PlnCuttolengthDsnMain ProcessingPlanDsn(String pro_order_no,Integer design_quantity,YdmProductDetail ypd,String pd) throws Exception{
		PlnCuttolengthDsnMain sCl_design_no=null;
		String userName = (String) this.getSession().getAttribute(HomeService.SESSION_USER_NAME);
		PlnProdorder pp=new PlnProdorder();
		pp.setProd_order_no(pro_order_no);
		List<PlnProdorder> lpp=this.getMapper(PlnProdorderMapper.class).findWithCondition(pp, "", " create_time desc ", 0, 1);
		
		// 读取基础配置 产线机组限制表
		ComDsnPltlmt cdp=new ComDsnPltlmt();
		cdp.setPlt("Y1");//工厂
		cdp.setPlt_line("Y1");//产线
		List<ComDsnPltlmt> lc=this.getMapper(ComDsnPltlmtMapper.class).find(cdp, 0, 0);
		if(lc==null||lc.size()==0){
			throw new Exception("未找到产线");
		}
		// 获取所有的限制条件
		ClRestrict MachineRestrict=new ClRestrict(lc);
		
		//根据加工计划号  读取生产订单对应的生产加工表[PLN_PROCESS_PLAN]
		PlnProcessPlan ppp=new PlnProcessPlan();
		ppp.setProduce_no(lpp.get(0).getProduce_no());
		ppp.setValid_flag("1");
		List<PlnProcessPlan> lppp=this.getMapper(PlnProcessPlanMapper.class).findWithCondition(ppp, null, " cut_order_no ", 0, 0);
		if(lppp==null||lppp.size()==0){
			throw new Exception("未找到生产订单["+ppp.getOrder_no()+"]对应的生产加工信息");
		}
		
//		ResultModel rm=this.getBean(PbModelDbServiceImpl.class).findPlnThickRangeCmbDb();
//		if(!"200".equals(rm.getState())){
//			throw new Exception("获取厚度公差范围失败！");
//		}
//		List<PbModelDb> lpmd=(List<PbModelDb>) rm.getData();
//		if(lpmd==null||lpmd.size()==0){
//			throw new Exception("请先配置厚度公差范围！");
//		}
		
//		if(!"1".equals(pd)){
//			//--------------获取配置的值比较公差范围------------------
//			for(PbModelDb pmd:lpmd){
//				if(pmd.getId().equals("200101")){//范围
//					if(ypd.getThick().doubleValue()-MachineRestrict.lim_max_height>(Double.parseDouble(pmd.getRegionkey()))){
//						throw new Exception("母卷["+ypd.getCoilno()+"]的厚度超出最大公差设备限制范围内，不能挂单！");
//					}
//				}
//				
//				if(pmd.getId().equals("200102")){
//					if(ypd.getThick().doubleValue()-MachineRestrict.lim_min_height<(Double.parseDouble(pmd.getRegionkey()))){
//						throw new Exception("母卷["+ypd.getCoilno()+"]的厚度小于最小公差设备限制范围内，不能挂单！");
//					}
//				}
//			}
//			//--------------------------------
//			
//			if(ypd.getWidth().doubleValue()>MachineRestrict.lim_max_wdt
//					||ypd.getWidth().doubleValue()<MachineRestrict.lim_min_wdt){
//				throw new Exception("母卷["+ypd.getCoilno()+"]的宽度不在设备限制范围内，不能挂单！");
//			}
//			if(ypd.getFactweight().doubleValue()>MachineRestrict.lim_max_wgt){
//				throw new Exception("母卷["+ypd.getCoilno()+"]的重量不在设备限制范围内，不能挂单！");
//			}
//			//对于母卷S1的 其他规格信息(内径、外径)， 如果无值，则继续；  如果有值，则判断是否在设备原料的限制范围内
//			if(ypd.getDiameter_inn()!=null&&ypd.getDiameter_inn().intValue()!=0){
//				if(ypd.getDiameter_inn().doubleValue()>MachineRestrict.lim_max_inner
//						||ypd.getDiameter_inn().doubleValue()<MachineRestrict.lim_min_inner){
//					throw new Exception("母卷["+ypd.getCoilno()+"]的内径不在设备限制范围内，不能挂单！");
//				}
//			}
//			if(ypd.getDiameter_out()!=null&&ypd.getDiameter_out().intValue()!=0){
//				if(ypd.getDiameter_out().doubleValue()>MachineRestrict.lim_max_outter
//						||ypd.getDiameter_out().doubleValue()<MachineRestrict.lim_min_outter){
//					throw new Exception("母卷["+ypd.getCoilno()+"]的外径不在设备限制范围内，不能挂单！");
//				}
//			}
//		}
		
		
		double sWidth=0,
				// 每个规格下总堆垛数
				allboxCount = 0,
				// 重量判断
				weightvalid = 0,
				// 重量上限
				weightupper = 0,
				// 临时-重量
				weighttemp=0,
				// 单堆垛重量
				V_singleWeight = 0,	
				// 单堆垛块数
				 boxCount ,
				// 该规格最后一堆,块数
		        V_lastbox_Count =0;
		// 总堆垛数/子板总数
		int iCutCount=0,allsubcount=0;
		// 加工计划号:单堆垛块数
		Map<String, Double> boxCounts = new HashMap<String, Double>();
		// 加工计划号:子堆垛数
		Map<String, Double> ZddCount = new HashMap<String, Double>();
		// 加工计划号:最后一堆.堆垛块数
		Map<String, Double> Last_Count = new HashMap<String, Double>();
		String  cut_style = "";
		for(PlnProcessPlan pppc:lppp){
			//对于子卷S1的 厚、宽、重量信息，判断其是否在设备原料的限制范围内
			if(!"1".equals(pd)){
				// 重量判断
				weightvalid += pppc.getEstimate_weight();
				//-------------------获取配置的值比较公差范围--------------------
//				for(PbModelDb pmd:lpmd){
//					if(pmd.getId().equals("200101")){//范围
//						if(pppc.getMat_thick()-MachineRestrict.lim_max_sub_thick>(Double.parseDouble(pmd.getRegionkey()))){
//							throw new Exception("加工计划["+pppc.getProduce_no()+"]的子板厚度超出最大公差设备限制范围内，不能挂单！");
//						}
//					}
//					
//					if(pmd.getId().equals("200102")){
//						if(pppc.getMat_thick()-MachineRestrict.lim_min_sub_thick<(Double.parseDouble(pmd.getRegionkey()))){
//							throw new Exception("加工计划["+pppc.getProduce_no()+"]的子板厚度小于最小公差设备限制范围内，不能挂单！");
//						}
//					}
//				}
				//--------------------------------------------------------------
				
//				if (pppc.getWidth() !=null) {
//					if(pppc.getWidth()>MachineRestrict.lim_max_sub_wdt
//							||pppc.getWidth()<MachineRestrict.lim_min_sub_wdt){
//						throw new Exception("加工计划["+pppc.getProduce_no()+"]的子板的宽度不在设备限制范围内，不能挂单！");
//					}
//				}
//				//对于子板S1的 其他规格信息(长)， 如果无值，则继续；  如果有值，则判断是否在设备原料的限制范围内
//				if(pppc.getLength()!=null){
//					if(pppc.getLength()>MachineRestrict.lim_max_sub_length
//							||pppc.getLength()<MachineRestrict.lim_min_sub_length){
//						throw new Exception("加工计划["+pppc.getProduce_no()+"]的子板的长度不在设备限制范围内，不能挂单！");
//					}
//				}
				// TODO 将来计算 板垛高度范围/板垛重量范围
				
			}
			if (pppc.getMono_stack_max_weight()==null || "".equals(pppc.getMono_stack_max_weight()) || pppc.getMono_stack_max_weight()==0) {
				weightupper = 99999;
			}else {
				weightupper =pppc.getMono_stack_max_weight();
			}
			if ( MachineRestrict.lim_max_box_wgt==0) {
				weighttemp = 99999;
			}else{
				weighttemp = MachineRestrict.lim_max_box_wgt;
			}
			weightupper = weightupper>weighttemp ? weighttemp:weightupper;
			// 如果销售加工计划传入了计划块数
			if ( pppc.getCut_num() != null && pppc.getCut_num() > 1) {
				// 总堆垛数
				allboxCount = Math.ceil(1.0 * pppc.getCut_num() * pppc.getThick() / MachineRestrict.lim_max_box_height);
				// 单堆垛块数
				boxCount = new BigDecimal(pppc.getCut_num() / allboxCount).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
				// 单堆垛重量
				V_singleWeight = boxCount * GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength());
				if (V_singleWeight > weightupper) {
					boxCount = Math.ceil(weightupper / GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength()));
					allboxCount = Math.ceil(pppc.getCut_num() / boxCount);
				}
				V_lastbox_Count = pppc.getCut_num() - (allboxCount - 1) * boxCount;
				Last_Count.put(pppc.getPlan_no(), V_lastbox_Count);
			}else {
				// 子板重量
				double weigth = GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength());
				// 根据加工计划计算 堆垛总数= 向上取整(估算重量/单垛重量上限)；
				allboxCount = Math.ceil(pppc.getEstimate_weight()/weightupper);
				// 根据 堆垛数 反推 单堆垛块数 =(四舍五入) [估算重量/总堆垛数/(7.85*(10^-6)*厚*宽*长)];	
				boxCount = new BigDecimal(pppc.getEstimate_weight()/allboxCount/weigth).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
				// 如果 单堆垛块数 * 厚度 > 设备限制高度，则重新计算: 	
				if (boxCount*pppc.getThick().doubleValue()>MachineRestrict.lim_max_box_height) {
					// 单堆垛块数_临时= [四舍五入](设备限制高度/厚度)；
					boxCount =  new BigDecimal(MachineRestrict.lim_max_box_height/pppc.getThick()).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
					// 堆垛总数 = (向上取整)[估算重量/(7.85*(10^-6)*厚*宽*长)* 单堆垛块数_临时]；
					allboxCount = Math.ceil(pppc.getEstimate_weight()/(weigth*boxCount));
					// 单堆垛块数 =(四舍五入) [估算重量/总堆垛数/(7.85*(10^-6)*厚*宽*长)];
					boxCount = new BigDecimal(pppc.getEstimate_weight()/allboxCount/weigth).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
				}
			}
			sWidth+=pppc.getWidth().doubleValue()*allboxCount*boxCount;
			allsubcount +=allboxCount*boxCount;
			iCutCount+=allboxCount;
			boxCounts.put(pppc.getPlan_no(), boxCount);
			ZddCount.put(pppc.getPlan_no(), allboxCount);
			cut_style += allboxCount+"*"+boxCount+"*";
		}
		
//		if (!"1".equals(pd)) {
//			if (ypd.getFactweight() != null) {
//				if (weightvalid > ypd.getFactweight()) {
//					throw new Exception(" 卷重小于加工计划各规格要求重量之和,不能挂单！");
//				}
//			}
//		}
		
		//保存设计主表数据：  横剪设计号：DCL+YYMMDD+6流水号
		String sDate=new SimpleDateFormat("yyMMdd").format(new Date());
		PlnCuttolengthDsnMain pldm=new PlnCuttolengthDsnMain();
		List<PlnCuttolengthDsnMain> lpdmNo=this.getMapper(PlnCuttolengthDsnMainMapper.class).findWithCondition(null, "", " to_number(serial_no) desc ", 0, 1);
		pldm.setCl_design_no("DCL"+sDate+String.format("%06d", 1));
		pldm.setSerial_no("1");
		if(lpdmNo!=null&&lpdmNo.size()>0){
			pldm.setSerial_no(String.valueOf(Integer.parseInt(lpdmNo.get(0).getSerial_no())+1));
			if(sDate.equals(lpdmNo.get(0).getCl_design_no().substring(3,9))){
				pldm.setCl_design_no("DCL"+sDate+String.format("%06d", Integer.parseInt(lpdmNo.get(0).getCl_design_no().substring(9,15))+1 ));
			}
		}
		
		pldm.setProd_order_no(lpp.get(0).getProd_order_no());
		pldm.setOrder_no(lpp.get(0).getOrder_no());
		pldm.setPline_code(lpp.get(0).getPline_code());
		pldm.setSteel_code(lpp.get(0).getSteel_code());
		
		String isMulti="0";//是否拼料 根据订单数判断，多个订单填1，否则填0
		pldm.setIs_multi(isMulti);
		pldm.setMat_diameter_inn(ypd.getDiameter_inn());
		pldm.setMat_diameter_out(ypd.getDiameter_out());
		pldm.setMat_single_weight(ypd.getFactweight());
		pldm.setMat_width(ypd.getWidth());
		pldm.setProd_rate(sWidth/lppp.get(0).getMat_width().doubleValue());
		// 堆垛总数
		pldm.setSub_count(iCutCount);
		// 钢板总数
		pldm.setPlate_count(allsubcount);
		pldm.setMat_thick(lppp.get(0).getThick());
		pldm.setMat_length(lppp.get(0).getLength());
		pldm.setSingle_weight(ypd.getFactweight());
		if(lppp.size()==1){
			pldm.setThick(lppp.get(0).getThick());
			pldm.setWidth(lppp.get(0).getWidth());
			pldm.setLength(lppp.get(0).getLength());
			pldm.setDiameter_inn(lppp.get(0).getDiameter_inn());
			pldm.setDiameter_out(lppp.get(0).getDiameter_out());
			pldm.setSingle_weight(lppp.get(0).getEstimate_weight());
		}
		
		if(!"1".equals(lpp.get(0).getOrder_nature()) && !"3".equals(lpp.get(0).getOrder_nature())){
			pldm.setCut_style(lppp.get(0).getCut_style());
		}
		
		pldm.setFixed_length_type_no(lpp.get(0).getFixed_length_type_no());
		pldm.setCut_edge_type_no(lpp.get(0).getCut_edge_type_no());
		pldm.setDeliver_date(lpp.get(0).getDeliver_date());
		pldm.setDesign_quantity(design_quantity);
		pldm.setDesign_weight(ypd.getFactweight());
		
		pldm.setDeliver_date_earliest(lpp.get(0).getDeliver_date());
		pldm.setDeliver_date_latest(lpp.get(0).getDeliver_date());
		pldm.setCreate_man_name(userName);
		pldm.setCreate_time(new Date());
		pldm.setIs_finished(0l);
		pldm.setReserve_1(lppp.get(0).getProduce_no());
		this.getMapper(PlnCuttolengthDsnMainMapper.class).insert(pldm);
		sCl_design_no=pldm;
		
		//倒叙取一条
		List<PlnCuttolengthDsnMultinfo> lpdmM=this.getMapper(PlnCuttolengthDsnMultinfoMapper.class).findWithCondition(null, "", " to_number (serial_no) desc ", 0,1);
		long DsnNo=1;
		int sub_seq = 1;
		if(lpdmM!=null&&lpdmM.size()>0){
			DsnNo=lpdmM.get(0).getSerial_no()+1;
		}
		//-----------------写拼料(单个堆垛的信息)-------------------------
		
			for(PlnProcessPlan pppc:lppp){
				for(int idx_sub=1;idx_sub<=ZddCount.get(pppc.getPlan_no()).intValue();idx_sub++){
					PlnCuttolengthDsnMultinfo pldmc=new PlnCuttolengthDsnMultinfo();
					pldmc.setSerial_no(DsnNo++);
					// 子堆垛序号
					pldmc.setSub_seq(sub_seq++);
					pldmc.setCl_design_no(pldm.getCl_design_no());
					pldmc.setOrder_no(lpp.get(0).getOrder_no());
					pldmc.setProd_order_no(lpp.get(0).getProd_order_no());
					// 堆垛规格
					pldmc.setThick(pppc.getThick()*boxCounts.get(pppc.getPlan_no()).intValue());
					pldmc.setWidth(pppc.getWidth());
					pldmc.setLength(pppc.getLength());
					// 子板规格
					pldmc.setSub_thick(pppc.getThick());
					pldmc.setSub_length(pppc.getLength());
					pldmc.setSub_width(pppc.getWidth());
					// 关联加工计划取唯一加工计划
					pldmc.setPlan_no(pppc.getPlan_no());
					// 如果传入了规格总块数,按块数来算
					if ( pppc.getCut_num() != null && pppc.getCut_num()>1 && ZddCount.get(pppc.getPlan_no()).intValue()>1) {
						if (idx_sub ==ZddCount.get(pppc.getPlan_no()).intValue() ) {
							// sub_count 最后一剁子板总数
							pldmc.setSub_count(Last_Count.get(pppc.getPlan_no()).intValue());
							// 总数*单重
							pldmc.setWeight(new BigDecimal(GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength())*Last_Count.get(pppc.getPlan_no()).intValue()).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
						}else {
							// sub_count 子板总数
							pldmc.setSub_count(boxCounts.get(pppc.getPlan_no()).intValue());
							// 总数*单重
							pldmc.setWeight(new BigDecimal(GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength())*boxCounts.get(pppc.getPlan_no()).intValue()).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
							
						}
					}else {
						// sub_count 子板总数
						pldmc.setSub_count(boxCounts.get(pppc.getPlan_no()).intValue());
						// 总数*单重
						pldmc.setWeight(new BigDecimal(GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength())*boxCounts.get(pppc.getPlan_no()).intValue()).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
					}
					// 子板单重
					pldmc.setSub_weight(new BigDecimal(GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength())).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
					// 定尺方式/切边方式
					pldmc.setFixed_length_type_no(lpp.get(0).getFixed_length_type_no());
					pldmc.setCut_edge_type_no(lpp.get(0).getCut_edge_type_no());
					
					if(pldmc.getSub_seq()>=1000){
						throw new Exception("子板序号["+pldmc.getSub_seq()+"]不在设备限制范围内！");
					}
					this.getMapper(PlnCuttolengthDsnMultinfoMapper.class).insert(pldmc);
				}
			}
		
		return sCl_design_no;
	}
	
	/**
	 * 根据厚宽长获取重量
	 * @param thick
	 * @param width
	 * @param length
	 * 注意单位都是毫米（传入）
	 * @return
	 */
	@SuppressWarnings("unused")
	public	static double GetWeightBySize(double thick, double width,double length ){
        return thick* width*length* 7.85 * Math.pow(10, -6);
	}
 
	/**
	 * 根据加工计划和堆垛高度限制获取子堆垛总数和单堆垛块数
	 * @param pppc 加工计划
	 * @param height 堆垛高度
	 * @return 子堆垛总数/单堆垛块数
	 */
	public Double[] getBoxCount(PlnProcessPlan pppc,double height){
		Double[] result =  new Double[2];
		// 每个规格下堆垛总数/单堆垛块数
		double  allboxCount = 0, boxCount;
		// 总堆垛数/子板总数
		int iCutCount = 0, allsubcount = 0;
		// 加工计划号:子堆垛数
		Map<String, BigDecimal> boxCounts = new HashMap<String, BigDecimal>();
		// 子板重量
		double weigth = GetWeightBySize(pppc.getThick(), pppc.getWidth(), pppc.getLength());
		// 根据加工计划计算 堆垛总数= 向上取整(估算重量/单垛重量上限)；
		allboxCount = Math.ceil(pppc.getEstimate_weight() / pppc.getMono_stack_max_weight());
		// 根据 堆垛数 反推 单堆垛块数 =(四舍五入) [估算重量/总堆垛数/(7.85*(10^-6)*厚*宽*长)];
		boxCount = new BigDecimal(pppc.getEstimate_weight() / allboxCount / weigth).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
		// 如果 单堆垛块数 * 厚度 > 设备限制高度，则重新计算:
		if (boxCount * pppc.getThick().doubleValue() > height) {
			// 单堆垛块数_临时= [四舍五入](设备限制高度/厚度)；
			boxCount = new BigDecimal(height / pppc.getThick()).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
			// 堆垛总数 = (向上取整)[估算重量/(7.85*(10^-6)*厚*宽*长)* 单堆垛块数_临时]；
			allboxCount = Math.ceil(pppc.getEstimate_weight() / (weigth * boxCount));
			// 单堆垛块数 =(四舍五入) [估算重量/总堆垛数/(7.85*(10^-6)*厚*宽*长)];
			boxCount = new BigDecimal(pppc.getEstimate_weight() / allboxCount / weigth).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
		}
		result[0] = allboxCount;
		result[1] = boxCount;
		return result;
	}
}
