付款申请单,如何追查跨级源头采购订单
来源:互联网 发布:淮南市大数据 编辑:程序博客网 时间:2024/04/29 11:56
案例背景:
采购订单 -> 收料通知单 -> 采购入库单 -> 应付单 -> 付款申请单,采购订单经过多步下推,才生成付款申请单。
现在需要根据付款申请单的单据内码,寻找其源头的采购订单;
打开采购订单列表,展示出来搜索出的源头采购订单;
技术难点:
1. 经过了多步骤下推,如何从付款申请单逐层往上追溯,找到源头采购订单?
2. 如果获取这样的追溯关系?
3. 中间环节应付单,对采购物料明细进行合并,重新归纳了付款计划,在此情景下如何追溯?
实现方案:
1. 通过付款申请单的关联主实体 - 付款明细,根据业务流程实例数据,寻找到源头的应付单
2. 通过应付单的的关联主实体 - 物料明细,读取业务流程实例数据,寻找到源头的采购订单
案例设计:
在付款申请单上,添加一个菜单:联查采购订单(tbSearchSrcPO);
然后挂上本插件,即可验证效果
示例代码:
采购订单 -> 收料通知单 -> 采购入库单 -> 应付单 -> 付款申请单,采购订单经过多步下推,才生成付款申请单。
现在需要根据付款申请单的单据内码,寻找其源头的采购订单;
打开采购订单列表,展示出来搜索出的源头采购订单;
技术难点:
1. 经过了多步骤下推,如何从付款申请单逐层往上追溯,找到源头采购订单?
2. 如果获取这样的追溯关系?
3. 中间环节应付单,对采购物料明细进行合并,重新归纳了付款计划,在此情景下如何追溯?
实现方案:
1. 通过付款申请单的关联主实体 - 付款明细,根据业务流程实例数据,寻找到源头的应付单
2. 通过应付单的的关联主实体 - 物料明细,读取业务流程实例数据,寻找到源头的采购订单
案例设计:
在付款申请单上,添加一个菜单:联查采购订单(tbSearchSrcPO);
然后挂上本插件,即可验证效果
示例代码:
已经在本地验证通过,代码较长
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel;using Kingdee.BOS;using Kingdee.BOS.Util;using Kingdee.BOS.BusinessEntity.BusinessFlow;using Kingdee.BOS.Core;using Kingdee.BOS.Core.DynamicForm.PlugIn;using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;using Kingdee.BOS.Core.Bill;using Kingdee.BOS.Core.Bill.PlugIn;using Kingdee.BOS.Core.Bill.PlugIn.Args;using Kingdee.BOS.Core.BusinessFlow.ServiceArgs;using Kingdee.BOS.Core.Metadata;using Kingdee.BOS.Core.Metadata.EntityElement;using Kingdee.BOS.Core.List;using Kingdee.BOS.Core.SqlBuilder;using Kingdee.BOS.ServiceHelper;namespace JDSample.FormPlugIn.Bill{ [Description("搜索付款申请单的源头采购订单")] public class S151202SearchSrcBillEdit : AbstractBillPlugIn { public override void AfterBarItemClick(AfterBarItemClickEventArgs e) { if (e.BarItemKey.EqualsIgnoreCase("tbSearchSrcPO")) {// 搜索源头采购订单 if (this.View.Model.GetPKValue() == null ) { this.View.ShowMessage("请先保存单据!"); return; } long payAppBillId = Convert.ToInt64(this.View.Model.GetPKValue()); this.DoSearchSrcPO(payAppBillId); } } /// <summary> /// 搜索源头采购订单,并显示列表 /// </summary> /// <param name="payAppBillId">付款申请单单据内码</param> private void DoSearchSrcPO(long payAppBillId) { // 读取付款申请单.明细内码 HashSet<long> payAppEntityIds = this.LoadEntityIds( "CN_PAYAPPLY", "FPAYAPPLYENTRY", new long[] { payAppBillId }); if (payAppEntityIds.Count == 0) { this.View.ShowMessage("付款申请单的明细单据体没有数据,没有源单!"); return; } // 读取付款申请单的业务流程实例 BusinessFlowInstanceCollection payAppInsts = this.LoadBFInstances( "CN_PAYAPPLY", "FPAYAPPLYENTRY", payAppEntityIds.ToArray()); if (payAppInsts.Count == 0) { this.View.ShowMessage("付款申请单的明细单据体是手工创建的,没有源单!"); return; } // 取付款申请单源头的应付单.付款计划 HashSet<long> apPlanEntityIds = this.GetSrcEntityIdsByInsts(payAppInsts, "AP_Payable", "FEntityPlan", "CN_PAYAPPLY", "FPAYAPPLYENTRY", payAppEntityIds); if (apPlanEntityIds.Count == 0) { this.View.ShowMessage("没有找到源头的应付单,线索中断,不能继续追查采购订单"); return; } // 根据应付单.付款计划内码,找到应付单.物料明细内码 HashSet<long> apBillIds = this.LoadBillIds("AP_Payable", "FEntityPlan", apPlanEntityIds.ToArray()); HashSet<long> apDetailIds = this.LoadEntityIds("AP_Payable", "FEntityDetail", apBillIds.ToArray()); // 加载应付单.物料明细的业务流程实例 BusinessFlowInstanceCollection apDetailInsts = this.LoadBFInstances( "AP_Payable", "FEntityDetail", apDetailIds.ToArray()); // 取应付单源头的采购订单物料明细内码 HashSet<long> poEntityIds = this.GetSrcEntityIdsByInsts(apDetailInsts, "PUR_PurchaseOrder", "FPOOrderEntry", "AP_Payable", "FEntityDetail", apDetailIds); if (poEntityIds.Count == 0) { this.View.ShowMessage("没有找到源头的采购订单!"); return; } // 取源头的采购订单内码 HashSet<long> poBillIds = this.LoadBillIds("PUR_PurchaseOrder", "FPOOrderEntry", poEntityIds.ToArray()); // 显示出搜索出来的采购订单列表 this.ShowPOList(poBillIds.ToArray()); } /// <summary> /// 根据单据体内码,读取其单据内码 /// </summary> /// <param name="formId"></param> /// <param name="entityKey"></param> /// <param name="entityIds"></param> /// <returns></returns> private HashSet<long> LoadBillIds(string formId, string entityKey, long[] entityIds) { HashSet<long> billIds = new HashSet<long>(); if (entityKey.EqualsIgnoreCase("FBillHead")) {// 需要读取的实体为单据头,直接返回实体内码集合,无需到数据库读取 foreach (var entityId in entityIds) { billIds.Add(entityId); } } else { // 读取单据的元数据 FormMetadata meta = MetaDataServiceHelper.Load(this.Context, formId) as FormMetadata; Entity entity = meta.BusinessInfo.GetEntity(entityKey); // 构建取数服务参数,仅加载单据内码字段 QueryBuilderParemeter queryParam = new QueryBuilderParemeter(); queryParam.FormId = formId; queryParam.BusinessInfo = meta.BusinessInfo; queryParam.SelectItems.Add(new SelectorItemInfo(meta.BusinessInfo.GetForm().PkFieldName)); queryParam.FilterClauseWihtKey = string.Format("{0}_{1} in ({2})", entityKey, entity.EntryPkFieldName, string.Join(",", entityIds)); // 读取数据 var rows = QueryServiceHelper.GetDynamicObjectCollection(this.Context, queryParam); // 把取到的单据内码返回 foreach(var row in rows) { long billId = Convert.ToInt64(row[0]); if (billIds.Contains(billId) == false) { billIds.Add(billId); } } } return billIds; } /// <summary> /// 读取指定单据的实体内码返回 /// </summary> /// <param name="formId">单据formId</param> /// <param name="entityKey">实体Key</param> /// <param name="billIds">单据内码集合</param> /// <returns></returns> private HashSet<long> LoadEntityIds(string formId, string entityKey, long[] billIds) { HashSet<long> entityIds = new HashSet<long>(); if (entityKey.EqualsIgnoreCase("FBillHead")) {// 需要读取的实体为单据头,直接返回单据内码集合,无需到数据库读取 foreach (var billId in billIds) { entityIds.Add(billId); } } else { // 读取单据的元数据 FormMetadata meta = MetaDataServiceHelper.Load(this.Context, formId) as FormMetadata; Entity entity = meta.BusinessInfo.GetEntity(entityKey); // 构建取数服务参数,仅加载实体内码字段 QueryBuilderParemeter queryParam = new QueryBuilderParemeter(); queryParam.FormId = formId; queryParam.BusinessInfo = meta.BusinessInfo; queryParam.SelectItems.Add( new SelectorItemInfo(string.Format("{0}_{1}", entityKey, entity.EntryPkFieldName))); queryParam.FilterClauseWihtKey = string.Format("{0} in ({1})", meta.BusinessInfo.GetForm().PkFieldName, string.Join(",", billIds)); // 读取数据 var rows = QueryServiceHelper.GetDynamicObjectCollection(this.Context, queryParam); // 把取到的实体内码返回 foreach(var row in rows) { entityIds.Add(Convert.ToInt64(row[0])); } } return entityIds; } /// <summary> /// 到业务流程实例中,基于目标单,寻找指定单据类型的源单 /// </summary> /// <param name="insts">业务流程实例</param> /// <param name="srcFormId">源单formId</param> /// <param name="srcEntityKey">源单实体key</param> /// <param name="targetFormId">目标单formId</param> /// <param name="targetEntityKey">目标实体key</param> /// <param name="targetEntityIds">目标单实体内码集合</param> /// <returns></returns> private HashSet<long> GetSrcEntityIdsByInsts(BusinessFlowInstanceCollection insts, string srcFormId, string srcEntityKey, string targetFormId, string targetEntityKey, HashSet<long> targetEntityIds) { HashSet<long> srcEntityIds = new HashSet<long>(); if (insts == null || insts.Count == 0) { return srcEntityIds; } // 到业务流程实例中,寻找目标单所在的节点 string targetTableNumber = this.LoadTableNumber(targetFormId, targetEntityKey); List<RouteTreeNode> targetNodes = new List<RouteTreeNode>(); foreach (var inst in insts) { var nodes = inst.SerarchTargetFormNodes(targetTableNumber); foreach(var node in nodes) { long targetEntityId = node.Id.EId; if (targetEntityIds.Contains(targetEntityId)) { targetNodes.Add(node); } } } // 基于目标单所在的节点,反查指定的源单 string srcTableNumber = this.LoadTableNumber(srcFormId, srcEntityKey); foreach (var targetNode in targetNodes) { // 不断往上追溯,寻找指定类型的源单 RouteTreeNode parentNode = targetNode.ParentNode; while (parentNode != null) { if (parentNode.Id.Tbl.EqualsIgnoreCase(srcTableNumber)) {// 此父节点,就是需要的源单类型,取值 if (srcEntityIds.Contains(parentNode.Id.EId) == false) { srcEntityIds.Add(parentNode.Id.EId); } } parentNode = parentNode.ParentNode; } } return srcEntityIds; } /// <summary> /// 获取单据关联主实体的业务流程实例:业务流程实例记录了每行单据体的来龙去脉 /// </summary> /// <param name="formId">单据</param> /// <param name="entityKey">关联主实体Key</param> /// <param name="entityIds">关联主实体内码集合</param> /// <returns></returns> private BusinessFlowInstanceCollection LoadBFInstances(string formId, string entityKey, long[] entityIds) { LoadInstancesByEntityIdArgs args = new LoadInstancesByEntityIdArgs(formId, entityKey, entityIds); var instances = BusinessFlowDataServiceHelper.LoadInstancesByEntityId(this.Context, args); return instances; } /// <summary> /// 获取单据体的表格编码 /// </summary> /// <param name="formId">单据FormId</param> /// <param name="entityKey">实体Key;如果关联主实体是单据头,请传入FBillHead</param> /// <returns>新建的数据库,从未保存过此业务单据时,表格编码可能为空</returns> /// <remarks> /// 在业务流程跟踪关系中,每个单据的单据体都有一个唯一的表格编码。 /// 默认是单据体的物理表格名。 /// 但在此物料表格被多个单据公用时,会在物理表名后面增加序号以示区分 /// </remarks> private string LoadTableNumber(string formId, string entityKey) { var tableDefine = BusinessFlowServiceHelper.LoadTableDefine(this.Context, formId, entityKey); if (tableDefine == null) { return string.Empty; } else { return tableDefine.TableNumber; } } /// <summary> /// 显示采购订单列表 /// </summary> /// <param name="poBillIds"></param> private void ShowPOList(long[] poBillIds) { ListShowParameter showParam = new ListShowParameter(); showParam.FormId = "PUR_PurchaseOrder"; showParam.ListFilterParameter.Filter = string.Format(" FID in ({0}) ", string.Join(",", poBillIds)); this.View.ShowForm(showParam); } }}
0 0
- 付款申请单,如何追查跨级源头采购订单
- 采购订单付款清单
- 采购订单付款清单
- PO采购-采购申请单
- 【干货分享】流程DEMO-付款申请单
- PO采购-采购订单
- ABAP_ALV_例子(采购申请单查询)
- MM--如何控制采购申请转变为采购订单数量不超过采购申请数量
- 如何控制采购申请转变为采购订单数量不超过采购申请数量
- MM--如何控制采购申请转变为采购订单数量不超过采购申请数量
- 如何实现下订单后一个小时后未付款的订单自动取消
- Oracle EBS 如何将申购单转换成采购订单
- 如何逐步构建采购订单Web API保存接口参数
- MAXIMO 采购配置--采购申请、采购订单
- 采购付款会计分录处理
- 采购订单批导
- 采购订单收货
- 采购订单历史删除
- 在单据维护界面仅下推选中的单据体行
- C# 接口详解
- Linux程序前台后台切换
- 68-类的成员变量
- 文章标题
- 付款申请单,如何追查跨级源头采购订单
- 推排序举例
- (水)POJ-2376 区间贪心,区间覆盖
- Java三大框架入门-struts2入门(一)
- 69-类的成员方法
- 文章标题
- 啊哈!算法—快速排序
- IE提交数据库显示乱码,360和chrome显示正常
- 如何通过插件携带第二个单据体到下游单据