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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesBoxingErrorProofingService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesConfigService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionRecordService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.util.MesPcnException;
import cn.estsh.i3plus.ext.mes.pcn.pojo.constant.MesCommonConstant;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.CheckTool;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.repository.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import cn.estsh.impp.framework.boot.util.ResultBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description : MES装箱防错
 * @Reference :
 * @Author : junsheng.li
 * @CreateDate 2024/6/7 14:33
 * @Modify:
 **/
@Service
@Slf4j
public class MesBoxingErrorProofingService implements IMesBoxingErrorProofingService {

    @Resource(name = CommonConstWords.IMPP_REDIS_MES_PCN)
    private ImppRedis redisMesPcn;

    @Autowired
    private MesPackageRepository mesPackageRDao;

    @Autowired
    private MesPartRepository partRDao;

    @Autowired
    private MesPackingDefineRepository mesPackingDefineRDao;

    @Autowired
    private MesPackingDefineDetailsRepository mesPackingDefineDetailsRDao;

    @Autowired
    private MesPackageDetailRepository mesPackageDetailRDao;

    @Autowired
    private IMesConfigService configService;

    @Autowired
    private MesPackageResultRepository mesPackageResultRDao;

    @Autowired
    private MesPackageSnRepository mesPackageSnRDao;

    @Autowired
    private IMesProduceSnExtService mesProduceSnExtService;

    @Autowired
    private IMesProductionRecordService mesProductionRecordService;

    @Autowired
    private MesCustomerPartRepository mesCustomerPartRDao;

    @Autowired
    private MesCustPartInvoicedRepository partInvoicedRao;


