From 2c12487d2aff40f60a44c18fcab094f38185daf0 Mon Sep 17 00:00:00 2001 From: mzr Date: Sat, 11 Oct 2025 08:49:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E6=96=99=E8=AE=A1=E5=88=92api?= =?UTF-8?q?=E7=B1=BB=E5=90=8C=E6=AD=A5=E4=BB=A3=E7=A0=81-=E5=BC=A0?= =?UTF-8?q?=E6=98=8E&=E6=9D=8E=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mmpac/META-INF/pickmReources.rest | 5 + .../mmpac/pickm/PickmMaintainServiceImpl.java | 585 +++++++++++++++ .../mmpac/pickm/IPickmMaintainService.java | 103 +++ .../openapi/mmpac/pickm/PickmResouce.java | 702 ++++++++++++++++++ 4 files changed, 1395 insertions(+) create mode 100644 mmpac/META-INF/pickmReources.rest create mode 100644 mmpac/src/private/nc/impl/mmpac/pickm/PickmMaintainServiceImpl.java create mode 100644 mmpac/src/public/nc/itf/mmpac/pickm/IPickmMaintainService.java create mode 100644 mmpac/src/public/nccloud/openapi/mmpac/pickm/PickmResouce.java diff --git a/mmpac/META-INF/pickmReources.rest b/mmpac/META-INF/pickmReources.rest new file mode 100644 index 00000000..6c0e9bc9 --- /dev/null +++ b/mmpac/META-INF/pickmReources.rest @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mmpac/src/private/nc/impl/mmpac/pickm/PickmMaintainServiceImpl.java b/mmpac/src/private/nc/impl/mmpac/pickm/PickmMaintainServiceImpl.java new file mode 100644 index 00000000..24df4cb9 --- /dev/null +++ b/mmpac/src/private/nc/impl/mmpac/pickm/PickmMaintainServiceImpl.java @@ -0,0 +1,585 @@ +package nc.impl.mmpac.pickm; + +import java.util.*; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import nc.bs.dao.BaseDAO; +import nc.bs.framework.common.NCLocator; +import nc.bs.logging.Log; +import nc.bs.mmpac.pickm.bp.PickmApproveBP; +import nc.bs.mmpac.pickm.bp.PickmDeleteBP; +import nc.bs.mmpac.pickm.bp.PickmFinishBP; +import nc.bs.mmpac.pickm.bp.PickmInsertBP; +import nc.bs.mmpac.pickm.bp.PickmUnApproveBP; +import nc.bs.mmpac.pickm.bp.PickmUnFinishBP; +import nc.bs.mmpac.pickm.bp.PickmUpdateBP; +import nc.bs.uapbd.util.ThirdPartyPostRequestUtil; +import nc.impl.pubapp.pattern.data.vo.VOQuery; +import nc.itf.bd.material.baseinfo.IMaterialBaseInfoQueryService; +import nc.itf.mmpac.pickm.IPickmMaintainService; +import nc.itf.mmpac.pickm.IPickmTransTypeService; +import nc.jdbc.framework.processor.ColumnProcessor; +import nc.pubitf.para.SysInitQuery; +import nc.util.mmf.framework.base.MMValueCheck; +import nc.vo.bc.pmpub.project.ProjectHeadVO; +import nc.vo.bd.material.MaterialVO; +import nc.vo.cmp.util.StringUtils; +import nc.vo.mmpac.pickm.entity.AggPickmVO; +import nc.vo.mmpac.pickm.entity.PickmHeadVO; +import nc.vo.mmpac.pickm.entity.PickmItemVO; +import nc.vo.mmpac.pickm.entity.PickmTransTypeVO; +import nc.vo.mmpac.pmo.pac0002.entity.PMOItemVO; +import nc.vo.org.OrgVO; +import nc.vo.pub.BusinessException; +import nc.vo.pub.ISuperVO; +import nc.vo.pub.IVOMeta; +import nc.vo.pub.VOStatus; +import nc.vo.pub.lang.UFBoolean; +import nc.vo.pub.lang.UFDate; +import nc.vo.pub.lang.UFDouble; +import nc.vo.pubapp.pattern.exception.ExceptionUtils; +import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill; +import nc.vo.pubapp.pattern.model.meta.entity.bill.IBillMeta; +import nc.vo.pubapp.pattern.model.transfer.bill.ClientBillCombinServer; +import nc.vo.pubapp.pattern.pub.SqlBuilder; +import nc.vo.scmpub.util.ArrayUtil; +import nc.vo.scmpub.util.CollectionUtils; +import nc.vo.util.CloneUtil; +import nccloud.pubitf.mmpub.commit.service.IBatchRunScriptService; +import nccloud.pubitf.riart.pflow.CloudPFlowContext; + +/** + * 备料计划操作实现类 + */ +public class PickmMaintainServiceImpl implements IPickmMaintainService { + private static Log log = Log.getInstance("rzmomlog"); + + private static BaseDAO dao = new BaseDAO(); + /** + * 备料计划审核,分别有流程和离散重写 + */ + @Override + public AggPickmVO[] auditPickm(AggPickmVO[] vos) throws BusinessException { + // 审批操作 + PickmApproveBP auditbp = new PickmApproveBP(); + return auditbp.batchApprovePickm(vos); + } + + /** + * 删除备料计划 + */ + @Override + public void delete(AggPickmVO[] vos) throws BusinessException { + try { + // 删除操作 + PickmDeleteBP deleteBP = new PickmDeleteBP(); + deleteBP.delete(vos, false); + } catch (Exception e) { + ExceptionUtils.marsh(e); + } + } + + /** + * 备料计划完成,分别有流程离散重写 + */ + @Override + public AggPickmVO[] finishPickm(AggPickmVO[] vos) throws BusinessException { + // 完成操作 + PickmFinishBP finishbp = new PickmFinishBP(); + return finishbp.finish(vos); + } + + /** + * 新增备料计划 + */ + @Override + public AggPickmVO[] insert(AggPickmVO[] vos) throws BusinessException { + // vos = + // NCLocator.getInstance().lookup(IPickmMaintainService.class).insert_RequiresNew(vos); + // // 根据交易类型进行保存即审核规则 + // IRule pickmAutoApproveRule = new PickmAutoApproveAfterSaveRule(); + // pickmAutoApproveRule.process(vos); + try { + PickmInsertBP bp = new PickmInsertBP(); + return bp.insert(vos); + } catch (Exception e) { + ExceptionUtils.marsh(e); + } + return null; + } + + /** + * 备料计划弃审,分别由流程离散重写 + */ + @Override + public AggPickmVO[] unAuditPickm(AggPickmVO[] vos) throws BusinessException { + // 审批操作 + PickmUnApproveBP auditbp = new PickmUnApproveBP(); + return auditbp.batchUnApprovePickm(vos); + } + + /** + * 备料计划取消完成,分别有流程离散备料计划重写 + */ + @Override + public AggPickmVO[] unfinishPickm(AggPickmVO[] vos) throws BusinessException { + // 取消完成操作 + PickmUnFinishBP finishbp = new PickmUnFinishBP(); + return finishbp.unfinish(vos); + } + + /** + * 修改备料计划 + */ + @Override + public AggPickmVO[] update(AggPickmVO[] vos) throws BusinessException { + try { + // 更新操作 + PickmUpdateBP bp = new PickmUpdateBP(); + vos = bp.update(vos, false, false); + } catch (Exception e) { + ExceptionUtils.marsh(e); + } + return vos; + } + + /** + * 修改备料计划,同时更新预留 + */ + @Override + public AggPickmVO[] updateForYL(AggPickmVO[] vos) throws BusinessException { + try { + // 更新操作 + PickmUpdateBP bp = new PickmUpdateBP(true); + vos = bp.update(vos, true, false); + } catch (Exception e) { + ExceptionUtils.marsh(e); + } + return vos; + + } + + @Override + public AggPickmVO[] updateForYLForNcc(AggPickmVO[] vos) throws BusinessException { + try { + // 更新操作 + PickmUpdateBP bp = new PickmUpdateBP(true); + vos = bp.update(vos, true, false); + } catch (Exception e) { + ExceptionUtils.marsh(e); + } + return vos; + + } + + @Override + public AggPickmVO[] saveAndCommitPickm(AggPickmVO[] vos, UFBoolean isUpdate, UFBoolean isUpdateForYL) + throws BusinessException { + ClientBillCombinServer utils = new ClientBillCombinServer(); + PickmUpdateBP updateBP = new PickmUpdateBP(true); + Object[] objects = null; + if (MMValueCheck.isTrue(isUpdate)) { + if (MMValueCheck.isTrue(isUpdateForYL)) { + objects = updateBP.update(vos, true, false); + } else { + objects = updateBP.update(vos, false, false); + } + } else { + PickmInsertBP insertBP = new PickmInsertBP(); + objects = insertBP.insert(vos); + } + this.filterDeleteBodyData(vos); + utils.combine(vos, (AbstractBill[]) objects); + + UFBoolean autoAuditFlag = this.getBSaveToAuditByTransTypeID(vos[0].getParentVO().getVbusitypeid()); + if (MMValueCheck.isNotEmpty(vos)) { + if (autoAuditFlag.booleanValue()) {// 非保存即审核时执行提交 + return vos; + } + // 执行提交 + CloudPFlowContext context = new CloudPFlowContext(); + context.setBillType("55A3"); + context.setActionName("SAVE"); + context.setBillVos(vos); + IBatchRunScriptService service = NCLocator.getInstance().lookup(IBatchRunScriptService.class); + Object[] obj = service.run(context, AggPickmVO.class); + this.filterDeleteBodyData(vos); + utils.combine(vos, (AbstractBill[]) obj); + return vos; + } + return null; + } + + @Override + public AggPickmVO[] pushRZMes(AggPickmVO[] vos) throws BusinessException { + if (ArrayUtil.isEmpty(vos)) { + return null; + } + try { + AggPickmVO[] cloneOrderVOS = (AggPickmVO[]) CloneUtil.deepClone(vos); + // 检查并筛选领料组织 + List newAggPickmVOS = checkAndFilterBillSrcOrg(cloneOrderVOS); + if (newAggPickmVOS.isEmpty()) { + return vos; + } + Boolean is55A2OR30=checkSrcBillType(newAggPickmVOS); + if(is55A2OR30){ + //来源生产订单 + pushToRZMOMBy55A2(newAggPickmVOS.toArray(new AggPickmVO[0])); + }else{ + //来源委外订单 + pushToRZMOMBy61(newAggPickmVOS.toArray(new AggPickmVO[0])); + } + } catch (Exception e) { + ExceptionUtils.wrappException(e); + } + return vos; + } + + /** + * 过滤删除的行 TODO + * + * @param uiBillArrays + * + */ + private void filterDeleteBodyData(AbstractBill[] uiBillArrays) { + for (AbstractBill bill : uiBillArrays) { + // change by zhangshqb 改为支持一主多子的聚合VO + IBillMeta metaData = bill.getMetaData(); + IVOMeta[] children = metaData.getChildren(); + for (IVOMeta ivoMeta : children) { + List normal = new ArrayList(); + ISuperVO[] childs = bill.getChildren(ivoMeta); + if (childs != null && childs.length > 0) { + for (ISuperVO child : childs) { + if (child.getStatus() != VOStatus.DELETED) { + normal.add(child); + } + } + bill.setChildren(ivoMeta, CollectionUtils.listToArray(normal)); + } + } + } + } + + private UFBoolean getBSaveToAuditByTransTypeID(String vbusitypeid) { + + IPickmTransTypeService service = NCLocator.getInstance().lookup(IPickmTransTypeService.class); + try { + PickmTransTypeVO typevo = service.queryTransTypeVO(vbusitypeid); + if (MMValueCheck.isEmpty(typevo)) { + return UFBoolean.FALSE; + } + return typevo.getBautoaduitaftersave() == null ? UFBoolean.FALSE : typevo.getBautoaduitaftersave(); + + } catch (BusinessException e) { + ExceptionUtils.wrappException(e); + } + return UFBoolean.FALSE; + } + + private Boolean checkSrcBillType(List newAggPickmVOS) throws BusinessException { + UFBoolean is61=UFBoolean.FALSE; + UFBoolean is55A2OR30=UFBoolean.FALSE; + for (AggPickmVO aggPickmVO : newAggPickmVOS) { + String vfirstbilltype = aggPickmVO.getParentVO().getVfirstbilltype(); + if("61".equals(vfirstbilltype)){ + is61=UFBoolean.TRUE; + }else if("55A2".equals(vfirstbilltype)){ + is55A2OR30=UFBoolean.TRUE; + }else if("30".equals(vfirstbilltype)){ + is55A2OR30=UFBoolean.TRUE; + } + } + if(is55A2OR30.booleanValue()&&is61.booleanValue()){ + throw new BusinessException("备料计划推送锐制失败,原因:不允许源头单据类型为生产订单和委外订单的单据同时审批"); + } + return is55A2OR30.booleanValue(); + } + private void buildSyncDataBy55A2(PickmHeadVO head, PickmItemVO[] bodys, JSONArray details) throws BusinessException { + Integer fsourcetype = head.getFsourcetype(); + if(fsourcetype!=0){ + return; + } + //2025年8月12日08点55分--新增生产订单项目字段信息 + String csourcebillrowid = head.getCsourcebillrowid(); + PMOItemVO[] srcBVOs = new VOQuery(PMOItemVO.class).query(new String[]{csourcebillrowid}); + ProjectHeadVO[] cprojectVOs=null; + if(srcBVOs!=null&&srcBVOs.length>0){ + String cprojectid = srcBVOs[0].getCprojectid(); + if(!StringUtils.isEmpty(cprojectid)){ + cprojectVOs= new VOQuery(ProjectHeadVO.class).query(new String[]{cprojectid}); + } + } + //end + for (PickmItemVO body : bodys) { + JSONObject singleObj = new JSONObject(); + String vsourcebillcode = head.getVsourcebillcode(); + String wlbm_wbid =body.getCbmaterialvid(); + String scgx_wbid =head.getVstdprocid(); + //wbid varchar (200) 第三方系统主键id + singleObj.put("wbid", head.getCpickmid()+"_"+body.getCpickm_bid()); // 第三方系统主键id + //operate int 操作状态 必填 1新增/修改、2删除(删除时只需上传wbid) + singleObj.put("operate", "1"); + //wbzbid varchar (200) 第三方系统分组id + singleObj.put("wbzbid", head.getCpickmid()); + + //wbqjpx varchar(2000) 全局排序 必填 BOM表物料行号 + singleObj.put("wbqjpx", body.getVrowno()); + + //scjh_wbid varchar(100) 第三方系统生产计划ID 必填 生产计划号外部ID,一般ERP系统的生产订单号。 + singleObj.put("scjh_wbid", head.getCsourcebillid()); + + + //jhxh numeric(5) 计划序号 -生产订单行号 + singleObj.put("jhxh", head.getVsourcebillrowno()); + + singleObj.put("wlbm_wbid", wlbm_wbid); // 第三方系统材料id + + //bomlx int BOM类型 必填 默认=0,即传入生产BOM(1为包装BOM)。 + singleObj.put("bomlx", 0); + if(body.getNunituseastnum()==null ){ + singleObj.put("dwyl", UFDouble.ZERO_DBL.getDouble()); // 单位用量nunituseastnum + singleObj.put("djyl", UFDouble.ZERO_DBL.getDouble()); // 单据用量nunituseastnum + }else{ + singleObj.put("dwyl", body.getNunituseastnum().getDouble()); // 单位用量nunituseastnum + singleObj.put("djyl", body.getNunituseastnum().getDouble()); // 单据用量nunituseastnum + } + + singleObj.put("clyl", body.getNplanoutastnum().getDouble()); // 材料用量 + +// String rccode = transferCodeByPk(RcVO.getDefaultTableName(), RcVO.VRCCODE, RcVO.CRCID, head.getVstdprocid()); + singleObj.put("scgx_wbid", body.getVbdef11()); +// singleObj.put("scgx_wbid", rccode); // 第三方系统使用工序id + + //sdbj int 锁定标记 必填 默认1:正常业务ERP审核后,传输至锐制MOM + singleObj.put("sdbj", 1); + //shbj int 审核标记 必填 默认1:正常业务ERP审核后,传输至锐制MOM + singleObj.put("shbj", 1); + + //jylxbm -- + singleObj.put("jylxbm", head.getVbusitype()); + + //2025年8月12日08点55分--新增生产订单项目字段信息 start + if(cprojectVOs!=null && cprojectVOs.length>0){ + singleObj.put("wlzdycs06", cprojectVOs[0].getProject_code()); + singleObj.put("wlzdycs11", cprojectVOs[0].getProject_name()); + } + //2025年8月12日08点55分--新增生产订单项目字段信息 end + + //2025年9月1日15点14分--新增需用日期字段 -start + UFDate drequiredate = body.getDrequiredate(); + singleObj.put("wlzdycs19", drequiredate==null?null:drequiredate.toStdString()); + //2025年9月1日15点14分--新增需用日期字段 -end + + details.add(singleObj); + + } + } + private void buildSyncDataBy61(PickmHeadVO head, PickmItemVO[] bodys, JSONArray details) throws BusinessException { + Integer fsourcetype = head.getFsourcetype(); + if(fsourcetype!=1){ + return; + } + for (PickmItemVO body : bodys) { + JSONObject singleObj = new JSONObject(); + String vsourcebillcode = head.getVsourcebillcode(); + String wlbm_wbid =body.getCbmaterialvid(); + + String scgx_wbid =head.getVstdprocid(); + //wbid varchar (200) 第三方系统主键id + singleObj.put("wbid", head.getCpickmid()+"_"+body.getCpickm_bid()); // 第三方系统主键id + //wbzbid varchar (200) 第三方系统分组id + singleObj.put("wbpid", head.getCpickmid()); + //operate int 操作状态 必填 1新增/修改、2删除(删除时只需上传wbid) + singleObj.put("operate", "1"); + //djly varchar(20) 来源单据 必填 取值read_djlyb中编号 + //领料通知默认1011 + singleObj.put("djly", "1011"); + + //_id varchar(50) 单据id 必填 后台该单据类型的唯一ID + singleObj.put("djbh_id", head.getCpickmid()); + + //djbh varchar(100) 单据编号 必填 前台单据编号 + singleObj.put("djbh", head.getVbillcode()); + + //djxh numeric(5) 单据序号 必填 前台单据序号 + singleObj.put("djxh", body.getVrowno()); + + //djrq datetime 单据日期 必填 + singleObj.put("djrq", head.getDmakedate().toString()); + + //wlbm_wbid varchar(100) 第三方系统物料名称id 必填 物料编码的后台ID + singleObj.put("wlbm_wbid", wlbm_wbid); + + //djsl numeric(18,3) 单据数量 必填 + UFDouble djsl = body.getNplanoutastnum() == null ? UFDouble.ZERO_DBL : body.getNplanoutastnum(); + singleObj.put("djsl", djsl.getDouble()); + + //sddd varchar(510)送达地点 必填 传仓库名称,要求上位ERP仓库名称不重复。 +// singleObj.put("sddd", transferCodeByPk(StordocVO.getDefaultTableName(), StordocVO.NAME, StordocVO.PK_STORDOC, body.getCoutstockid())); + + //ckbh_wbid varchar(100) 第三方系统仓库id 必填 储区根据仓库默认,同仓库多储区时,两者必填; +// singleObj.put("ckbh_wbid",body.getCoutstockid()); + + //qfbj int 签发标记 必填 默认1;上位系统审核传至MOM 1 + singleObj.put("qfbj", 1); + + //cght_wbid varchar(100) 第三方系统合同id 必填 委外订单主键ID + singleObj.put("cght_wbid",head.getCfirstbillid()); + //htbh varchar(100) 合同号 委外订单单据号 + singleObj.put("htbh",head.getVfirstbillcode()); + + //htxh numeric(5) 合同序号 委外订单单据序号 + singleObj.put("htxh",head.getVfirstbillrowno()); + + //cght_wbid varchar(100) 第三方系统合同id 必填 +// singleObj.put("cght_wbid", transferCodeByPk("bd_defdoc", DefdocVO.CODE, DefdocVO.PK_DEFDOC, body.getVbdef5())); + details.add(singleObj); + + } + } + + private List checkAndFilterBillSrcOrg(AggPickmVO[] aggPickmVOS) throws BusinessException { + List aggvoList = new ArrayList<>(); + List finalList = new ArrayList<>(); + + for (AggPickmVO aggvo : aggPickmVOS) { + String pkOrg = aggvo.getParentVO().getPk_org(); + String orgCode = transferCodeByPk(OrgVO.getDefaultTableName(), OrgVO.CODE, OrgVO.PK_ORG, pkOrg); + //过滤上游不是生产订单和委外订单的备料计划 + String vfirstbilltype = aggvo.getParentVO().getVfirstbilltype(); + String vdef20 = aggvo.getParentVO().getVdef20(); + if(vdef20==null||"N".equals(vdef20)){ + if ("C022".equals(orgCode)&& 1 == aggvo.getParentVO().getFbillstatus()&&aggvo.getChildrenVO()!=null && aggvo.getChildrenVO().length > 0) { + if("61".equals(vfirstbilltype)||"55A2".equals(vfirstbilltype)||"30".equals(vfirstbilltype)){ + //2025年7月2日10点33分--新增不传--表体物料编码前三位为103时不传 + //获取表体物料信息 + aggvoList.add(aggvo); + } + } + } + + } + //再次筛选 + //2025年7月2日10点33分--新增不传--表体物料编码前三位为103时不传 + //获取表体物料信息 + if(aggvoList.isEmpty()){ + return aggvoList; + } + Set materialpks=new HashSet<>(); + for (AggPickmVO aggvo : aggvoList) { + PickmItemVO[] items = (PickmItemVO[]) aggvo.getChildren(PickmItemVO.class); + for (PickmItemVO item : items) { + String cbmaterialvid = item.getCbmaterialvid(); + materialpks.add(cbmaterialvid); + } + } + if(materialpks.isEmpty()){ + return aggvoList; + } + //根据物料id查询物料信息 + MaterialVO[] vos = NCLocator.getInstance().lookup(IMaterialBaseInfoQueryService.class).queryDataByPks(materialpks.toArray(new String[0])); + //组装Map + Map materialMap = new HashMap<>(); + if(vos==null || vos.length<1){ + throw new BusinessException("Failed to query material info , please check !!!"); + } + for (MaterialVO vo : vos) { + String cmaterialvid = vo.getPk_material(); + String cmaterialcode =vo.getCode(); + materialMap.put(cmaterialvid, cmaterialcode); + } + //筛选行数据 + for (AggPickmVO aggvo : aggvoList) { + List newItems = new ArrayList<>(); + PickmItemVO[] items = (PickmItemVO[]) aggvo.getChildren(PickmItemVO.class); + for (PickmItemVO item : items) { + String cmaterialvid = item.getCbmaterialvid(); + if (materialMap.containsKey(cmaterialvid)) { + String materialCode = materialMap.get(cmaterialvid); + if(!materialCode.startsWith("103")){ + newItems.add(item); + } + } + } + if (!newItems.isEmpty()) { + aggvo.setChildren(PickmItemVO.class,newItems.toArray(new PickmItemVO[0])); + finalList.add(aggvo); + } + } + return finalList; + } + + private void pushToRZMOMBy55A2(AggPickmVO[] aggPickmVOS) throws BusinessException { + String rzwmsip = SysInitQuery.getParaString("GLOBLE00000000000000", "RZWMSIP"); + JSONObject jsonObject = new JSONObject(); + JSONObject dataIn = new JSONObject(); + JSONObject dataIn2 = new JSONObject(); + JSONArray details = new JSONArray(); + jsonObject.put("dataflow", "用友BIP→RZMOMv6"); + jsonObject.put("actionCode", "scbomb"); + + for (AggPickmVO aggPickmVO : aggPickmVOS) { + PickmHeadVO head = aggPickmVO.getParentVO(); + PickmItemVO[] bodys = (PickmItemVO[]) aggPickmVO.getChildrenVO(); + buildSyncDataBy55A2(head, bodys, details); + } + dataIn2.put("Details", details); + dataIn.put("Data", dataIn2); + jsonObject.put("data", dataIn); + log.error("生产BOW推送锐制请求报文:" + jsonObject.toJSONString()); + String result = ThirdPartyPostRequestUtil.sendPostRequest(rzwmsip, jsonObject.toJSONString()); + JSONObject resultObj = JSONObject.parseObject(result); + if (resultObj == null || !"true".equals(resultObj.getString("success"))) { + String errorMsg = resultObj == null ? "接口返回为空" : resultObj.getString("msg"); + throw new BusinessException("RZ同步失败,原因:" + errorMsg); + }else{ + log.error("RZMOM同步成功,返回参数【"+resultObj.toJSONString()+"】"); + } + } + private void pushToRZMOMBy61(AggPickmVO[] aggPickmVOS) throws BusinessException { + String rzwmsip = SysInitQuery.getParaString("GLOBLE00000000000000", "RZWMSIP"); + JSONObject jsonObject = new JSONObject(); + JSONObject dataIn = new JSONObject(); + JSONObject dataIn2 = new JSONObject(); + JSONArray details = new JSONArray(); + jsonObject.put("dataflow", "用友BIP→RZMOMv6"); + jsonObject.put("actionCode", "wwfhtzdb"); + + for (AggPickmVO aggPickmVO : aggPickmVOS) { + PickmHeadVO head = aggPickmVO.getParentVO(); + PickmItemVO[] bodys = (PickmItemVO[]) aggPickmVO.getChildrenVO(); + buildSyncDataBy61(head, bodys, details); + } + dataIn2.put("Details", details); + dataIn.put("Data", dataIn2); + jsonObject.put("data", dataIn); + log.error("生产BOW推送锐制请求报文:" + jsonObject.toJSONString()); + String result = ThirdPartyPostRequestUtil.sendPostRequest(rzwmsip, jsonObject.toJSONString()); + JSONObject resultObj = JSONObject.parseObject(result); + if (resultObj == null || !"true".equals(resultObj.getString("success"))) { + String errorMsg = resultObj == null ? "接口返回为空" : resultObj.getString("msg"); + throw new BusinessException("RZ同步失败,原因:" + errorMsg); + }else{ + log.error("RZMOM同步成功,返回参数【"+resultObj.toJSONString()+"】"); + } + } + private String transferCodeByPk(String tableName, String selectField, String pkField, String pk) throws BusinessException { + if (StringUtils.isEmpty(pk)) { + return null; + } + SqlBuilder sqlBuilder = new SqlBuilder(); + sqlBuilder.append(" select " + selectField); + sqlBuilder.append(" from " + tableName); + sqlBuilder.append(" where "); + sqlBuilder.append(pkField, pk); + Object o = dao.executeQuery(sqlBuilder.toString(), new ColumnProcessor()); + if (o == null) { + throw new BusinessException("未查询到编码信息,sql【" + sqlBuilder + "】"); + } + return o.toString(); + } + +} diff --git a/mmpac/src/public/nc/itf/mmpac/pickm/IPickmMaintainService.java b/mmpac/src/public/nc/itf/mmpac/pickm/IPickmMaintainService.java new file mode 100644 index 00000000..f89fb799 --- /dev/null +++ b/mmpac/src/public/nc/itf/mmpac/pickm/IPickmMaintainService.java @@ -0,0 +1,103 @@ +package nc.itf.mmpac.pickm; + +import nc.vo.mmpac.pickm.entity.AggPickmVO; +import nc.vo.pub.BusinessException; +import nc.vo.pub.lang.UFBoolean; + +/** + * 标准单据业务操作接口,增删改查 + * + * @since 6.0 + * @version 2010-12-16 下午04:36:00 + * @author + */ +public interface IPickmMaintainService { + + /** + * 删除备料计划单据 + * + * @param AggPickmVO + * @throws BusinessException + */ + void delete(AggPickmVO[] vos) throws BusinessException; + + /** + * 新增备料计划单据 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] insert(AggPickmVO[] vos) throws BusinessException; + + /** + * 更新备料计划单据 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] update(AggPickmVO[] vos) throws BusinessException; + + /** + * 为预留更新单据 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] updateForYL(AggPickmVO[] vos) throws BusinessException; + AggPickmVO[] updateForYLForNcc(AggPickmVO[] vos) throws BusinessException; + + /** + * 备料计划审核 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] auditPickm(AggPickmVO[] vos) throws BusinessException; + + /** + * 备料计划取消审核 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] unAuditPickm(AggPickmVO[] vos) throws BusinessException; + + /** + * 备料计划完成 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] finishPickm(AggPickmVO[] vos) throws BusinessException; + + /** + * 备料计划取消完成 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] unfinishPickm(AggPickmVO[] vos) throws BusinessException; + /** + * 备料计划保存提交 + * + * @param AggPickmVO + * @return AggPickmVO + * @throws BusinessException + */ + AggPickmVO[] saveAndCommitPickm(AggPickmVO[] vos,UFBoolean isUpdate,UFBoolean isUpdateForYL) throws BusinessException; + + /** + * 推送RZMES + * @param vos + * @return + * @throws BusinessException + */ + AggPickmVO[] pushRZMes(AggPickmVO[] vos) throws BusinessException; +} diff --git a/mmpac/src/public/nccloud/openapi/mmpac/pickm/PickmResouce.java b/mmpac/src/public/nccloud/openapi/mmpac/pickm/PickmResouce.java new file mode 100644 index 00000000..2d428865 --- /dev/null +++ b/mmpac/src/public/nccloud/openapi/mmpac/pickm/PickmResouce.java @@ -0,0 +1,702 @@ +package nccloud.openapi.mmpac.pickm; + +import java.util.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +import nc.bs.dao.BaseDAO; +import nc.bs.framework.common.NCLocator; +import nc.bs.logging.Log; +import nc.bs.scmpub.query.SCMBillQuery; +import nc.itf.mmpac.pickm.IPickmMaintainService; +import nc.jdbc.framework.processor.BeanListProcessor; +import nc.jdbc.framework.processor.ColumnProcessor; +import nc.jdbc.framework.processor.MapListProcessor; +import nc.util.mmf.framework.base.MMCollectionUtil; +import nc.vo.bd.bom.bom0202.entity.AggBomVO; +import nc.vo.bd.bom.bom0202.entity.BomItemVO; +import nc.vo.bd.bom.bom0202.entity.BomVO; +import nc.vo.bd.material.MaterialVO; +import nc.vo.bd.material.measdoc.MeasdocVO; +import nc.vo.bd.psn.PsndocVO; +import nc.vo.mmpac.pickm.entity.AggPickmVO; +import nc.vo.mmpac.pickm.entity.PickmHeadVO; +import nc.vo.mmpac.pickm.entity.PickmItemVO; +import nc.vo.mmpac.pmo.pac0002.entity.PMOHeadVO; +import nc.vo.mmpac.pmo.pac0002.entity.PMOItemVO; +import nc.vo.org.GroupVO; +import nc.vo.org.OrgVO; +import nc.vo.org.StockOrgVO; +import nc.vo.pub.*; +import nc.vo.pub.lang.UFBoolean; +import nc.vo.pubapp.AppContext; +import nc.vo.pubapp.pattern.pub.SqlBuilder; +import nc.vo.vorg.StockOrgVersionVO; +import nc.ws.opm.pub.utils.result.APIErrCodeEnum; +import nccloud.api.rest.utils.ResultMessageUtil; + +import nccloud.ws.rest.resource.AbstractNCCRestResource; +import org.json.JSONString; + +@Path("mmpac/pickm") +public class PickmResouce extends AbstractNCCRestResource { + private static String HEADTABLE = "mm_pickm"; + private static String BODYTABLE = "mm_pickm_b"; + private static final BaseDAO BASE_DAO = new BaseDAO(); + private static final Log logger = Log.getInstance("pmoresouceLogger"); + + private static Map entityNameToClassName = new HashMap(); + + public PickmResouce() { + } + + + /** + * 备料计划 新增修改删除三个接口 openapi , 提供给mes, + * 备料计划是审批后的, 传递的是流程生产订单明细行主键, + * 操作的是流程备料计划的明细行,新增修改删除是针对于明细行来说的 + * 根据流程生产订单明细行的主键 可以查询到流程备料计划的AggVO,然后操作他的明细 + */ + @POST + @Path("save") + @Consumes({"application/json"}) + @Produces({"application/json"}) + public JSONString save(Map paramMap) { + logger.debug("开始进行备料计划明细行的新增操作"); + // 如果没有传递data属性 + if (!paramMap.containsKey("data")) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + try { + List> batchData = (List) paramMap.get("data"); + IPickmMaintainService serv = (IPickmMaintainService) NCLocator.getInstance().lookup(IPickmMaintainService.class); + // 如果没有数据 + if (MMCollectionUtil.isEmpty(batchData)) { + logger.info("传入数据异常,参数要包含data"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + List resAggVOS = new ArrayList<>(); + // 批量处理每一个主子表对象 + for (Map singleData : batchData) { + if (!singleData.containsKey("pk_pmo")) { + logger.info("传入数据异常,参数要包含pk_pmo"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含pk_pmo", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + String pk_pmo = (String) singleData.get("pk_pmo"); + // 查询表头 + String searchHeadSql = "SELECT * FROM mm_pickm WHERE nvl(dr,0) = 0 AND vsourcemocode = '" + pk_pmo + "'"; + List> pickmHeadRows = (List>) BASE_DAO.executeQuery(searchHeadSql, new MapListProcessor()); + if (pickmHeadRows == null) { + logger.info("根据pk_pmo查询的流程备料计划不存在"); + return ResultMessageUtil.exceptionToJSON("根据pk_pmo查询的流程备料计划不存在", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + PickmHeadVO pickmHeadVO = transferToPickmHeadVO(pickmHeadRows.get(0), VOStatus.UPDATED); + if (!singleData.containsKey("mm_pickm_b")) { + logger.info("传入数据异常,参数要包含mm_pickm_b"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含mm_pickm_b", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + List> batchPickms = (List>) singleData.get("mm_pickm_b"); + + // 循环请求体中每一个备料计划明细 + List finalPickmItemVOS = null; + for (Map singlePickm : batchPickms) { + // 需要将singleData中的每一个code转为主键重新存储 + Map newMap = transferSingleDataCodeToPk(singlePickm); + PickmItemVO pickmItemVO = transferToPickmItemVO(newMap, VOStatus.NEW); + // 查询表体 + String searchBodySql = "SELECT * FROM mm_pickm_b WHERE nvl(dr,0) = 0 AND cpickmid = '" + pickmHeadVO.getCpickmid() + "'"; + List existingPickmItemVOS = (List) BASE_DAO.executeQuery(searchBodySql, new BeanListProcessor(PickmItemVO.class)); + if (existingPickmItemVOS == null) { + logger.info("根据pk_pmo查询的流程备料计划明细不存在"); + return ResultMessageUtil.exceptionToJSON("根据pk_pmo查询的流程备料计划明细不存在", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + // 如果已存在的不为空 + finalPickmItemVOS = new ArrayList<>(existingPickmItemVOS); + // 如果新增加的不为空 + finalPickmItemVOS.add(pickmItemVO); + } + if (finalPickmItemVOS == null) { + logger.info("数据异常 处理后备料计划明细为空"); + return ResultMessageUtil.exceptionToJSON("数据异常 处理后备料计划明细为空", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + // 转换为AggVO + PickmItemVO[] array = (PickmItemVO[]) finalPickmItemVOS.toArray(new PickmItemVO[0]); + AggPickmVO aggPickmVO = new AggPickmVO(); + aggPickmVO.setParent(pickmHeadVO); + aggPickmVO.setChildren(PickmItemVO.class, array); + aggPickmVO.getParentVO().setStatus(VOStatus.UPDATED); + this.setDefaultValue(aggPickmVO); + resAggVOS.add(aggPickmVO); + } + // 更新 + AggPickmVO[] updatedAggVOS = (AggPickmVO[]) resAggVOS.toArray(new AggPickmVO[0]); + AggPickmVO[] insertBills = serv.update(updatedAggVOS); + logger.info("备料计划明细行新增成功"); + return ResultMessageUtil.toJSON(insertBills, "备料计划明细行新增成功"); + } catch (Exception e) { + logger.error("备料计划明细行新增异常", e); + return ResultMessageUtil.exceptionToJSON(e); + } + } + + @POST + @Path("update") + @Consumes({"application/json"}) + @Produces({"application/json"}) + public JSONString update(Map paramMap) { + logger.debug("开始进行备料计划明细行的修改操作"); + // 如果没有传递data属性 + if (!paramMap.containsKey("data")) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + try { + List> batchData = (List) paramMap.get("data"); + IPickmMaintainService serv = (IPickmMaintainService) NCLocator.getInstance().lookup(IPickmMaintainService.class); + // 如果没有数据 + if (MMCollectionUtil.isEmpty(batchData)) { + logger.info("传入数据异常,参数要包含data"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + List resAggVOS = new ArrayList<>(); + // 批量处理每一个主子表对象 + for (Map singleData : batchData) { + if (!singleData.containsKey("pk_pmo")) { + logger.info("传入数据异常,参数要包含pk_pmo"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含pk_pmo", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + // 根据流程生产订单明细 + String pk_pmo = (String) singleData.get("pk_pmo"); + PMOItemVO pmoItemVO = (PMOItemVO) BASE_DAO.retrieveByPK(PMOItemVO.class, pk_pmo); + if (pmoItemVO == null) { + logger.info("根据pk_pmo查询的流程生产订单明细行不存在"); + return ResultMessageUtil.exceptionToJSON("根据pk_pmo查询的流程生产订单明细行不存在", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + List pickmHeadVOS = (List) BASE_DAO.retrieveByClause(PickmHeadVO.class, PickmHeadVO.VSOURCEMOROWID + " = '" + pk_pmo + "'"); + if (pickmHeadVOS == null || pickmHeadVOS.isEmpty()) { + logger.info("根据流程生产订单明细主键查询备料计划失败"); + return ResultMessageUtil.exceptionToJSON("根据流程生产订单明细主键查询备料计划失败", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + PickmHeadVO pickmHeadVO = pickmHeadVOS.get(0); + if (!singleData.containsKey("mm_pickm_b")) { + logger.info("传入数据异常,参数要包含mm_pickm_b"); + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含mm_pickm_b", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 拿到每一个明细 进行修改 + List> batchPickms = (List>) singleData.get("mm_pickm_b"); + + // 先将物料编码相同的明细进行分组 + Map>> materialGroups = new HashMap<>(); + for (Map singlePicm : batchPickms) { + String cbmaterialvid = (String) singlePicm.get("cbmaterialvid"); + if (cbmaterialvid == null) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,流程备料计划明细行中参数要包含cbmaterialvid", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + materialGroups.computeIfAbsent(cbmaterialvid, k -> new ArrayList<>()).add(singlePicm); + } + + // 查询该备料计划下的所有明细 + String searchBodySql = "SELECT * FROM mm_pickm_b WHERE nvl(dr,0) = 0 AND cpickmid = '" + pickmHeadVO.getCpickmid() + "'"; + List existingPickmItemVOS = (List) BASE_DAO.executeQuery(searchBodySql, new BeanListProcessor(PickmItemVO.class)); + if (existingPickmItemVOS == null || existingPickmItemVOS.isEmpty()) { + logger.info("根据备料计划主键查询的流程备料计划明细不存在"); + return ResultMessageUtil.exceptionToJSON("根据备料计划主键查询的流程备料计划明细不存在", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + List finalPickmItemVOS = new ArrayList<>(); + + // 处理每个物料组 + for (Map.Entry>> entry : materialGroups.entrySet()) { + String materialCode = entry.getKey(); + List> materialItems = entry.getValue(); + + // 将物料编码转换为主键 + String materialPk = transferPkByCode(MaterialVO.getDefaultTableName(), MaterialVO.PK_MATERIAL, MaterialVO.CODE, materialCode); + + // 查询该物料对应的所有备料计划明细 + List materialPickmItems = new ArrayList<>(); + for (PickmItemVO item : existingPickmItemVOS) { + if (materialPk.equals(item.getCbmaterialvid())) { + materialPickmItems.add(item); + } + } + + if (materialPickmItems.isEmpty()) { + logger.info("未找到物料编码 " + materialCode + " 对应的备料计划明细"); + return ResultMessageUtil.exceptionToJSON("未找到物料编码 " + materialCode + " 对应的备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 判断是否有重复物料(同一物料编码但isvirtual不同) + if (materialItems.size() == 1) { + // 无重复,直接更新 + Map singlePicm = materialItems.get(0); + Map newSinglePicm = transferSingleDataCodeToPk(singlePicm); + PickmItemVO pickmItemVO = transferToPickmItemVO(newSinglePicm, VOStatus.UPDATED); + + // 直接取第一个匹配的明细进行更新 + PickmItemVO existingPickmItemVO = materialPickmItems.get(0); + for (String attributeName : pickmItemVO.getAttributeNames()) { + if (pickmItemVO.getAttributeValue(attributeName) != null) { + existingPickmItemVO.setAttributeValue(attributeName, pickmItemVO.getAttributeValue(attributeName)); + } + } + finalPickmItemVOS.add(existingPickmItemVO); + + } else if (materialItems.size() == 2) { + // 有重复,需要通过BOM逻辑进行匹配 + // 先查询BOM信息 + String bomSql = "cbmaterialvid = '" + pmoItemVO.getCmaterialvid() + "' and vbbomversionnumber = '" + pmoItemVO.getVbomversion() + "'"; + BomVO bomHeadVO = (BomVO) BASE_DAO.retrieveByClause(BomVO.class, bomSql); + if (bomHeadVO == null) { + logger.info("未找到对应的BOM信息"); + return ResultMessageUtil.exceptionToJSON("未找到对应的BOM信息", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + String bombSql = BomVO.CBOMID + " = '" + bomHeadVO.getCbomid() + "'"; + List bomItemVOS = (List) BASE_DAO.retrieveByClause(BomItemVO.class, bombSql); + + // 分离实项和虚项 + Map realItem = null; + Map virtualItem = null; + + for (Map item : materialItems) { + String isVirtual = (String) item.get("isvirtual"); + if (isVirtual == null || (!isVirtual.equals("Y") && !isVirtual.equals("N"))) { + return ResultMessageUtil.exceptionToJSON("isvirtual参数错误,必须为Y或者N", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + if ("N".equals(isVirtual)) { + realItem = item; + } else { + virtualItem = item; + } + } + + if (realItem == null || virtualItem == null) { + return ResultMessageUtil.exceptionToJSON("重复物料组中必须包含一个实项(isvirtual=N)和一个虚项(isvirtual=Y)", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 处理实项 - 通过BOM查找对应的备料计划明细 + Map newRealItem = transferSingleDataCodeToPk(realItem); + PickmItemVO realPickmItemVO = transferToPickmItemVO(newRealItem, VOStatus.UPDATED); + + PickmItemVO realExistingItem = null; + + // 先检查BOM表头 + String hcmaterialvid = bomHeadVO.getHcmaterialvid(); + UFBoolean hisvirtual = bomHeadVO.getHisvirtual(); + if (hcmaterialvid != null && hisvirtual != null && + hcmaterialvid.equals(realPickmItemVO.getCbmaterialvid()) && !hisvirtual.booleanValue()) { + for (PickmItemVO item : materialPickmItems) { + if (bomHeadVO.getCbomid().equals(item.getCbombid())) { + realExistingItem = item; + break; + } + } + } + + // 如果表头没找到,查找BOM明细 + if (realExistingItem == null) { + for (BomItemVO bomItemVO : bomItemVOS) { + if (bomItemVO != null) { + String cmaterialvid = bomItemVO.getCmaterialvid(); + UFBoolean bisvirtual = bomItemVO.getBisvirtual(); + if (cmaterialvid != null && bisvirtual != null && + cmaterialvid.equals(realPickmItemVO.getCbmaterialvid()) && !bisvirtual.booleanValue()) { + for (PickmItemVO item : materialPickmItems) { + if (bomItemVO.getCbom_bid().equals(item.getCbombid())) { + realExistingItem = item; + break; + } + } + if (realExistingItem != null) break; + } + } + } + } + + if (realExistingItem == null) { + logger.error("未找到实项对应的备料计划明细"); + return ResultMessageUtil.exceptionToJSON("未找到实项对应的备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 更新实项 + for (String attributeName : realPickmItemVO.getAttributeNames()) { + if (realPickmItemVO.getAttributeValue(attributeName) != null) { + realExistingItem.setAttributeValue(attributeName, realPickmItemVO.getAttributeValue(attributeName)); + } + } + finalPickmItemVOS.add(realExistingItem); + + // 处理虚项 - 排除法找到另一个明细 + PickmItemVO virtualExistingItem = null; + for (PickmItemVO item : materialPickmItems) { + if (!item.equals(realExistingItem)) { + virtualExistingItem = item; + break; + } + } + + if (virtualExistingItem == null) { + logger.error("未找到虚项对应的备料计划明细"); + return ResultMessageUtil.exceptionToJSON("未找到虚项对应的备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 更新虚项 + Map newVirtualItem = transferSingleDataCodeToPk(virtualItem); + PickmItemVO virtualPickmItemVO = transferToPickmItemVO(newVirtualItem, VOStatus.UPDATED); + + for (String attributeName : virtualPickmItemVO.getAttributeNames()) { + if (virtualPickmItemVO.getAttributeValue(attributeName) != null) { + virtualExistingItem.setAttributeValue(attributeName, virtualPickmItemVO.getAttributeValue(attributeName)); + } + } + finalPickmItemVOS.add(virtualExistingItem); + + } else { + return ResultMessageUtil.exceptionToJSON("同一物料编码最多只能有2个明细(一个实项一个虚项)", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + } + + PickmItemVO[] array = finalPickmItemVOS.toArray(new PickmItemVO[0]); + AggPickmVO aggPickmVO = new AggPickmVO(); + aggPickmVO.setParent(pickmHeadVO); + aggPickmVO.setChildren(PickmItemVO.class, array); + aggPickmVO.getParentVO().setStatus(VOStatus.UPDATED); + this.setDefaultValue(aggPickmVO); + resAggVOS.add(aggPickmVO); + } + // 更新 + AggPickmVO[] updatedAggVOS = resAggVOS.toArray(new AggPickmVO[0]); + AggPickmVO[] updateBills = serv.update(updatedAggVOS); + logger.info("备料计划明细行修改成功"); + return ResultMessageUtil.toJSON(updateBills, "备料计划明细行修改成功"); + } catch (Exception e) { + logger.error("备料计划明细行修改异常", e); + return ResultMessageUtil.exceptionToJSON(e); + } + } + + @POST + @Path("delete") + @Consumes({"application/json"}) + @Produces({"application/json"}) + public JSONString delete(Map paramMap) { + logger.debug("开始进行备料计划明细行的删除操作"); + // 如果没有传递data属性 + if (!paramMap.containsKey("data")) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + try { + List> paramList = (List) paramMap.get("data"); + if (MMCollectionUtil.isEmpty(paramList)) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含data", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + IPickmMaintainService serv = (IPickmMaintainService) NCLocator.getInstance().lookup(IPickmMaintainService.class); + List resultAggVOList = new ArrayList<>(); + + // 按pk_pmo分组处理 + Map>> pmoGroups = new HashMap<>(); + for (Map map : paramList) { + String pk_pmo = (String) map.get("pk_pmo"); + if (pk_pmo == null) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含pk_pmo", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + pmoGroups.computeIfAbsent(pk_pmo, k -> new ArrayList<>()).add(map); + } + + for (Map.Entry>> pmoEntry : pmoGroups.entrySet()) { + String pk_pmo = pmoEntry.getKey(); + List> pmoItems = pmoEntry.getValue(); + + // 根据流程生产订单明细查询PMO信息 + PMOItemVO pmoItemVO = (PMOItemVO) BASE_DAO.retrieveByPK(PMOItemVO.class, pk_pmo); + if (pmoItemVO == null) { + logger.info("根据pk_pmo查询的流程生产订单明细行不存在"); + return ResultMessageUtil.exceptionToJSON("根据pk_pmo查询的流程生产订单明细行不存在", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 根据流程生产订单明细主键查询备料计划 + List pickmHeadVOS = (List) BASE_DAO.retrieveByClause(PickmHeadVO.class, PickmHeadVO.VSOURCEMOID + " = '" + pmoItemVO.getCmoid() + "'"); + if (pickmHeadVOS == null || pickmHeadVOS.isEmpty()) { + logger.info("根据流程生产订单明细主键查询备料计划失败"); + return ResultMessageUtil.exceptionToJSON("根据流程生产订单明细主键查询备料计划失败", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + PickmHeadVO pickmHeadVO = pickmHeadVOS.get(0); + + // 获取当前head对应所有子项 + String searchBodySql = "SELECT * FROM mm_pickm_b WHERE nvl(dr,0) = 0 AND CPICKMID = '" + pickmHeadVO.getCpickmid() + "'"; + List existingPickmItemVOS = (List) BASE_DAO.executeQuery(searchBodySql, new BeanListProcessor(PickmItemVO.class)); + if (existingPickmItemVOS == null || existingPickmItemVOS.isEmpty()) { + return ResultMessageUtil.exceptionToJSON("未找到对应的备料计划明细,pk_pmo: " + pk_pmo, APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 收集所有materials并按物料编码分组 + Map>> materialGroups = new HashMap<>(); + for (Map pmoItem : pmoItems) { + List> materials = (List>) pmoItem.get("materials"); + if (MMCollectionUtil.isEmpty(materials)) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,参数要包含materials", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + for (Map material : materials) { + String cbmaterialvid = (String) material.get("cbmaterialvid"); + String isvirtual = (String) material.get("isvirtual"); + if (cbmaterialvid == null || isvirtual == null) { + return ResultMessageUtil.exceptionToJSON("传入数据异常,material要包含cbmaterialvid和isvirtual", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + materialGroups.computeIfAbsent(cbmaterialvid, k -> new ArrayList<>()).add(material); + } + } + + // 处理每个物料组 + for (Map.Entry>> materialEntry : materialGroups.entrySet()) { + String materialCode = materialEntry.getKey(); + List> materialItems = materialEntry.getValue(); + + // 将物料编码转换为主键 + String materialPk = transferPkByCode(MaterialVO.getDefaultTableName(), MaterialVO.PK_MATERIAL, MaterialVO.CODE, materialCode); + + // 查询该物料对应的所有备料计划明细 + List materialPickmItems = new ArrayList<>(); + for (PickmItemVO item : existingPickmItemVOS) { + if (materialPk.equals(item.getCbmaterialvid())) { + materialPickmItems.add(item); + } + } + + if (materialPickmItems.isEmpty()) { + logger.info("未找到物料编码 " + materialCode + " 对应的备料计划明细"); + return ResultMessageUtil.exceptionToJSON("未找到物料编码 " + materialCode + " 对应的备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 判断删除逻辑 + if (materialItems.size() == 1) { + // 删除单个物料明细 + Map material = materialItems.get(0); + String isvirtual = (String) material.get("isvirtual"); + + if (materialPickmItems.size() == 1) { + // 只有一个明细,直接删除 + materialPickmItems.get(0).setStatus(VOStatus.DELETED); + } else if (materialPickmItems.size() == 2) { + // 有两个明细,根据isvirtual判断删除哪个 + if ("N".equals(isvirtual)) { + // 删除实项,通过BOM逻辑查找 + PickmItemVO realItem = findRealItemByBOM(materialPickmItems, pmoItemVO, materialPk); + if (realItem != null) { + realItem.setStatus(VOStatus.DELETED); + } else { + return ResultMessageUtil.exceptionToJSON("未找到对应的实项备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + } else if ("Y".equals(isvirtual)) { + // 删除虚项,通过排除法查找 + PickmItemVO realItem = findRealItemByBOM(materialPickmItems, pmoItemVO, materialPk); + PickmItemVO virtualItem = null; + for (PickmItemVO item : materialPickmItems) { + if (!item.equals(realItem)) { + virtualItem = item; + break; + } + } + if (virtualItem != null) { + virtualItem.setStatus(VOStatus.DELETED); + } else { + return ResultMessageUtil.exceptionToJSON("未找到对应的虚项备料计划明细", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + } + } + } else if (materialItems.size() == 2) { + // 删除两个明细,验证必须包含一个实项和一个虚项 + boolean hasReal = false; + boolean hasVirtual = false; + for (Map material : materialItems) { + String isvirtual = (String) material.get("isvirtual"); + if ("N".equals(isvirtual)) { + hasReal = true; + } else if ("Y".equals(isvirtual)) { + hasVirtual = true; + } + } + + if (!hasReal || !hasVirtual) { + return ResultMessageUtil.exceptionToJSON("删除重复物料组必须包含一个实项(isvirtual=N)和一个虚项(isvirtual=Y)", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + + // 删除该物料的所有明细 + for (PickmItemVO item : materialPickmItems) { + item.setStatus(VOStatus.DELETED); + } + } else { + return ResultMessageUtil.exceptionToJSON("同一物料编码的删除项数量不能超过2个", APIErrCodeEnum.BUSINESSEXCCODE.getCode()); + } + } + + // 设置未删除的明细状态为更新 + for (PickmItemVO item : existingPickmItemVOS) { + if (item.getStatus() != VOStatus.DELETED) { + item.setStatus(VOStatus.UPDATED); + } + } + + PickmItemVO[] array = existingPickmItemVOS.toArray(new PickmItemVO[0]); + AggPickmVO aggPickmVO = new AggPickmVO(); + aggPickmVO.setParent(pickmHeadVO); + aggPickmVO.getParentVO().setStatus(VOStatus.UPDATED); + aggPickmVO.setChildren(PickmItemVO.class, array); + this.setDefaultValue(aggPickmVO); + resultAggVOList.add(aggPickmVO); + } + + if (!resultAggVOList.isEmpty()) { + serv.update(resultAggVOList.toArray(new AggPickmVO[0])); + } + logger.info("备料计划明细行删除成功"); + return ResultMessageUtil.toJSON(new String[0], "备料计划明细行删除成功"); + } catch (Exception e) { + logger.error("备料计划明细行删除异常", e); + return ResultMessageUtil.exceptionToJSON(e); + } + } + + /** + * 通过BOM逻辑查找实项(isvirtual=N对应的明细) + */ + private PickmItemVO findRealItemByBOM(List materialPickmItems, PMOItemVO pmoItemVO, String materialPk) throws BusinessException { + try { + // 查询BOM信息 + String bomSql = "cbmaterialvid = '" + pmoItemVO.getCmaterialvid() + "' and vbbomversionnumber = '" + pmoItemVO.getVbomversion() + "'"; + BomVO bomHeadVO = (BomVO) BASE_DAO.retrieveByClause(BomVO.class, bomSql); + if (bomHeadVO == null) { + return null; + } + + String bombSql = BomVO.CBOMID + " = '" + bomHeadVO.getCbomid() + "'"; + List bomItemVOS = (List) BASE_DAO.retrieveByClause(BomItemVO.class, bombSql); + + // 先检查BOM表头 + String hcmaterialvid = bomHeadVO.getHcmaterialvid(); + UFBoolean hisvirtual = bomHeadVO.getHisvirtual(); + if (hcmaterialvid != null && hisvirtual != null && + hcmaterialvid.equals(materialPk) && !hisvirtual.booleanValue()) { + for (PickmItemVO item : materialPickmItems) { + if (bomHeadVO.getCbomid().equals(item.getCbombid())) { + return item; + } + } + } + + // 如果表头没找到,查找BOM明细 + for (BomItemVO bomItemVO : bomItemVOS) { + if (bomItemVO != null) { + String cmaterialvid = bomItemVO.getCmaterialvid(); + UFBoolean bisvirtual = bomItemVO.getBisvirtual(); + if (cmaterialvid != null && bisvirtual != null && + cmaterialvid.equals(materialPk) && !bisvirtual.booleanValue()) { + for (PickmItemVO item : materialPickmItems) { + if (bomItemVO.getCbom_bid().equals(item.getCbombid())) { + return item; + } + } + } + } + } + + return null; + } catch (Exception e) { + logger.error("查找实项明细异常", e); + return null; + } + } + + /** + * 将请求参数转换为PickmHeadVO + */ + public static PickmHeadVO transferToPickmHeadVO(Map row, Integer type) throws BusinessException { + if (row == null) { + throw new BusinessException("根据pk_pmo未查询出相关流程备料计划"); + } + PickmHeadVO pickmHeadVO = new PickmHeadVO(); + pickmHeadVO.setPk_group(AppContext.getInstance().getPkGroup()); + pickmHeadVO.setStatus(type); + for (String key : row.keySet()) { + pickmHeadVO.setAttributeValue(key, row.get(key)); + } + return pickmHeadVO; + } + + /** + * 将请求参数mm_pickm_b数组中的每一个个体转换为PickmItemVO个体 + */ + public static PickmItemVO transferToPickmItemVO(Map pickmBody, Integer type) throws BusinessException { + PickmItemVO body = new PickmItemVO(); + for (String key : pickmBody.keySet()) { + body.setAttributeValue(key, pickmBody.get(key)); + } + body.setStatus(type); + return body; + } + + private void setDefaultValue(AggPickmVO vo) { + String pk = vo.getParentVO().getCpickmid(); + + for (PickmItemVO item : (PickmItemVO[]) vo.getChildrenVO()) { + if (2 == item.getStatus()) { + item.setCpickmid(pk); + item.setCpickm_bid((String) null); + } + } + + } + + /** + * 根据编码查询主键 + */ + private String transferPkByCode(String tableName, String selectField, String codeField, String code) throws BusinessException { + if (code == null || code.trim().isEmpty()) { + return null; + } + SqlBuilder sqlBuilder = new SqlBuilder(); + sqlBuilder.append(" select " + selectField); + sqlBuilder.append(" from " + tableName); + sqlBuilder.append(" where "); + sqlBuilder.append(codeField, code); + Object o = BASE_DAO.executeQuery(sqlBuilder.toString(), new ColumnProcessor()); + if (o == null) { + throw new BusinessException("未查询到主键信息,sql【" + sqlBuilder + "】"); + } + return o.toString(); + } + + + // transferSingleDataCodeToPk + private Map transferSingleDataCodeToPk(Map singleData) throws BusinessException { + // 1. 创建新 Map,复制原始数据(浅拷贝) + Map newData = new HashMap<>(singleData); + // 2. 只修改需要的字段(其他字段保持不变) + String org_code = transferPkByCode(OrgVO.getDefaultTableName(), OrgVO.PK_ORG, OrgVO.CODE, (String) singleData.get("pk_org")); + newData.put("pk_org", org_code); // 修改新 Map,不影响原 Map + String group_code = transferPkByCode(GroupVO.getDefaultTableName(), GroupVO.PK_GROUP, GroupVO.CODE, (String) singleData.get("pk_group")); + newData.put("pk_group", group_code); + String csupplyorgvidcode = transferPkByCode(StockOrgVersionVO.getDefaultTableName(), StockOrgVersionVO.PK_VID, StockOrgVersionVO.CODE, (String) singleData.get("csupplyorgvid")); + newData.put("csupplyorgvid", csupplyorgvidcode); + String cbmaterialvidcode = transferPkByCode(MaterialVO.getDefaultTableName(), MaterialVO.PK_MATERIAL, MaterialVO.CODE, (String) singleData.get("cbmaterialvid")); + newData.put("cbmaterialvid", cbmaterialvidcode); + String cdeliverorgvidcode = transferPkByCode(StockOrgVersionVO.getDefaultTableName(), StockOrgVersionVO.PK_VID, StockOrgVersionVO.CODE, (String) singleData.get("cdeliverorgvid")); + newData.put("cdeliverorgvid", cdeliverorgvidcode); + String cdeliverorgidcode = transferPkByCode(StockOrgVO.getDefaultTableName(), StockOrgVO.PK_STOCKORG, StockOrgVO.CODE, (String) singleData.get("cdeliverorgid")); + newData.put("cdeliverorgid", cdeliverorgidcode); + String cbunitidcode = transferPkByCode(MeasdocVO.getDefaultTableName(), MeasdocVO.PK_MEASDOC, MeasdocVO.CODE, (String) singleData.get("cbunitid")); + newData.put("cbunitid", cbunitidcode); + return newData; + } + + + public String getModule() { + return "mmpac"; + } +}