
【场景】选单界面,过滤掉已经选单使用过的行,避免重复选择
如在采购订单中,选单采购申请单分录,确认后,继续选单,依然能够看到已选单的分录

最终如果没有允许超额的会保存报错,而允许超额的可能会导致反写翻倍的场景
【案例】采购订单选单采购申请单,在采购申请单选单界面,针对已选单的分录,选单界面不再显示
<1>在上游的采购申请单,增加列表插件
实现思路
a)根据下游单据的数据包,通过link实体获取已经选中的源行,记录分录内码
b)根据已选源行分录内码过滤,使用not in 或者not exists

```csharp
using Kingdee.BOS.BusinessEntity.BusinessFlow;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.List.PlugIn;
using Kingdee.BOS.Core.List.PlugIn.Args;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Core.Metadata.EntityElement;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Util;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DynamicFormPlugIn.List
{
[Kingdee.BOS.Util.HotUpdate]
[System.ComponentModel.Description("源单列表插件 - 选单控制可选数据过滤")]
public class SelBillListPlugIn_FilterSelRow : AbstractListPlugIn
{
/*
* 挂在源单列表插件
* 针对特定目标单据单据选单时, 过滤源单的主业务组织逻辑
*/
/// <summary>
/// 目标单 表单标识
/// </summary>
string tgtFormId = "PUR_PurchaseOrder";
/// <summary>
/// 是否选单界面
/// </summary>
bool isSelBillSpec = false;
/// <summary>
/// 下游单据,关联的已选源单内码
/// </summary>
Dictionary<string, List<int>> srcFormBillIds = new Dictionary<string, List<int>>();
public override void OnInitialize(InitializeEventArgs e)
{
if (this.ListView.OpenParameter.ListType == (int)Kingdee.BOS.Core.Enums.BOSEnums.Enu_ListType.SelBill)
{
if (this.View.ParentFormView == null)
return;
string parentFormId = this.View.ParentFormView.BillBusinessInfo.GetForm().Id;
if (string.Equals(tgtFormId, parentFormId, StringComparison.OrdinalIgnoreCase))
{
isSelBillSpec = true;
// 根据 父视图单据界面的link实体,收集已经使用的源单行数据
CollectUseSrcRows(this.View.ParentFormView.BillBusinessInfo, this.View.ParentFormView.Model.DataObject, srcFormBillIds);
}
}
}
/// <summary>
/// 收集已使用的源单行号
/// </summary>
private static void CollectUseSrcRows(BusinessInfo businessInfo, DynamicObject billObj, Dictionary<string, List<int>> srcFormBillIds)
{
var billForm = businessInfo.GetForm();
if (billForm.LinkSet == null || billForm.LinkSet.LinkEntitys.Count == 0)
return;
// <0>收集关联源单对象和单据内码
foreach (var linkEntity in billForm.LinkSet.LinkEntitys)
{
if (linkEntity == null)
continue;
string entityKey = linkEntity.ParentEntityKey;
var entity = businessInfo.GetEntryEntity(entityKey);
if (entity == null)
continue;
var billData = billObj;
if (billData == null)
continue;
// <1>获取link 实体的父实体数据包
var entityObjColl = GetEntityDynamicObject(businessInfo, billData, entity);
for (int rowIdx = 0, rowCnt = entityObjColl.Count; rowIdx < rowCnt; ++rowIdx)
{
var entityRow = entityObjColl[rowIdx];
if (entityRow == null)
continue;
if (!entityRow.DynamicObjectType.Properties.ContainsKey(linkEntity.Key))
continue;
// <2>根据link实体 收集 源单内码 源单对象
var linkObjCol = entityRow[linkEntity.Key] as DynamicObjectCollection;
if (linkObjCol == null || linkObjCol.Count <= 0)
continue;
foreach (var linkObj in linkObjCol)
{
if (linkObj == null)
continue;
var linkSTableName = ObjectUtils.Object2String(linkObj["STableName"]);
var linkSBillid = ObjectUtils.Object2Int(linkObj["SBillId"]);
var linkSEntryid = ObjectUtils.Object2Int(linkObj["SId"]);
if (linkSTableName.IsNullOrEmptyOrWhiteSpace())
continue;
if (linkSEntryid == 0)
continue;
if (!srcFormBillIds.ContainsKey(linkSTableName))
srcFormBillIds[linkSTableName] = new List<int>();
srcFormBillIds[linkSTableName].Add(linkSEntryid);
}
}
}
}
/// <summary>
/// 获取目标实体的数据
/// </summary>
/// <param name="billObj"></param>
/// <param name="targetEntity"></param>
/// <returns></returns>
private static List<DynamicObject> GetEntityDynamicObject(BusinessInfo businessInfo, DynamicObject billObj, Entity targetEntity)
{
if (billObj == null)
return null;
List<DynamicObject> result = new List<DynamicObject>();
if (targetEntity is HeadEntity)
{
result.Add(billObj);
return result;
}
if (targetEntity is SubHeadEntity)
{
if (billObj.DynamicObjectType.Properties.ContainsKey(targetEntity.EntryName))
{
DynamicObjectCollection subHeadObj = billObj[targetEntity.EntryName] as DynamicObjectCollection;
if (subHeadObj == null || subHeadObj.Count <= 0)
return null;
foreach (var subHeadObjItem in subHeadObj)
{
result.Add(subHeadObjItem);
}
return result;
}
return null;
}
Entity headEntity = businessInfo.Entrys.FirstOrDefault(x => x is HeadEntity);
if (headEntity == null)
return null;
SubEntryEntity targetSubEntryEntity = targetEntity as SubEntryEntity;
string parentEntityKey = targetSubEntryEntity == null ? headEntity.Key : targetSubEntryEntity.ParentEntityKey;
///实现思路,假设 A(单据头) B(单据体) C(子单据体) D(子子单据体)四级关系
///从单据数据包 目标实体 和目标实体父实体的内码 获取 目标实体的所有数据
///第一步获取搜索路径,第二步根据搜索路径存入所有目标实体的父实体数据包,将父实体数据包的所有子分录收集
EntryEntity entryEntity = targetEntity as EntryEntity;//先获取对应的搜索路径
Stack<EntryEntity> pathEntity = new Stack<EntryEntity>();
while ((entryEntity as SubEntryEntity) != null)//递归子单据体
{
entryEntity = (entryEntity as SubEntryEntity).ParentEntity;
pathEntity.Push(entryEntity);
}
List<DynamicObjectCollection> lastEntityCollection = new List<DynamicObjectCollection>();
DynamicObjectCollection billObjCollection = new DynamicObjectCollection(billObj.DynamicObjectType);
billObjCollection.Add(billObj);
lastEntityCollection.Add(billObjCollection);
DynamicObjectCollection tempCollection = null;
while (pathEntity.Count != 0)
{
EntryEntity tempEntity = pathEntity.Pop();
//递归BFS
List<DynamicObjectCollection> tempEntityCollection = new List<DynamicObjectCollection>();
foreach (var lastEntityObjs in lastEntityCollection)
{
if (!lastEntityObjs.DynamicCollectionItemPropertyType.Properties.ContainsKey(tempEntity.EntryName))
continue;
foreach (var lastEntityObj in lastEntityObjs)
{
tempCollection = lastEntityObj[tempEntity.EntryName] as DynamicObjectCollection;
if (tempCollection == null || tempCollection.Count == 0)
continue;
tempEntityCollection.Add(tempCollection);
}
}
lastEntityCollection = tempEntityCollection;
}
//这里是目标实体的父实体数据包集合,兼容了目标实体是单据体
foreach (var lastEntityObjs in lastEntityCollection)
{
if (!lastEntityObjs.DynamicCollectionItemPropertyType.Properties.ContainsKey(targetEntity.EntryName))
continue;
foreach (var lastEntityObj in lastEntityObjs)
{
DynamicObjectCollection objColl = lastEntityObj[targetEntity.EntryName] as DynamicObjectCollection;
if (objColl == null)
continue;
foreach (var obj in objColl)
{
result.Add(obj);
}
}
}
return result;
}
/// <summary>
/// 追加过滤
/// </summary>
/// <param name="e"></param>
public override void AfterCreateSqlBuilderParameter(SqlBuilderParameterArgs e)
{
if (!isSelBillSpec)
return;
/*
* 假定过滤实体为明细,这里与转换规则有关系,如果是明细下推就是明细关联
* 当然你也可以全部实体扫描,这里没有这个必要
*/
Entity filterEntity = this.View.BillBusinessInfo.GetEntity("FEntity");
if (filterEntity == null)
return;
TableDefine tableDefine = Kingdee.BOS.ServiceHelper.BusinessFlowServiceHelper.LoadTableDefine(this.Context, this.View.BillBusinessInfo.GetForm().Id, filterEntity.Key);
if (tableDefine == null)
return;
if (srcFormBillIds.ContainsKey(tableDefine.TableNumber))
{
//todo 如果分录少的话可以这么写,直接not in,分录多的话这个地方会有些性能损耗
string sourceEntryPkKey = string.Concat(filterEntity.Key, "_", filterEntity.EntryPkFieldName);
string filter = string.Format("{0} NOT IN ({1})", sourceEntryPkKey, string.Join(",", srcFormBillIds[tableDefine.TableNumber]));
e.sqlBuilderParameter.FilterClauseWihtKey = e.sqlBuilderParameter.FilterClauseWihtKey.JoinFilterString(filter);
}
}
}
}
```
【效果】选单界面过滤已选择行