    @Override
    public ListPager<MesPackageDetail> queryMesPackageDetailByPager(MesPackage mesPackage, Pager pager) {

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(mesPackage.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(mesPackage.getPackageNo(), MesPcnExtConstWords.PACKAGE_NO, packBean);
        if (pager == null || Objects.equals(pager.getPageSize(), 0)) {
            return new ListPager<>(mesPackageDetailRDao.findByHqlWhere(packBean), pager);
        }
        pager = PagerHelper.getPager(pager, mesPackageDetailRDao.findByHqlWhereCount(packBean));
        List<MesPackageDetail> resultList = mesPackageDetailRDao.findByHqlWherePage(packBean, pager);
        return new ListPager<>(resultList, pager);
    }

    @Override
    public Integer getIsMemory(String organizeCode, String userName) {
        Object object = redisMesPcn.getObject(getKey(organizeCode, userName));
        if (Objects.isNull(object)) {
            return CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue();
        } else {
            return (Integer) object;
        }
    }

    @Override
    public ResultBean doScan(MesPackageDetail mesPackageDetail) {
        //获取包装定义
        MesPackingDefine packingDefine = getMesPackingDefine(mesPackageDetail);
        //扫描的是包装
        if (mesPackageDetail.getIsScanPackageBoolean()) {
            checkNotNull(mesPackageDetail);
            MesPackage mesPackage = getMesPackage(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getPackageNo());
            if (Objects.isNull(mesPackage)) {
                MesPart mesPart;
                Double qty;
                String packageOneCode = MesPcnExtConstWords.EMPTY;
                //WMS打印的条码信息
                MesPackageSn mesPackageSn = getMesPackageSn(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getPackageNo());
                if(!Objects.isNull(mesPackageSn)){
                    mesPart = getPart(mesPackageSn.getOrganizeCode(),mesPackageSn.getPartNo());
                    qty = mesPackageSn.getQty();
                    packageOneCode = mesPackageSn.getPackageOneCode();
                }else{
                    //解析获取信息保存
                    if (StringUtils.isEmpty(packingDefine.getSplitChar())) {
                        MesPcnException.throwMesBusiException("箱类别代号[%s]分隔符不能为空,请检查数据!", packingDefine.getPackCode());
                    }
                    String[] split = mesPackageDetail.getPackageNo().split("\\" + packingDefine.getSplitChar());
                    //获取序列号
                    checkSerial(packingDefine, split);
                    //工厂校验
                    checkOrganizeCode(mesPackageDetail, packingDefine, split);
                    //获取物料信息是否存在
                    mesPart = getMesPart(mesPackageDetail, packingDefine, split);
                    //获取数量信息是否存在
                    qty = getQty(packingDefine, split);
                }
                mesPackage = mesPackageRDao.insert(getMesPackage(mesPackageDetail, mesPart, qty, packingDefine,packageOneCode));
            }
            mesPackage.setIsPackage(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            return ResultBean.success("箱条码扫描成功,请扫零件条码!").setResultObject(mesPackage);
        } else {
            /**
             * 2024-12-23 修复bug 44242
             * 已经关箱的箱条码，如果重复扫描，不需要重置，可以扫描下一个需要装箱的条码。
             *
             */
            checkNotNull(mesPackageDetail);
            //校验零件条码是否存在
            if (StringUtils.isEmpty(mesPackageDetail.getSerialNumber())) {
                MesPcnException.throwMesBusiException("零件条码不允许为空,请检查数据!");
            }
            //校验包装条码信息
            MesPackage mesPackage = getMesPackageAndCheck(mesPackageDetail.getPackageNo(), mesPackageDetail.getOrganizeCode());
            //校验是否已关闭
            if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == mesPackage.getIsSealed()) {
                List<MesProduceSn> produceSnList = mesProduceSnExtService.getProduceSnList(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getSerialNumber());
                //1.查询包装明细是否包含此零件
                List<MesPackingDefineDetails> defineDetails = getMesPackingDefineDetailsNew(mesPackageDetail.getOrganizeCode(), mesPackage.getPackageSn(), mesPackage.getPartNo());
                //确保是自制件和外协件
                if ((produceSnList != null && !produceSnList.isEmpty())|| (defineDetails != null && !defineDetails.isEmpty() && StringUtils.isEmpty(defineDetails.get(0).getPackageBarcodeRule()))) {
                    MesPcnException.throwMesBusiException("箱条码已封箱，不允许扫描零件条码，请检查数据！");
                }else {
                    //扫描的是箱条码
                    mesPackageDetail.setIsScanPackage(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
                    mesPackageDetail.setPackageNo(mesPackageDetail.getSerialNumber());
                    return this.doScan(mesPackageDetail);
                }
            }
            //校验条码规则
            MesPart mesPart = getMesPartNew(mesPackageDetail, mesPackage, packingDefine);
            //包装规格明细
            MesPackageDetail saveMesPackageDetail = getPackageDetail(mesPackageDetail, mesPart, packingDefine);
            if (mesPackageDetail.getIsMemoryBoolean()) {
                //保存包装明细
                mesPackageDetailRDao.insert(saveMesPackageDetail);
                //更新包装表
                updateMesPackage(mesPackage, mesPackageDetail.getModifyUser(), 1d, false, packingDefine);
            }
            //缓存是否记忆开关
            saveRedis(getKey(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getModifyUser()),mesPackageDetail.getIsMemory());
            mesPackage.setMesPackageDetail(saveMesPackageDetail);
            if(mesPackage.getIsSealed() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()){
                return ResultBean.success("当前箱条码已完成装箱,请扫描下一个箱条码!").setResultObject(mesPackage);
            }
            return ResultBean.success("零件条码扫描成功,请继续扫描零件条码!").setResultObject(mesPackage);
        }
    }

    @Override
    public ResultBean saveMesPackageDetails(List<MesPackageDetail> mesPackageDetailList, String userName) {
        MesPackageDetail packageDetail = mesPackageDetailList.iterator().next();
        //校验包装条码信息
        MesPackage mesPackage = getMesPackageAndCheck(packageDetail.getPackageNo(), packageDetail.getOrganizeCode());
        //校验是否已关闭
        if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == mesPackage.getIsSealed()) {
            MesPcnException.throwMesBusiException("箱条码已封箱,不允许扫描零件条码,请检查数据!");
        }
        //去掉重复零件条码
        List<MesPackageDetail> saveMesPackageDetailList = new ArrayList<>();
        checkSerialNumber(saveMesPackageDetailList,mesPackageDetailList, packageDetail, userName);
        //保存包装明细
        if(!CollectionUtils.isEmpty(saveMesPackageDetailList)){
            mesPackageDetailRDao.saveAll(saveMesPackageDetailList);
            int qty = saveMesPackageDetailList.size();
            //更新包装表
            updateMesPackage(mesPackage, userName, qty, false, null);
        }
        if(mesPackage.getIsSealed() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()){
            return ResultBean.success("当前箱条码已完成装箱,请扫描下一个箱条码!").setResultObject(mesPackage);
        }
        return ResultBean.success("提交成功,请继续扫描零件条码!").setResultObject(mesPackage);
    }

    @Override
    public ResultBean updateMesPackage(MesPackage mesPackage) {
        String userName = mesPackage.getModifyUser();
        if (Objects.isNull(CommonEnumUtil.TRUE_OR_FALSE.valueOfDescription(mesPackage.getIsSealed()))) {
            MesPcnException.throwMesBusiException("是否封箱不能为空,请检查数据!");
        }
        //查询包装条码信息
        MesPackage mesPackageDb = getMesPackageAndCheck(mesPackage.getPackageNo(), mesPackage.getOrganizeCode());
        if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == mesPackage.getIsSealed()) {
            if (CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == mesPackageDb.getIsSealed()) {
                MesPcnException.throwMesBusiException("箱条码[%s]状态为已关箱,请勿重复操作,请检查数据!", mesPackage.getPackageNo());
            }
            //校验是否存在包装明细
            DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(mesPackage.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(mesPackage.getPackageNo(), "packageNo", ddlPackBean);
            if (!mesPackageDetailRDao.isExitByHql(ddlPackBean)) {
                MesPcnException.throwMesBusiException("箱条码[%s]下不存在零件条码,不允许关箱,请检查数据!", mesPackage.getPackageNo());
            }
            //关箱
            updateMesPackage(mesPackageDb, mesPackage.getModifyUser(), 0d, true, null);
            return ResultBean.success("关箱成功!");
        } else {
            if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == mesPackageDb.getIsSealed()) {
                MesPcnException.throwMesBusiException("箱条码[%s]状态不为已关箱,不需要拆箱,请检查数据!", mesPackage.getPackageNo());
            }
            //拆箱
            unboxing(mesPackage, userName, mesPackageDb);
            return ResultBean.success("拆箱成功!");
        }
    }

