package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesPackingRuleService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesTemplateService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesPackageExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionCustomContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionDispatchContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.print.IPrintTemplateStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step.method.IMesPackageNoGenerateStepService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.util.MesPcnException;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesProduceSnPrintModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.actor.shipping.dispatch.IFsmRouteDataService;
import cn.estsh.i3plus.mes.pcn.api.iservice.busi.ISyncFuncService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.mes.pcn.util.StringUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.model.GenSerialNoModel;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StationResultBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.repository.IMesPrintedSnLogRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesPackageDetailRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesPackageRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import rx.internal.util.LinkedArrayList;

import javax.persistence.EntityManager;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description : 打包工步
 * @Author : wangjie
 **/
@Slf4j
@Service("mesPackageNoGenerateStepService")
public class MesPackageNoGenerateStepService extends BaseStepService implements IMesPackageNoGenerateStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    @Autowired
    private IMesPackingRuleService packingRuleService;

    @Autowired
    private IMesPackageExtService packageExtService;

    @Autowired
    private IMesTemplateService templateService;

    @Autowired
    private ISyncFuncService syncFuncService;

    @Autowired
    private IFsmRouteDataService fsmRouteDataService;

    @Autowired
    private MesPackageRepository packageRepository;

    @Autowired
    private IMesPrintedSnLogRepository printedSnLogRepository;

    @Autowired
    private MesPackageDetailRepository packageDetailRepository;

    @Autowired
    private EntityManager entityManager;

    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StationResultBean resultBean = new StationResultBean();

        StepResult stepResult = StepResult.getSuccessComplete();

        //获取上下文信息
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean);

        //配置错误 抛出异常
        if (!productionProcessContext.getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //存储生产过程上下文对象
        productionProcessContextStepService.dispatchProductionProcessContext(reqBean, productionProcessContext);

        //从上下文中取出生产线对象
        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();

        //排序线 直接跳过
        if (MesExtEnumUtil.WORK_CENTER_TYPE.SORT.getValue() == workCenter.getCenterType()) return stepResult;

        //获取上下文产出条码数据信息集合
        List<MesProductionPsOutContext> productionPsOutContextList = productionDispatchContextStepService.getProductionPsOutContext(reqBean);

        //获取上下文产品加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);

        if (CollectionUtils.isEmpty(productionPsOutContextList) || CollectionUtils.isEmpty(prodRuleContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在产出零件条码信息,请重置工序解决!");

        //在加工规则中搜集可以打包的数据的数据关联键集合
        List<Integer> foreignKeyList = prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getIsPackage()) && o.getIsPackage().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0)).map(MesProdRuleContext::getForeignKey).collect(Collectors.toList());

        //搜集数据关联键集合对应的[合格状态]的产出条码,根据零件号分组
        /**Map<String, List<String>> productSnMap2Part = productionPsOutContextList.stream()
                .filter(o -> (null != o && o.getQcStatus().compareTo(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue()) == 0 && foreignKeyList.contains(o.getForeignKey())))
                .collect(Collectors.groupingBy(MesProductionPsOutContext::getPartNo, Collectors.mapping(MesProductionPsOutContext::getProductSn, Collectors.toList())));**/
        Map<String, LinkedList<String>> productSnMap2Part = new HashMap<>();
        productionPsOutContextList.forEach(o -> productSnMap2Part.computeIfAbsent(o.getPartNo(), k -> new LinkedList<>()).addAll(generateVirtualPs(o.getQty(), o.getProductSn())));

        //获取包装规则信息
        Map<String, MesPackageRuleContext> packageRuleContextMap = productionProcessContextStepService.getPackageRuleContext(reqBean);
        Integer initQty = CollectionUtils.isEmpty(packageRuleContextMap) ? MesPcnExtConstWords.ZERO : packageRuleContextMap.size();

        //获取打包数据
        Map<String, String> packageDataContextMap = productionCustomContextStepService.getPackageDataContext(reqBean);

        //不同的零件号分别打包处理
        for (Map.Entry<String, LinkedList<String>> entry : productSnMap2Part.entrySet()) {

            if (null == entry) continue;

            //解析当前零件已经存在的包装明细
            List<MesPackageDataContext> packageDataContextList = (CollectionUtils.isEmpty(packageDataContextMap) ||
                    !packageDataContextMap.containsKey(entry.getKey())) ? null : JSONObject.parseArray(packageDataContextMap.get(entry.getKey()), MesPackageDataContext.class);

            //获取生产过程打包规则
            MesPackageRuleContext packageRuleContext;
            if (!CollectionUtils.isEmpty(packageDataContextList) || (!CollectionUtils.isEmpty(packageRuleContextMap) && packageRuleContextMap.containsKey(entry.getKey()))) {
                //从缓存中获取, 如果存在包装信息, 则使用上次获取的包装信息
                packageRuleContext = !CollectionUtils.isEmpty(packageDataContextList) ? packageDataContextList.get(0) : packageRuleContextMap.get(entry.getKey());
            } else {
                //获取包装规则信息
                packageRuleContext = getPackageRuleContext(reqBean, stepResult, entry.getKey(), false);
                Optional<MesProdRuleContext> optional = prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getIsPrintPackage()) && o.getIsPrintPackage().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0)).findFirst();
                if (null == optional || !optional.isPresent()) packageRuleContext.setIsPrintPackage(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
            }

            //无生产过程打包规则时, 忽略当前零件
            if (null == packageRuleContext) continue;

            //更新包装规则信息
            if (null == packageRuleContextMap) packageRuleContextMap = new HashMap<>();
            if (!packageRuleContextMap.containsKey(entry.getKey())) packageRuleContextMap.put(entry.getKey(), packageRuleContext);

            MesLabelTemplate labelTemplate = null;
            IPrintTemplateStrategyService strategyService = null;

            if (CollectionUtils.isEmpty(packageDataContextList)) {
                //查询模版信息
                labelTemplate = templateService.getLabelTemplate(packageRuleContext.getPackageTemplate(), reqBean.getOrganizeCode());
                strategyService = (null != labelTemplate && !StringUtils.isEmpty(labelTemplate.getMethodCode())) ? (IPrintTemplateStrategyService) SpringContextsUtil.getBean(labelTemplate.getMethodCode()) : null;
                if (null == strategyService) {
                    this.sendMessage(reqBean, new StationResultBean().writeDbLog(), String.format("零件编码[%s]未配置有效的包装条码模版[%s]信息!",
                            packageRuleContext.getPartNo(), packageRuleContext.getPackageTemplate()), MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                    continue;
                }
            }

            //生成包装及明细, 根据标包数量判断是否执行打印 [递归]
            stepResult.setDataCollection(new ArrayList());
            packageDataContextList = doHandlePackagePrint(reqBean, stepResult, packageRuleContext, packageDataContextList, entry.getValue(), false);

            //更新实时的打包数据
            if (CollectionUtils.isEmpty(packageDataContextMap)) packageDataContextMap = new HashMap<>();
            if (CollectionUtils.isEmpty(packageDataContextList)) packageDataContextMap.remove(entry.getKey());
            else packageDataContextMap.put(entry.getKey(), JSONObject.toJSONString(packageDataContextList));

            //判断存在包装信息则进行打印
            if (!CollectionUtils.isEmpty(stepResult.getDataCollection())) {
                doPrintPackageNo(reqBean, resultBean, stepResult, packageRuleContext, labelTemplate, strategyService, (List<MesPackage>) stepResult.getDataCollection(), false);
            }

            log.info("工厂{}生产线{}工位{}:FSM STATE DISPATCHER --- DO STEP --- {} EXEC --- PART:{} --- CACHED:{} --- PACKAGE:{}",
                    reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(),
                    StringUtil.toLowerCaseFirst(this.getClass().getSimpleName()), entry.getKey(),
                    CollectionUtils.isEmpty(packageDataContextList) ? MesPcnExtConstWords.SQUARE_BRACKETS : JSONObject.toJSONString(packageDataContextList),
                    CollectionUtils.isEmpty(stepResult.getDataCollection()) ? MesPcnExtConstWords.SQUARE_BRACKETS : JSONObject.toJSONString(stepResult.getDataCollection()));

        }

        //保存包装规则信息
        if (!CollectionUtils.isEmpty(packageRuleContextMap) && initQty != packageRuleContextMap.size()) productionProcessContextStepService.dispatchPackageRuleContext(reqBean, packageRuleContextMap);
        // 保存打包数据
        productionCustomContextStepService.dispatchPackageDataContext(reqBean, packageDataContextMap);

        return stepResult;

    }

    //获取包装规则信息
    @Override
    public MesPackageRuleContext getPackageRuleContext(StationRequestBean reqBean, StepResult stepResult, String partNo, Boolean isAsyn) {

        String message;

        //根据 物料代码,零件类型=零件 查询成品包装明细规则
        List<MesPackingRuleDetail> packingRuleDetailList = packingRuleService.getPackingRuleDetailList(reqBean.getOrganizeCode(), partNo, MesExtEnumUtil.PACKING_RULE_DETAIL_PART_TYPE.I.getValue());
        if (CollectionUtils.isEmpty(packingRuleDetailList)) {
            message = String.format("零件编码[%s]未配置零件类型的成品包装明细规则信息!", partNo);
            if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            else stepResult.msg(message);
            return null;
        }

        //根据包装代码查询成品包装规则
        List<MesPackingRule> packingRuleList = packingRuleService.getPackingRuleList(reqBean.getOrganizeCode(),
                packingRuleDetailList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPackageCode()))).map(MesPackingRuleDetail::getPackageCode).collect(Collectors.toList()));

        //过滤成品包装规则, 取默认包装对应的数据
        MesPackingRule packingRule = filterPackingRule(packingRuleList);
        if (null == packingRule) {
            message = String.format("零件编码[%s]未配置成品包装规则信息!", partNo);
            if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            else stepResult.msg(message);
            return null;
        }

        //根据默认包装获取成品包装明细规则
        MesPackingRuleDetail packingRuleDetail = filterPackingRuleDetail(packingRuleDetailList, packingRule);
        if (StringUtils.isEmpty(packingRuleDetail.getPackageCode()) ||
                StringUtils.isEmpty(packingRuleDetail.getPackSpecQty()) || MathOperation.compareTo(packingRuleDetail.getPackSpecQty(), new Double(0)) == 0) {
            message = String.format("零件编码[%s]配置零件类型的成品包装明细规则信息中必要信息无效:包装代码[%s]包装规格数量[%s]!", partNo, packingRuleDetail.getPackageCode(), packingRuleDetail.getPackSpecQty());
            if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            else stepResult.msg(message);
            return null;
        }

        String generateTypeName = MesExtEnumUtil.PACKING_RULE_GENERATE_TYPE.valueOfDescription(packingRule.getGenerateType());
        String packageBarcodeRule = packingRule.getPackageBarcodeRule();
        String packageTemplate = packingRule.getPackageTemplate();
        String printer = packingRule.getPrinter();

        //如果 packageBarcodeRule || packageTemplate || printer 有一个为空, 则需要根据 箱类别代号查询包装定义, 但是 printer 不进行强验证,可能是否的是默认打印机
        if (StringUtils.isEmpty(generateTypeName) || (StringUtils.isEmpty(packingRule.getPackCode()) && (StringUtils.isEmpty(packageBarcodeRule) || StringUtils.isEmpty(packageTemplate)))) {
            message = String.format("零件编码[%s]零件类型对应的包装代码[%s]配置的成品包装规则信息中必要信息无效:统计方式[%s]箱类别代号[%s]!",
                    partNo, packingRuleDetail.getPackageCode(), StringUtils.isEmpty(generateTypeName) ? MesPcnExtConstWords.EMPTY : generateTypeName, packingRule.getPackCode());
            if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            else stepResult.msg(message);
            return null;
        }

        //根据箱类别代号查询包装定义
        MesPackingDefine packingDefine = StringUtils.isEmpty(packingRule.getPackCode()) ? null : packingRuleService.getPackingDefine(reqBean.getOrganizeCode(), packingRule.getPackCode());

        //判断是否需要查询包装定义
        if (StringUtils.isEmpty(packageBarcodeRule) || StringUtils.isEmpty(packageTemplate) || StringUtils.isEmpty(printer)) {
            if (null == packingDefine && (StringUtils.isEmpty(packageBarcodeRule) || StringUtils.isEmpty(packageTemplate))) {
                message = String.format("零件编码[%s]零件类型对应的包装代码[%s]配置成品包装规则信息中的箱类别代号[%s]未维护包装定义信息!", partNo, packingRuleDetail.getPackageCode(), packingRule.getPackCode());
                if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                else stepResult.msg(message);
                return null;
            }

            //如果为空, 则取包装定义中维护的信息
            if (StringUtils.isEmpty(packageBarcodeRule)) packageBarcodeRule = packingDefine.getPackageBarcodeRule();
            if (StringUtils.isEmpty(packageTemplate)) packageTemplate = packingDefine.getPackageTemplate();
            if (StringUtils.isEmpty(printer) && null != packingDefine) printer = packingDefine.getPrinter();

            //此时 packageBarcodeRule || packageTemplate 仍有一个为空则 记录日志 忽略当前零件的打包
            if (StringUtils.isEmpty(packageBarcodeRule) || StringUtils.isEmpty(packageTemplate)) {
                message = String.format("零件编码[%s]零件类型对应的包装代码[%s]配置的成品包装规则信息中必要信息无效:编码规则[%s]模版[%s]打印机[%s]!", partNo, packingRuleDetail.getPackageCode(), packageBarcodeRule, packageTemplate, printer);
                if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), message, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                else stepResult.msg(message);
                return null;
            }
        }

        //封装包装规则信息
        MesPackageRuleContext packageRuleContext = new MesPackageDataContext();
        BeanUtils.copyProperties(packingRuleDetail, packageRuleContext);
        BeanUtils.copyProperties(packingRule, packageRuleContext);
        packageRuleContext.setPackageBarcodeRule(packageBarcodeRule);
        packageRuleContext.setPackageTemplate(packageTemplate);
        packageRuleContext.setPrinter(printer);
        if (null == packingDefine || StringUtils.isEmpty(packingDefine.getIsSendAries()) ||
                packingDefine.getIsSendAries().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) != 0) packageRuleContext.setSystemSyncStatusWms(MesPcnExtConstWords.ZERO);
        return packageRuleContext;
    }

    //生成包装及明细, 根据标包数量判断是否执行打印 [递归]
    @Override
    public List<MesPackageDataContext> doHandlePackagePrint(StationRequestBean reqBean, StepResult stepResult, MesPackageRuleContext packageRuleContext,
                                                            List<MesPackageDataContext> packageDataContextList, LinkedList<String> productSnList, Boolean isAsyn) {

        //缓存的包装条码明细数量
        Integer cachedQty = CollectionUtils.isEmpty(packageDataContextList) ? MesPcnExtConstWords.ZERO : packageDataContextList.size();
        //当前满足标包的差额数量
        Integer needQty = packageRuleContext.getPackSpecQty().intValue() - cachedQty;
        //如果缓存中的个数超过标包, needQty则为负数, 下面去截取条码的时候会下标越界, 所以此场景下将 needQty改为0
        if (needQty < 0) needQty = MesPcnExtConstWords.ZERO;

        //当前满足标包的差额条码
        LinkedList<String> productSnList2Cur = null;
        //除去当前满足标包的差额条码后的剩余条码
        LinkedList<String> productSnList2Remain = null;

        //当前零件剩余未打包条码 如果小于等于 当前满足标包的差额数量, 则直接将 未打包条码赋给当前满足标包的差额条码, 否则 截取条码
        if (productSnList.size() <= needQty) {
            productSnList2Cur = productSnList;
        } else {
            //缓存中的个数已经等于或者超过标包,则不需要截取条码
            if (needQty.compareTo(MesPcnExtConstWords.ZERO) == 0) {
                productSnList2Remain = productSnList;
            } else {
                //根据需要的个数进行截取条码
                productSnList2Cur = new LinkedList<>(productSnList.subList(0, needQty));
                productSnList2Remain = new LinkedList<>(productSnList.subList(needQty, productSnList.size()));
            }
        }

        //当前的实际打包数量 = 缓存的包装条码明细数量 + 当前满足标包的差额条码的个数
        Integer curQty = cachedQty + (CollectionUtils.isEmpty(productSnList2Cur) ? MesPcnExtConstWords.ZERO : productSnList2Cur.size());

        MesPackage packageDb = null;
        //判断是否存在缓存的包装条码明细信息,如果进行递归则已无包装条码, 则重新生成信息的包装条码
        if (!CollectionUtils.isEmpty(packageDataContextList)) packageDb = getMesPackage(reqBean.getOrganizeCode(), packageDataContextList.get(0).getPackageId());
        //缓存中的包装条码也可能在DB中已被删除, 所以这里直接判断 包装条码信息是否为空则生成包装条码信息
        if (null == packageDb) packageDb = insertMesPackage(reqBean, packageRuleContext, curQty, isAsyn);

        //如果包装条码未空, 说明上面生成包装条码的时候 根据编码规则生成出现问题, 则直接退出, 记录日志, 忽略当前零件的打包
        if (null == packageDb) return null;

        //判断当前是否满包, isAsyn=false代表是工位按钮零件打包触发,零头也直接封箱
        Boolean isSealed = !isAsyn ? curQty >= packageRuleContext.getPackSpecQty().intValue() : true;
        //判断包装条码是否存在ID进行新增或者更新操作, 如果满足标包则标记满包状态跟打印状态
        packageDb = savePackageDb(reqBean, packageDb, curQty, isSealed, isAsyn);

        //判断统计方式,是否生成包装明细信息, 返回当前未满包的包装条码明细数据
        List<MesPackageDataContext> resultList = insertPackageDetailAndBackUnSealedResultList(reqBean, packageRuleContext, packageDb, productSnList2Cur, isSealed);

        //如果当前的实际打包数量不满足标包, 则将此前已经缓存的条码合并到 当前未满包的包装条码明细数据resultList中
        if (!CollectionUtils.isEmpty(resultList) && !CollectionUtils.isEmpty(packageDataContextList)) resultList.addAll(packageDataContextList);

        //判断满包 存储打包信息
        if (isSealed) stepResult.getDataCollection().add(packageDb);

        //如果已无剩余条码, 则返回当前未满包的包装条码明细数据resultList
        if (CollectionUtils.isEmpty(productSnList2Remain)) return resultList;

        //传递剩余条码进行递归处理: 此时packageDataContextList直接为null
        return doHandlePackagePrint(reqBean, stepResult, packageRuleContext, null, productSnList2Remain, isAsyn);

    }

    //根据ID查询包装信息
    @Override
    public MesPackage getMesPackage(String organizeCode, Long packageId) { return packageExtService.getMesPackage(organizeCode, packageId); }

    //生成包装条码信息
    private MesPackage insertMesPackage(StationRequestBean reqBean, MesPackageRuleContext packageRuleContext, Integer curQty, Boolean isAsyn) {

        //封装流水号入参对象
        GenSerialNoModel serialNoModel = new GenSerialNoModel(packageRuleContext.getPackageBarcodeRule())
                .putDataMap(MesPackageRuleContext.class.getSimpleName(), packageRuleContext)
                .partNo(packageRuleContext.getPartNo()).basicInfo(reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode());

        //后面的savePackageDb那边只判断了跨天封箱情况下才会重新生成包装条码, 所以这里如果是正常工步创建则使用标包数量,如是是零件打包创建则使用实际数量生成包装条码,因为可能存在零头数量
        if (isAsyn) serialNoModel.putDataMap(MesPcnExtConstWords.QTY, new Double(curQty));

        //根据编码规则生成包装条码
        String packageNo = doGereratePackageNo(reqBean, serialNoModel, isAsyn);
        if (StringUtils.isEmpty(packageNo)) return null;
        MesPackage packageDb = new MesPackage();
        packageDb.setPackageNo(packageNo);
        packageDb.setPartNo(packageRuleContext.getPartNo());
        packageDb.setPartName(packageRuleContext.getPartName());
        packageDb.setQty(new Double(1));
        packageDb.setPackSpecQty(packageRuleContext.getPackSpecQty());
        packageDb.setGenerateType(packageRuleContext.getGenerateType());
        packageDb.setUnit(packageRuleContext.getUnit());
        packageDb.setLotNo(TimeTool.getToday());
        packageDb.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        packageDb.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.UNPRINT.getValue());
        packageDb.setWorkCenterCode(reqBean.getWorkCenterCode());
        packageDb.setWorkCellCode(reqBean.getWorkCellCode());
        packageDb.setQcStatus(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue());
        packageDb.setPackageSn(packageRuleContext.getPackCode());
        packageDb.setPackageLabelTemplate(packageRuleContext.getPackageTemplate());
        packageDb.setFid(UUID.randomUUID().toString());
        packageDb.setOrganizeCode(reqBean.getOrganizeCode());
        packageDb.setSystemSyncStatusWms(packageRuleContext.getSystemSyncStatusWms());
        ConvertBean.serviceModelInitialize(packageDb, reqBean.getUserInfo());
        //一维码是在编码规则的策略中调用transform方法生成的, 暂存到dataMap中,key=包装条码
        if (!CollectionUtils.isEmpty(serialNoModel.getDataMap()) && serialNoModel.getDataMap().containsKey(packageNo)) {
            packageDb.setPackageOneCode(serialNoModel.getDataMap().get(packageNo).toString());
        }
        if (!StringUtils.isEmpty(packageRuleContext.getPartPackWorkOrderNo())) packageDb.setWorkOrderNo(packageRuleContext.getPartPackWorkOrderNo());
        return packageDb;
    }

    //判断包装条码是否存在ID进行新增或者更新操作, 如果满足标包则标记满包状态跟打印状态
    private MesPackage savePackageDb(StationRequestBean reqBean, MesPackage packageDb, Integer curQty, Boolean isSealed, Boolean isAsyn) {

        if (!StringUtils.isEmpty(packageDb.getId())) {
            //下面直接根据ID进行修改, 所以此处置为游离态
            entityManager.detach(packageDb);
            ConvertBean.serviceModelUpdate(packageDb, reqBean.getUserInfo());
        }

        packageDb.setQty(new Double(curQty));
        if (isSealed) {
            packageDb.setLotNo(TimeTool.getToday());
            packageDb.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            packageDb.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue());
        }

        if (StringUtils.isEmpty(packageDb.getId())) return packageRepository.insert(packageDb);

        Boolean unChangePackageNo = !isSealed ? true : TimeTool.getToday().equals(packageDb.getLotNo());
        if (!unChangePackageNo) {
            //包装条码中因为含有批次号, 隔天封箱需要重新生成包装条码
            //封装流水号入参对象
            GenSerialNoModel serialNoModel = new GenSerialNoModel(packageDb.getPackageLabelTemplate())
                    .putDataMap(MesPcnExtConstWords.QTY, packageDb.getQty())
                    .putDataMap(MesPcnExtConstWords.UNIT, packageDb.getUnit())
                    .partNo(packageDb.getPartNo()).basicInfo(reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode());

            //根据编码规则生成包装条码
            String packageNo = doGereratePackageNo(reqBean, serialNoModel, isAsyn);
            if (!StringUtils.isEmpty(packageNo)) {
                String sourcePackageNo = packageDb.getPackageNo();
                packageDb.setPackageNo(packageNo);
                if (!CollectionUtils.isEmpty(serialNoModel.getDataMap()) && serialNoModel.getDataMap().containsKey(packageNo)) {
                    packageDb.setPackageOneCode(serialNoModel.getDataMap().get(packageNo).toString());
                }
                packageDb.setRemark(String.format("封箱跨天,原包装条码:%s", sourcePackageNo));
                //替换包装明细数据的包装条码
                savePackageDetailDbByPackageNo(reqBean, packageDb, sourcePackageNo);
            }
        }

        //更新操作
        savePackageDbById(reqBean, packageDb);

        return packageDb;
    }

    //判断统计方式,是否生成包装明细信息, 返回当前未满包的包装条码明细数据
    private List<MesPackageDataContext> insertPackageDetailAndBackUnSealedResultList(StationRequestBean reqBean, MesPackageRuleContext packageRuleContext,
                                                                                     MesPackage packageDb, LinkedList<String> productSnList2Cur, Boolean isSealed) {
        //当前未满包的包装条码明细数据
        List<MesPackageDataContext> resultList = null;
        if (CollectionUtils.isEmpty(productSnList2Cur)) return resultList;
        //包装条码明细ID
        Long detailId = null;
        //遍历当前满足标包的差额条码, 这边根据条码分组(因为可能存在重复条码[适配弹框输入的工单数量])
        Map<String, Integer> productSnMap = productSnList2Cur.stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(o -> 1)));
        for (Map.Entry<String, Integer> entry : productSnMap.entrySet()) {
            if (null == entry) continue;
            //判断统计方式,是否生成包装明细信息
            if (packageRuleContext.getGenerateType().compareTo(MesExtEnumUtil.PACKING_RULE_GENERATE_TYPE.PACKAGE_DETAIL.getValue()) == 0) {
                detailId = insertMesPackageDetail(reqBean, packageDb, entry.getKey(), entry.getValue());
            }
            //判断不满包则 赋值给 当前未满包的包装条码明细数据resultList
            if (!isSealed) {
                if (CollectionUtils.isEmpty(resultList)) resultList = new ArrayList<>();
                for (Integer i = 0; i < entry.getValue(); i++) {
                    MesPackageDataContext packageDataContext = new MesPackageDataContext();
                    BeanUtils.copyProperties(packageRuleContext, packageDataContext);
                    packageDataContext.setPackageId(packageDb.getId());
                    packageDataContext.setDetailId(detailId);
                    packageDataContext.setPackageNo(packageDb.getPackageNo());
                    packageDataContext.setQty(new Double(1));
                    packageDataContext.setSerialNumber(entry.getKey());
                    packageDataContext.setCreateDatetime(packageDb.getCreateDatetime());
                    packageDataContext.setModifyDatetime(TimeTool.getNowTime(true));
                    resultList.add(packageDataContext);
                }
            }
        }
        return resultList;
    }

    //生成包装明细信息
    private Long insertMesPackageDetail(StationRequestBean reqBean, MesPackage packageDb, String productSn, Integer qty) {
        MesPackageDetail packageDetailDb = new MesPackageDetail();
        packageDetailDb.setPackageNo(packageDb.getPackageNo());
        packageDetailDb.setPartNo(packageDb.getPartNo());
        packageDetailDb.setPartName(packageDb.getPartName());
        packageDetailDb.setSerialNumber(productSn);
        packageDetailDb.setProductSn(productSn);
        packageDetailDb.setQty(new Double(qty));
        packageDetailDb.setQcStatus(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue());
        packageDetailDb.setFid(UUID.randomUUID().toString());
        packageDetailDb.setOrganizeCode(reqBean.getOrganizeCode());
        ConvertBean.serviceModelInitialize(packageDetailDb, reqBean.getUserInfo());
        return packageDetailRepository.insert(packageDetailDb).getId();
    }

    //根据编码规则生成包装条码
    private String doGereratePackageNo(StationRequestBean reqBean, GenSerialNoModel serialNoModel, Boolean isAsyn) {
        try {
            return syncFuncService.syncSerialNo(serialNoModel, reqBean.getUserInfo(), reqBean.getOrganizeCode(), 1).getResultList().get(0).toString();
        } catch (ImppBusiException e) {
            if (!isAsyn) this.sendMessage(reqBean, new StationResultBean().writeDbLog(), e.getErrorDetail(), MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            else MesPcnException.throwBusiException(e.getErrorDetail());
        } catch (Exception e) {
            String webMsg = String.format("零件编码[%s]编码规则代码[%s]生成包装条码%s", serialNoModel.getPartNo(), serialNoModel.getRuleCode(), fsmRouteDataService.handleFsmCfgOrDefault(reqBean, MesPcnEnumUtil.FSM_CFG.FSM_EXCEPTION_MSG.getCode()));
            if (!isAsyn) {
                this.sendMessage(reqBean, new StationResultBean().writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.ERROR.getValue()), webMsg, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                this.cacheException(reqBean, reqBean.getStepName(), webMsg, e, true);
            } else {
                if (!StringUtils.isEmpty(reqBean.getWorkCellCode())) this.cacheException(reqBean, reqBean.getStepName(), webMsg, e, false);
                else log.info("工厂{}{} --- Exception --- {} --- {}", reqBean.getOrganizeCode(), reqBean.getDataMap().get(MesPcnExtConstWords.MESSAGE), JSONObject.toJSONString(e), Thread.currentThread().getName());
                MesPcnException.throwBusiException(webMsg);
            }
        }
        return null;
    }

    //进行打印
    @Override
    public MesProduceSnPrintModel doPrintPackageNo(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesPackageRuleContext packageRuleContext,
                          MesLabelTemplate labelTemplate, IPrintTemplateStrategyService strategyService, List<MesPackage> packageList, Boolean isAsyn) {

        MesProduceSnPrintModel printModel = null;

        if (packageRuleContext.getIsPrintPackage().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0) return printModel;

        if (null == strategyService) {
            //查询模版信息
            labelTemplate = templateService.getLabelTemplate(packageRuleContext.getPackageTemplate(), reqBean.getOrganizeCode());
            strategyService = (null != labelTemplate && !StringUtils.isEmpty(labelTemplate.getMethodCode())) ? (IPrintTemplateStrategyService) SpringContextsUtil.getBean(labelTemplate.getMethodCode()) : null;
        }
        if (null == strategyService) {
            if (!isAsyn) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), String.format("零件编码[%s]未配置有效的包装条码模版[%s]信息!", packageRuleContext.getPartNo(), packageRuleContext.getPackageTemplate()));
            else MesPcnException.throwBusiException("零件编码[%s]未配置有效的包装条码模版[%s]信息!", packageRuleContext.getPartNo(), packageRuleContext.getPackageTemplate());
        }

        MesProduceSnPrintModel mesProduceSnPrintModel = new MesProduceSnPrintModel();
        mesProduceSnPrintModel.setOrganizeCode(reqBean.getOrganizeCode());
        mesProduceSnPrintModel.setUserName(reqBean.getUserInfo());
        mesProduceSnPrintModel.setMesLabelTemplate(labelTemplate);
        mesProduceSnPrintModel.setPrinter(packageRuleContext.getPrinter());
        mesProduceSnPrintModel.setPartNo(packageRuleContext.getPartNo());
        mesProduceSnPrintModel.setPartName(packageRuleContext.getPartName());
        mesProduceSnPrintModel.getPackageList().addAll(packageList);

        try {
            printModel = strategyService.execute(null, mesProduceSnPrintModel, null, stepResult, reqBean, !StringUtils.isEmpty(reqBean.getWorkCellCode()));
        } catch (ImppBusiException e) {
            if (!isAsyn) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), e.getErrorDetail());
            else MesPcnException.throwBusiException(e.getErrorDetail());
        } catch (Exception e) {
            String webMsg = String.format("零件编码[%s]包装条码模版[%s]打印包装条码%s", packageRuleContext.getPartNo(), packageRuleContext.getPackageTemplate(), fsmRouteDataService.handleFsmCfgOrDefault(reqBean, MesPcnEnumUtil.FSM_CFG.FSM_EXCEPTION_MSG.getCode()));
            if (!isAsyn) {
                this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.ERROR.getValue()), webMsg, MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                this.cacheException(reqBean, reqBean.getStepName(), webMsg, e, true);
                foundExThrowNoShowMsg();
            } else {
                if (!StringUtils.isEmpty(reqBean.getWorkCellCode())) this.cacheException(reqBean, reqBean.getStepName(), webMsg, e, false);
                else log.info("工厂{}{} --- Exception --- {} --- {}", reqBean.getOrganizeCode(), reqBean.getDataMap().get(MesPcnExtConstWords.MESSAGE), JSONObject.toJSONString(e), Thread.currentThread().getName());
                MesPcnException.throwBusiException(webMsg);
            }
        }

        if (CollectionUtils.isEmpty(printModel.getPrintContextList())) return printModel;

        //发送打印信息
        if (!StringUtils.isEmpty(reqBean.getWorkCellCode())){
            this.sendMessage(reqBean, new StationResultBean()
                    .busiType(MesPcnEnumUtil.STATION_BUSI_TYPE.CUSTOM_COMPONENT.getValue())
                    .dataType(MesPcnEnumUtil.STATION_DATA_TYPE.FILE.getValue())
                    .customPageName(MesPcnExtConstWords.SORT_WORK_CENTER_PRINT)
                    .resultObj(printModel.getPrintContextList())
            );
        }

        //保存打印记录日志
        printedSnLogRepository.saveAll(printModel.getMesPrintedSnLogList());

        return printModel;
    }

    //强制打包业务处理
    @Override
    public void doForcePrint(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<MesPackageDataContext> packageDataContextList, MesPackage packageDb) {
        //包装条码中因为含有包装数量, 故强制打包需要重新生成包装条码
        //封装流水号入参对象
        GenSerialNoModel serialNoModel = new GenSerialNoModel(packageDataContextList.get(0).getPackageBarcodeRule())
                .putDataMap(MesPcnExtConstWords.QTY, new Double(packageDataContextList.size()))
                .putDataMap(MesPcnExtConstWords.UNIT, packageDb.getUnit())
                .partNo(packageDb.getPartNo()).basicInfo(reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode());

        //根据编码规则生成包装条码
        String packageNo = doGereratePackageNo(reqBean, serialNoModel, true);
        if (StringUtils.isEmpty(packageNo)) MesPcnException.throwBusiException("根据编码规则[%s]生成包装条码失败!", serialNoModel.getRuleCode());

        //下面直接根据ID进行修改, 所以此处置为游离态
        entityManager.detach(packageDb);
        ConvertBean.serviceModelUpdate(packageDb, reqBean.getUserInfo());
        packageDb.setQty(new Double(packageDataContextList.size()));
        packageDb.setLotNo(TimeTool.getToday());
        packageDb.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
        packageDb.setPrintStatus(MesExtEnumUtil.PRINT_STATUS.PRINTED.getValue());
        packageDb.setPackageNo(packageNo);
        if (!CollectionUtils.isEmpty(serialNoModel.getDataMap()) && serialNoModel.getDataMap().containsKey(packageNo)) {
            packageDb.setPackageOneCode(serialNoModel.getDataMap().get(packageNo).toString());
        }
        packageDb.setRemark(String.format("强制封箱,原包装条码:%s", packageDataContextList.get(0).getPackageNo()));

        List<MesPackage> packageList = new ArrayList<>();
        packageList.add(packageDb);
        //进行打印
        doPrintPackageNo(reqBean, resultBean, stepResult, packageDataContextList.get(0), null, null, packageList, true);
        //更新操作
        savePackageDbById(reqBean, packageDb);

        //替换包装明细数据的包装条码
        savePackageDetailDbByPackageNo(reqBean, packageDb, packageDataContextList.get(0).getPackageNo());
    }

    //替换包装明细数据的包装条码
    private void savePackageDetailDbByPackageNo(StationRequestBean reqBean, MesPackage packageDb, String sourcePackageNo) {
        packageDetailRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.PACKAGE_NO},
                new Object[]{reqBean.getOrganizeCode(), sourcePackageNo},
                new String[]{MesPcnExtConstWords.PACKAGE_NO, MesPcnExtConstWords.REMARK,
                        MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{packageDb.getPackageNo(), packageDb.getRemark(),
                        packageDb.getModifyUser(), packageDb.getModifyDatetime(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});
    }

    //更新操作
    private void savePackageDbById(StationRequestBean reqBean, MesPackage packageDb) {
        packageRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.ID},
                new Object[]{reqBean.getOrganizeCode(), packageDb.getId()},
                new String[]{MesPcnExtConstWords.PACKAGE_NO, MesPcnExtConstWords.PACKAGE_ONE_CODE, MesPcnExtConstWords.QTY,
                        MesPcnExtConstWords.IS_SEALED, MesPcnExtConstWords.PRINT_STATUS, MesPcnExtConstWords.LOT_NO, MesPcnExtConstWords.REMARK,
                        MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{packageDb.getPackageNo(), packageDb.getPackageOneCode(), packageDb.getQty(),
                        packageDb.getIsSealed(), packageDb.getPrintStatus(), packageDb.getLotNo(), packageDb.getRemark(),
                        packageDb.getModifyUser(), packageDb.getModifyDatetime(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});
    }

    //删除包装信息
    @Override
    public void deletePackageData(StationRequestBean reqBean, MesPackage packageDb, Integer generateType) {
        int count = packageRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.ID, MesPcnExtConstWords.IS_SEALED},
                new Object[]{reqBean.getOrganizeCode(), packageDb.getId(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()},
                new String[]{MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), reqBean.getUserInfo(), TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});
        if (count == 0 || generateType.compareTo(MesExtEnumUtil.PACKING_RULE_GENERATE_TYPE.PACKAGE.getValue()) == 0) return;
        packageDetailRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.PACKAGE_NO},
                new Object[]{reqBean.getOrganizeCode(), packageDb.getPackageNo()},
                new String[]{MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), reqBean.getUserInfo(), TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});
    }

    //修改包装信息的数量
    @Override
    public void savePackageData(StationRequestBean reqBean, MesPackage packageDb, Double qty) {
        packageRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.ID, MesPcnExtConstWords.IS_SEALED},
                new Object[]{reqBean.getOrganizeCode(), packageDb.getId(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()},
                new String[]{MesPcnExtConstWords.QTY, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{qty, reqBean.getUserInfo(), TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});
    }

    //过滤成品包装规则, 取默认包装对应的数据
    private MesPackingRule filterPackingRule(List<MesPackingRule> packingRuleList) {
       if (CollectionUtils.isEmpty(packingRuleList)) return null;
       if (packingRuleList.size() == 1) return packingRuleList.get(0);
       Optional<MesPackingRule> optional = packingRuleList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getDefaultFlag()) && o.getDefaultFlag().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0)).findFirst();
       return (null != optional && optional.isPresent()) ? optional.get() : null;
    }

    //根据默认包装获取成品包装明细规则
    private MesPackingRuleDetail filterPackingRuleDetail(List<MesPackingRuleDetail> packingRuleDetailList, MesPackingRule packingRule) {
        if (CollectionUtils.isEmpty(packingRuleDetailList)) return null;
        if (packingRuleDetailList.size() == 1) return packingRuleDetailList.get(0);
        Optional<MesPackingRuleDetail> optional = packingRuleDetailList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPackageCode()) && o.getPackageCode().equals(packingRule.getPackageCode()))).findFirst();
        return (null != optional && optional.isPresent()) ? optional.get() : null;
    }

    //零件打包业务处理
    @Override
    public void doHandlePackagePart(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, MesPackageDataContext packageDataContext) {
        //生成包装及明细, 根据标包数量判断是否执行打印 [递归]
        doHandlePackagePrint(reqBean, stepResult, packageDataContext, null, generateVirtualPs(packageDataContext.getQty()), true);
        //进行打印
        doPrintPackageNo(reqBean, resultBean, stepResult, packageDataContext, null, null, (List<MesPackage>) stepResult.getDataCollection(), true);
    }

    //生成虚拟条码,零件打包不写包装明细数据, 只是为了适配工步中的方法去递归生成包装条码
    @Override
    public LinkedList<String> generateVirtualPs(Double qty) {
        LinkedList<String> virtualPsList = new LinkedList<>();
        for (int i = 0; i < qty.intValue(); i ++) {
            virtualPsList.add(String.valueOf(i));
        }
        return virtualPsList;
    }

    //生成一样的虚拟条码, 适配弹框输入工单数量
    @Override
    public LinkedList<String> generateVirtualPs(Double qty, String productSn) {
        LinkedList<String> virtualPsList = new LinkedList<>();
        for (int i = 0; i < qty.intValue(); i ++) {
            virtualPsList.add(productSn);
        }
        return virtualPsList;
    }

}