    @Override
    public void updateMesPackageDetails(MesPackageDetail mesPackageDetail) {
        //查询包装条码信息
        MesPackage mesPackageDb = getMesPackageAndCheck(mesPackageDetail.getPackageNo(), mesPackageDetail.getOrganizeCode());
        if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == mesPackageDb.getIsSealed()) {
            MesPcnException.throwMesBusiException("箱条码[%s]不为已关箱状态,不允许操作替换条码,请检查数据!", mesPackageDetail.getPackageNo());
        }
        //校验是否重复扫描
        List<MesPackageDetail> mesPackageDetails = getMesPackageDetailList(mesPackageDetail);
        //校验条码是否符合规则
        //获取包装定义
        MesPackingDefine packingDefine = getMesPackingDefine(mesPackageDetail);
        MesPart mesPart = getMesPartNew(mesPackageDetail, mesPackageDb, packingDefine);
        boolean exist = false;
        for (MesPackageDetail packageDetail : mesPackageDetails) {
            //替换条码是否已经存在
            if (packageDetail.getSerialNumber().equals(mesPackageDetail.getSerialNumber())) {
                MesPcnException.throwMesBusiException("零件条码[%s]已存在存在,请检查数据!", mesPackageDetail.getSerialNumber());
            }
            //替换条码
            if (packageDetail.getSerialNumber().equals(mesPackageDetail.getOldSerialNumber())) {
                packageDetail.setSerialNumber(mesPackageDetail.getSerialNumber());
                packageDetail.setOldSerialNumber(mesPackageDetail.getOldSerialNumber());
                packageDetail.setPartNo(mesPart.getPartNo());
                packageDetail.setPartName(mesPart.getPartName());
                ConvertBean.serviceModelUpdate(packageDetail, mesPackageDetail.getModifyUser());
                exist = true;
            }
        }
        if(!exist){
            MesPcnException.throwMesBusiException("原零件条码[%s]不存在,请检查数据!", mesPackageDetail.getOldSerialNumber());
        }
        mesPackageDetailRDao.saveAll(mesPackageDetails);
    }

    private List<MesPackageDetail> getMesPackageDetailList(MesPackageDetail mesPackageDetail) {
        String[] serialNumberList = new String[]{mesPackageDetail.getSerialNumber(), mesPackageDetail.getOldSerialNumber()};
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(mesPackageDetail.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(mesPackageDetail.getPackageNo(), MesPcnExtConstWords.PACKAGE_NO, ddlPackBean);
        DdlPreparedPack.getInPackArray(serialNumberList, MesPcnExtConstWords.SERIAL_NUMBER, ddlPackBean);
        List<MesPackageDetail> mesPackageDetails = mesPackageDetailRDao.findByHqlWhere(ddlPackBean);
        if (CollectionUtils.isEmpty(mesPackageDetails)) {
            MesPcnException.throwMesBusiException("零件条码[%s]不存在,请检查数据!", mesPackageDetail.getOldSerialNumber());
        }
        return mesPackageDetails;
    }

    @Override
    public void unLock(String organizeCode, String pwd) {
        String cfgValue = configService.getCfgValue(organizeCode, MesCommonConstant.BOXING_ERROR_PROOFING_PWD);
        if (!Objects.equals(cfgValue, pwd)) {
            MesPcnException.throwMesBusiException("解锁失败密码错误,请检查数据!");
        }
    }

//    private MesPart getMesPart(MesPackageDetail mesPackageDetail, MesPackage mesPackage, MesPackingDefine packingDefine) {
//        //校验是否重复扫描
//        checkSerialNumber(mesPackageDetail);
//        //获取包装定义明细
//        List<MesPackingDefineDetails> defineDetails = getMesPackingDefineDetails(mesPackageDetail.getOrganizeCode(), mesPackage.getPackageSn());
//        //校验是否包含
////        String partNo = getPartNo(mesPackageDetail, mesPackage, defineDetails);
//        //校验条码信息
//        String partNo = checkSn(mesPackageDetail, packingDefine, mesPackage, defineDetails);
//        //物料信息
//        return getPart(mesPackageDetail.getOrganizeCode(), partNo);
//    }

    private MesPart getMesPartNew(MesPackageDetail mesPackageDetail, MesPackage mesPackage, MesPackingDefine packingDefine) {
        //校验是否重复扫描
        checkSerialNumber(mesPackageDetail, packingDefine);
        //校验条码信息
        String partNo = checkSnNew(mesPackageDetail, packingDefine, mesPackage);
        //物料信息
        return getPart(mesPackageDetail.getOrganizeCode(), partNo);
    }

    private void checkSerialNumber(MesPackageDetail mesPackageDetail, MesPackingDefine packingDefine) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(mesPackageDetail.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(mesPackageDetail.getSerialNumber(), MesPcnExtConstWords.SERIAL_NUMBER, ddlPackBean);
        if (Objects.equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), packingDefine.getIsConfirmCheck())) {
            DdlPreparedPack.getNumEqualPack(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), "isSecondPack", ddlPackBean);
        }
        if (mesPackageDetailRDao.isExitByHql(ddlPackBean)) {
            MesPcnException.throwMesBusiException("零件条码[%s]已装箱,请检查数据!", mesPackageDetail.getSerialNumber());
        }
    }

    private List<MesPackingDefineDetails> getMesPackingDefineDetails(String organizeCode, String packCode) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(packCode, MesPcnExtConstWords.PACK_CODE, ddlPackBean);
        List<MesPackingDefineDetails> defineDetails = mesPackingDefineDetailsRDao.findByHqlWhere(ddlPackBean);
        if (CollectionUtils.isEmpty(defineDetails)) {
            MesPcnException.throwMesBusiException("箱类别代号[%s]包装定义明细未维护,请检查数据!", packCode);
        }
        return defineDetails;
    }

    private List<MesPackingDefineDetails> getMesPackingDefineDetailsNew(String organizeCode, String packCode,String partNo) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(packCode, "packCode", ddlPackBean);
        DdlPreparedPack.getStringEqualPack(partNo, "partNo", ddlPackBean);
        List<MesPackingDefineDetails> defineDetails = mesPackingDefineDetailsRDao.findByHqlWhere(ddlPackBean);
        if (CollectionUtils.isEmpty(defineDetails)) {
            MesPcnException.throwMesBusiException("箱类别代号【%s】包装定义明细未维护，请检查数据！", packCode);
        }
        return defineDetails;
    }

    private void unboxing(MesPackage mesPackage, String userName, MesPackage mesPackageDb) {
        //更新包装表
        mesPackageDb.setQty(0d);
        mesPackageDb.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        ConvertBean.serviceModelUpdate(mesPackageDb, userName);
        mesPackageRDao.update(mesPackageDb);

        //软删包装明细
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(mesPackage.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(mesPackage.getPackageNo(), MesPcnExtConstWords.PACKAGE_NO, ddlPackBean);
        mesPackageDetailRDao.updateByProperties(
                new String[]{MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.IS_DELETED},
                new Object[]{userName, TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()},
                ddlPackBean);
    }


    private MesPackage getMesPackageAndCheck(String packageNo, String organizeCode) {
        MesPackage mesPackageDb = getMesPackage(organizeCode, packageNo);
        if (Objects.isNull(mesPackageDb)) {
            MesPcnException.throwMesBusiException("箱条码[%s]信息不存在,请检查数据!", packageNo);
        }
        return mesPackageDb;
    }

    private void checkSerialNumber(List<MesPackageDetail> saveMesPackageDetailList,List<MesPackageDetail> mesPackageDetailList, MesPackageDetail packageDetail, String userName) {
        List<MesPackageDetail> mesPackageDetails = getMesPackageDetailList(packageDetail.getOrganizeCode(), packageDetail.getPackageNo());
        if (!CollectionUtils.isEmpty(mesPackageDetails)) {
            List<String> serialNumberList = mesPackageDetails.stream().map(MesPackageDetail::getSerialNumber).collect(Collectors.toList());
            for (MesPackageDetail mesPackageDetail : mesPackageDetailList) {
                ConvertBean.serviceModelInitialize(mesPackageDetail, userName);
                if (!serialNumberList.contains(mesPackageDetail.getSerialNumber())) {
                    //校验零件规则
                    saveMesPackageDetailList.add(mesPackageDetail);
                }
            }
        }else{
            saveMesPackageDetailList.addAll(mesPackageDetailList);
        }
    }


    private void updateMesPackage(MesPackage mesPackage, String userName, double qty, boolean close, MesPackingDefine packingDefine) {
        mesPackage.setQty(MathOperation.add(mesPackage.getQty(), qty));
        if (mesPackage.getPackSpecQty() <= mesPackage.getQty() || close) {
            mesPackage.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            mesPackage.setLotNo(TimeTool.getToday());
            //数据写入接口表回传wms
            if (packingDefine == null || !Objects.equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), packingDefine.getIsConfirmCheck())) {
                saveMesPackageResult(mesPackage, userName);
            }
        }
        ConvertBean.serviceModelUpdate(mesPackage, userName);
        mesPackageRDao.update(mesPackage);
    }

    private void saveMesPackageResult(MesPackage mesPackage, String userName) {
        MesPackageResult mesPackageResult;
        List<MesPackageResult> mesPackageResultList = new ArrayList<>();
        List<MesPackageDetail> mesPackageDetailList = getMesPackageDetailList(mesPackage.getOrganizeCode(), mesPackage.getPackageNo());
        for (MesPackageDetail mesPackageDetail : mesPackageDetailList) {
            mesPackageResult = new MesPackageResult(mesPackageDetail, mesPackage.getQty());
            ConvertBean.serviceModelInitialize(mesPackageResult, userName);
            mesPackageResultList.add(mesPackageResult);
        }
        mesPackageResultRDao.saveAll(mesPackageResultList);
    }

    private List<MesPackageDetail> getMesPackageDetailList(String organizeCode, String packageNo) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(packageNo, MesPcnExtConstWords.PACKAGE_NO, ddlPackBean);
        List<MesPackageDetail> mesPackageDetails = mesPackageDetailRDao.findByHqlWhere(ddlPackBean);
        return mesPackageDetails;
    }

    private MesPackageDetail getPackageDetail(MesPackageDetail mesPackageDetail, MesPart mesPart, MesPackingDefine packingDefine) {
        MesPackageDetail saveMesPackageDetail = new MesPackageDetail();
        saveMesPackageDetail.setPackageNo(mesPackageDetail.getPackageNo());
        saveMesPackageDetail.setSerialNumber(mesPackageDetail.getSerialNumber());
        saveMesPackageDetail.setPartNo(mesPart.getPartNo());
        saveMesPackageDetail.setPartName(mesPart.getPartName());
        saveMesPackageDetail.setQty(1d);
        saveMesPackageDetail.setOrganizeCode(mesPackageDetail.getOrganizeCode());
        if (packingDefine != null && Objects.equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), packingDefine.getIsConfirmCheck())) {
            saveMesPackageDetail.setIsSecondPack(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
        } else {
            saveMesPackageDetail.setIsSecondPack(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        }
        ConvertBean.serviceModelInitialize(saveMesPackageDetail, mesPackageDetail.getCreateUser());
        return saveMesPackageDetail;
    }

    private String  checkSn(MesPackageDetail mesPackageDetail, MesPackingDefine packingDefine,MesPackage mesPackage,List<MesPackingDefineDetails> defineDetails ) {
        List<MesProduceSn> produceSnList = mesProduceSnExtService.getProduceSnList(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getSerialNumber());
        String packageBarcodeRule;
        String partNo = null;
        if (!produceSnList.isEmpty()){
            /**
             * 自制件不需要校验规则 by castle 2024-12-18 bug 44247
             *
             */
            partNo = produceSnList.get(0).getPartNo();
        }else {
            for (MesPackingDefineDetails defineDetail : defineDetails) {
                //条码规则为空
                if (StringUtils.isEmpty(defineDetail.getPackageBarcodeRule())) {
                    MesPcnException.throwMesBusiException("箱类别代号【%s】零件号【%s】条码规则未维护，请检查数据！", mesPackage.getPackageSn(), defineDetail.getPartNo());
                }
                packageBarcodeRule = defineDetail.getPackageBarcodeRule().replace("*", "");
                //包含箱条码
                if (mesPackageDetail.getSerialNumber().contains(packageBarcodeRule)) {
                    partNo = defineDetail.getPartNo();
                    break;
                }
            }
        }
        if (Objects.isNull(partNo)) {
            MesPcnException.throwMesBusiException("零件条码【%s】未匹配到符合条码规则的数据，请检查数据！", mesPackageDetail.getSerialNumber());
        }
        //校验零件是否一致
        if (!partNo.equals(mesPackage.getPartNo())) {
            MesPcnException.throwMesBusiException("零件条码【%s】包装定义明细零件【%s】和箱零件【%s】不一致，请检查数据！", mesPackageDetail.getSerialNumber(), partNo, mesPackage.getPartNo());
        }


        if (!CollectionUtils.isEmpty(produceSnList)) {
            MesProduceSn nextMesProduceSn = produceSnList.stream().sorted(Comparator.comparing(MesProduceSn::getCreateDatetime).reversed()).collect(Collectors.toList()).iterator().next();
            if (!MesExtEnumUtil.PRODUCE_SN_STATUS.checkAllowBoxingErrorProofing(nextMesProduceSn.getSnStatus()) || !MesExtEnumUtil.PRODUCE_QC_STATUS.checkAllowBoxingErrorProofing(nextMesProduceSn.getQcStatus())) {
                MesPcnException.throwMesBusiException("条码[%s]状态[%s]质量状态[%s]不允许操作装箱防错,请检查数据!",
                        mesPackageDetail.getSerialNumber(), MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(nextMesProduceSn.getSnStatus()),
                        MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(nextMesProduceSn.getQcStatus()));
            }
            if(!partNo.equals(nextMesProduceSn.getPartNo())){
                MesPcnException.throwMesBusiException("条码[%s]零件号[%s]和箱零件[%s]不匹配,请检查数据!", mesPackageDetail.getSerialNumber(), nextMesProduceSn.getPartNo(), partNo);
            }
        }
        //工艺校验
        if(!Objects.isNull(packingDefine) && !Objects.isNull(packingDefine.getCheckCraftFlag()) && CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == packingDefine.getCheckCraftFlag()){
            //查询加工记录
            List<MesProductionRecord> productionRecordList = mesProductionRecordService.findProductionRecordList(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getSerialNumber());
            if(CollectionUtils.isEmpty(productionRecordList)){
                MesPcnException.throwMesBusiException("条码[%s]校验装箱防错对应工艺失败,加工记录信息不存在,请检查数据!", mesPackageDetail.getSerialNumber());
            }
            if(StringUtils.isEmpty(packingDefine.getCraft())){
                MesPcnException.throwMesBusiException("条码[%s]校验装箱防错对应工艺为空,请检查数据!", mesPackageDetail.getSerialNumber());
            }
            //校验条码是否经过该工艺
            Optional<MesProductionRecord> productionRecordOptional = productionRecordList.stream().filter(t -> !StringUtils.isEmpty(t.getCraftCode()) && packingDefine.getCraft().equals(t.getCraftCode())).findFirst();
            if(!productionRecordOptional.isPresent()){
                MesPcnException.throwMesBusiException("条码[%s]校验装箱防错对应工艺[%s]失败,请检查数据!", mesPackageDetail.getSerialNumber(),packingDefine.getCraft());
            }
        }

        return partNo;
    }

    /**
     * 2024/12/19 10:50 by castle fix bug 44247
     * 装箱防错逻辑优化：
     * 1.箱条码会包含零件号（客户零件号），取箱条码中的零件号，作为扫描条码的零件号
     * 2.自制件 & 外协件
     *
     *   2.1 自制件
     *
     *          2.2.1 首先查询包装明细中包含此零件 且 规则为空 --- 确定为自制件
     *
     *          2.2.2  根据零件号和扫描的条码，查询条码表是否存在，存在即自制件，不需要校验规则 (需要校验条码状态 qcStatus=10合格 15 可疑转正常 snStatus = 10 或 20)
     *
     *   2.2 外协件
     *
     *          根据零件号 查询包装明细的规则，校验规则是否符合扫描的箱条码
     * @param mesPackageDetail
     * @param packingDefine
     * @param mesPackage
     * @return
     */
    private String  checkSnNew(MesPackageDetail mesPackageDetail, MesPackingDefine packingDefine,MesPackage mesPackage ) {
        String partNo = mesPackage.getPartNo();
        //1.查询包装明细是否包含此零件
        List<MesPackingDefineDetails> defineDetails = getMesPackingDefineDetailsNew(mesPackageDetail.getOrganizeCode(), mesPackage.getPackageSn(), partNo);
        if (defineDetails.isEmpty()) {
            MesPcnException.throwMesBusiException("箱类别代号【%s】零件号【%s】未维护，请检查数据！", mesPackage.getPackageSn(), partNo);
        }
        MesPackingDefineDetails mesPackingDefineDetails = defineDetails.get(0);
        if (StringUtils.isEmpty(mesPackingDefineDetails.getPackageBarcodeRule())){
            //是自制件
            MesProduceSn produceSn = mesProduceSnExtService.getProduceSnForBox(mesPackageDetail.getSerialNumber(), partNo, mesPackageDetail.getOrganizeCode());
            if (produceSn == null){
                MesPcnException.throwMesBusiException("扫描条码【%s】零件号【%s】在条码表不存在, 请检查数据！", mesPackageDetail.getSerialNumber(), partNo);
            }
            if (!MesExtEnumUtil.PRODUCE_QC_STATUS.checkAllowBoxingErrorProofing(produceSn.getQcStatus())){
                MesPcnException.throwBusiException("扫描条码【%s】零件号【%s】,QC状态【%s】,不能包装此零件！",
                        mesPackageDetail.getSerialNumber(), partNo, MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSn.getQcStatus()));
            }
            if (!MesExtEnumUtil.PRODUCE_SN_STATUS.checkAllowBoxingErrorProofing(produceSn.getSnStatus())) {
                MesPcnException.throwBusiException("扫描条码【%s】零件号【%s】,条码状态【%s】,不能包装此零件！",
                        mesPackageDetail.getSerialNumber(), partNo, MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSn.getSnStatus()));
            }
        }else{
            //外协件
            String packageBarcodeRule = mesPackingDefineDetails.getPackageBarcodeRule().replace("*", "");
            boolean checkResult = mesPackageDetail.getSerialNumber().contains(packageBarcodeRule);
            if (!checkResult){
                MesPcnException.throwMesBusiException("零件条码【%s】未匹配到符合条码规则的数据，请检查数据！", mesPackageDetail.getSerialNumber());
            }
        }

        //工艺校验
        if(!Objects.isNull(packingDefine) && !Objects.isNull(packingDefine.getCheckCraftFlag()) && CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == packingDefine.getCheckCraftFlag()){
            //查询加工记录
            List<MesProductionRecord> productionRecordList = mesProductionRecordService.findProductionRecordList(mesPackageDetail.getOrganizeCode(), mesPackageDetail.getSerialNumber());
            if(CollectionUtils.isEmpty(productionRecordList)){
                MesPcnException.throwMesBusiException("条码【%s】校验装箱防错对应工艺失败，加工记录信息不存在，请检查数据！", mesPackageDetail.getSerialNumber());
            }
            if(StringUtils.isEmpty(packingDefine.getCraft())){
                MesPcnException.throwMesBusiException("条码【%s】校验装箱防错对应工艺为空，请检查数据！", mesPackageDetail.getSerialNumber());
            }
            //校验条码是否经过该工艺
            Optional<MesProductionRecord> productionRecordOptional = productionRecordList.stream().filter(t -> !StringUtils.isEmpty(t.getCraftCode()) && packingDefine.getCraft().equals(t.getCraftCode())).findFirst();
            if(!productionRecordOptional.isPresent()){
                MesPcnException.throwMesBusiException("条码【%s】校验装箱防错对应工艺【%s】失败，请检查数据！", mesPackageDetail.getSerialNumber(),packingDefine.getCraft());
            }
        }

        return partNo;
    }

    private String getPartNo(MesPackageDetail mesPackageDetail, MesPackage mesPackage, List<MesPackingDefineDetails> defineDetails) {
        String packageBarcodeRule;
        String partNo = null;
        for (MesPackingDefineDetails defineDetail : defineDetails) {
            //条码规则为空
            if (StringUtils.isEmpty(defineDetail.getPackageBarcodeRule())) {
                MesPcnException.throwMesBusiException("箱类别代号[%s]零件号[%s]条码规则未维护,请检查数据!", mesPackage.getPackageSn(), defineDetail.getPartNo());
            }
            packageBarcodeRule = defineDetail.getPackageBarcodeRule().replace(MesPcnExtConstWords.ASTERISK, MesPcnExtConstWords.EMPTY);
            //包含箱条码
            if (mesPackageDetail.getSerialNumber().contains(packageBarcodeRule)) {
                partNo = defineDetail.getPartNo();
                break;
            }
        }
        if (Objects.isNull(partNo)) {
            MesPcnException.throwMesBusiException("零件条码[%s]未匹配到符合条码规则的数据,请检查数据!", mesPackageDetail.getSerialNumber());
        }
        //校验零件是否一致
        if (!partNo.equals(mesPackage.getPartNo())) {
            MesPcnException.throwMesBusiException("零件条码[%s]包装定义明细零件[%s]和箱零件[%s]不一致,请检查数据!", mesPackageDetail.getSerialNumber(), partNo, mesPackage.getPartNo());
        }
        return partNo;
    }

    private void checkNotNull(MesPackageDetail mesPackageDetail) {
        if (StringUtils.isEmpty(mesPackageDetail.getPackageNo())) {
            MesPcnException.throwMesBusiException("包装编码不能为空,请检查数据!");
        }
        if (StringUtils.isEmpty(mesPackageDetail.getScanType())) {
            MesPcnException.throwMesBusiException("客户条码规则不能为空,请检查数据!");
        }
    }

    private void checkSerial(MesPackingDefine packingDefine, String[] split) {
        if (StringUtils.isEmpty(packingDefine.getSerialIdIndex()) || packingDefine.getSerialIdIndex() > split.length
                || StringUtils.isEmpty(split[packingDefine.getSerialIdIndex() - 1])) {
            MesPcnException.throwMesBusiException("序列号所在位置不存在,请检查数据!");
        }
        String serialNo = split[packingDefine.getSerialIdIndex() - 1];
    }

    private void checkOrganizeCode(MesPackageDetail mesPackageDetail, MesPackingDefine packingDefine, String[] split) {
        if (Objects.equals(packingDefine.getCheckOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue())) {
            return;
        }
        if (StringUtils.isEmpty(packingDefine.getOrganizeIndex()) || packingDefine.getOrganizeIndex() > split.length
                || StringUtils.isEmpty(split[packingDefine.getOrganizeIndex() - 1])) {
            MesPcnException.throwMesBusiException("工厂所在位置不存在,请检查数据!");
        }
        String organizeCode = split[packingDefine.getOrganizeIndex() - 1];
        if (!Objects.equals(organizeCode, mesPackageDetail.getOrganizeCode())) {
            MesPcnException.throwMesBusiException("箱条码工厂[%s]和当前工厂[%s]不匹配,请检查数据!", organizeCode, mesPackageDetail.getOrganizeCode());
        }
    }

    private MesPart getMesPart(MesPackageDetail mesPackageDetail, MesPackingDefine packingDefine, String[] split) {
        if (StringUtils.isEmpty(packingDefine.getPartNoIndex()) || packingDefine.getPartNoIndex() > split.length
                || StringUtils.isEmpty(split[packingDefine.getPartNoIndex() - 1])) {
            MesPcnException.throwMesBusiException("物料号所在位置不存在,请检查数据!");
        }
        String partNo = split[packingDefine.getPartNoIndex() - 1];
        if (Objects.equals(packingDefine.getPackBarcodeCustPartNo(), CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue())) {
            DdlPackBean invoicePackBean = DdlPackBean.getDdlPackBean(mesPackageDetail.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(partNo, MesPcnExtConstWords.CUST_PART_NO, invoicePackBean);
            MesCustPartInvoiced invoiced = partInvoicedRao.getByProperty(invoicePackBean);
            if (invoiced != null && !StringUtils.isEmpty(invoiced.getPartNo())) {
                partNo = invoiced.getPartNo();
            } else {
                DdlPackBean packBean = DdlPackBean.getDdlPackBean(mesPackageDetail.getOrganizeCode());
                DdlPreparedPack.getStringEqualPack(partNo, MesPcnExtConstWords.CUST_PART_NO, packBean);
                MesCustomerPart mesCustomerPart = mesCustomerPartRDao.getByProperty(packBean);
                if (mesCustomerPart == null) {
                    MesPcnException.throwMesBusiException("客户零件号[%s]信息不存在,请检查数据!", partNo);
                }
                partNo = mesCustomerPart.getErpPartNo();
            }
            if (StringUtils.isEmpty(partNo)) {
                MesPcnException.throwMesBusiException("客户零件号[%s]未绑定物料号数据,请检查数据!", split[packingDefine.getPartNoIndex() - 1]);
            }
        }
        return getPart(mesPackageDetail.getOrganizeCode(), partNo);
    }

    private MesPart getPart(String organizeCode, String partNo) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(partNo, MesPcnExtConstWords.PART_NO, packBean);
        MesPart mesPart = partRDao.getByProperty(packBean);
        if (Objects.isNull(mesPart)) {
            MesPcnException.throwMesBusiException("物料[%s]信息不存在,请检查数据!", partNo);
        }
        return mesPart;
    }

    private Double getQty(MesPackingDefine packingDefine, String[] split) {
        if (StringUtils.isEmpty(packingDefine.getQtyIndex()) || packingDefine.getQtyIndex() > split.length
                || StringUtils.isEmpty(split[packingDefine.getQtyIndex() - 1])) {
            MesPcnException.throwMesBusiException("数量所在位置不存在,请检查数据!");
        }
        //校验是否数字
        if (!CheckTool.isNumber(split[packingDefine.getQtyIndex() - 1])) {
            MesPcnException.throwMesBusiException("数量所在位置不为数字类型,请检查数据!");
        }
        return Double.parseDouble(split[packingDefine.getQtyIndex() - 1]);
    }

    private MesPackage getMesPackage(MesPackageDetail mesPackageDetail, MesPart mesPart, Double qty, MesPackingDefine packingDefine,String packageOneCode) {
        //保存包装信息
        MesPackage packages = new MesPackage();
        packages.setPackageNo(mesPackageDetail.getPackageNo());
        packages.setPartNo(mesPart.getPartNo());
        packages.setPartName(mesPart.getPartName());
        packages.setPackSpecQty(qty);
        packages.setQty(0d);
        packages.setIsSealed(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        packages.setPrintStatus(MesPcnEnumUtil.PACKAGE_PRINT_STATUS.UNPRINTED.getValue());
        packages.setPackageSn(packingDefine.getPackCode());
        packages.setPackageOneCode(packageOneCode);
        packages.setOrganizeCode(mesPackageDetail.getOrganizeCode());
        ConvertBean.serviceModelInitialize(packages, mesPackageDetail.getCreateUser());
        return packages;
    }

    private MesPackage getMesPackage(String organizeCode, String packageNo) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(packageNo, MesPcnExtConstWords.PACKAGE_NO, packBean);
        return mesPackageRDao.getByProperty(packBean);
    }

    private MesPackageSn getMesPackageSn(String organizeCode, String packageNo) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(packageNo, MesPcnExtConstWords.PACKAGE_NO, packBean);
        return mesPackageSnRDao.getByProperty(packBean);
    }

    private MesPackingDefine getMesPackingDefine(MesPackageDetail mesPackageDetail) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(mesPackageDetail.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(mesPackageDetail.getScanType(), MesPcnExtConstWords.SCAN_TYPE, packBean);
        MesPackingDefine packingDefine = mesPackingDefineRDao.getByProperty(packBean);
        if (Objects.isNull(packingDefine)) {
            MesPcnException.throwFlowException("客户条码规则在包装定义界面未维护,请检查数据!");
        }
        return packingDefine;
    }

    private void saveRedis(String isMemoryKey,Integer isMemory) {
        Object object = redisMesPcn.getObject(isMemoryKey);
        if(Objects.isNull(object) || !Objects.equals(isMemory, object)){
            redisMesPcn.putObject(isMemoryKey, isMemory,-1);
        }
    }

    private String getKey(String organizeCode, String userName) {
        return new StringJoiner(MesPcnExtConstWords.COLON).add(organizeCode).add(MesPcnExtConstWords.USER_INFO_CONTEXT).add(userName).add(MesPcnExtConstWords.BOXING_ERROR_PROOFING).add(MesPcnExtConstWords.IS_MEMORY).toString();
    }

}
