
# 委外齐套分析下推领料单限制拣货仓库
## 业务场景
委外齐套分析在完成齐套分析后会生成本次领料数,在审核后点击下推委外领料单会根据当前的本次领料数下推委外领料单并进行目标数量的填充。在完成数量填充后,单据转换根据拣货服务,自动按当前的发料组织匹配可用的库存。标准产品在该拣货过程未与委外齐套分析仓库页签勾选的仓库范围联动,导致匹配到不应考虑的仓库库存。
本文提供给一种二开办法来补充实现如何控制拣货服务在限定的仓库范围内匹配库存。
## 实现方案
1.二开委外齐套分析至委外领料单单据转换,传入委外齐套分析仓库页签设置的仓库范围。
2.二开委外领料单拣货服务,加入考虑第1步传入的仓库范围,约束拣货服务获取的库存数据以及先后顺序。
## 详细技术步骤
### 二开委外领料单

加入扩展文本字段,用于下推时填入仓库范围
### 扩展修改单据转换

该插件用于获取源单的仓库范围填充到领料单分录上
#### 参考插件代码
```csharp
using Kingdee.BOS.Core.Metadata.ConvertElement.PlugIn;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kingdee.BOS.Core.Metadata.ConvertElement.PlugIn.Args;
using Kingdee.BOS.Core.List;
using Kingdee.BOS.Util;
using Kingdee.K3.Core.MFG.EntityHelper;
using Kingdee.BOS.Core;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.App;
using Kingdee.BOS.Contracts;
namespace SampleAppPlugIn
{
public class SampleConvertPlugIn : AbstractConvertPlugIn
{
long pmBillId = 0;//委外齐套分析单内码
public override void OnInSelectedRow(InSelectedRowEventArgs e)
{
IEnumerable<ListSelectedRow> selectedRows = e.SelectedRows;
if (!selectedRows.IsEmpty())
{
pmBillId = selectedRows.FirstOrDefault().PrimaryKeyValue.ConvertTo<long>();
}
}
public override void OnAfterCreateLink(CreateLinkEventArgs e)
{
if (pmBillId == 0)
return;
List<ExtendedDataEntity> extendedDataEntitys = e.TargetExtendedDataEntities.FindByEntityKey("FBillHead").ToList();
if (extendedDataEntitys.IsEmpty())
return;
FormMetadata prepareMtrlMetaData = ServiceHelper.GetService<IMetaDataService>().Load(this.Context,"SUB_PrepareMtrl") as FormMetadata;
DynamicObject prepareMtrlBill = ServiceHelper.GetService<IViewService>().LoadSingle(this.Context, pmBillId, prepareMtrlMetaData.BusinessInfo.GetDynamicObjectType());
DynamicObjectCollection stockEntrys = prepareMtrlBill["PreparemtrlStockEntity"] as DynamicObjectCollection;
List<long> selectedStocks = stockEntrys.Where(x => x.GetDynamicValue<bool>("Selected")).Select(x => x.GetDynamicValue<long>("StockId_Id")).ToList();//获取委外齐套分析单的仓库页签勾选的仓库
foreach (var pickData in extendedDataEntitys)
{
DynamicObject pickDataView = pickData.DataEntity;
DynamicObjectCollection pickEntrys = pickDataView["Entity"] as DynamicObjectCollection;
foreach (var pickEntry in pickEntrys)
{
List<long> stockIds = new List<long>();//用于过滤仓库范围的仓库ID集合
long issueStock = pickEntry.GetDynamicValue<long>("StockID_Id");
if (issueStock > 0)
{//如果映射了用料清单的领料仓库,拣货只会按该仓库获取库存,这里清理掉用于获得其他仓库的库存
stockIds.Add(issueStock);//先加入发料仓,用于优先拣发料仓的库存
pickEntry.SetDynamicObjectItemValue("StockID_Id", 0);
pickEntry.SetDynamicObjectItemValue("StockID", null);
}
stockIds.AddRange(selectedStocks);
stockIds = stockIds.Distinct().ToList();
pickEntry.SetDynamicObjectItemValue("FStockFilterString", string.Join(",", stockIds));
}
}
}
}
}
```
### 二开拣货服务

拣货服务的插件,重写RegexSelectResultByCurRowData,按自定义逻辑处理(过滤,重排序)并返回e.SelResults,实现自定义逻辑过滤&优选拣货结果。
#### 参考插件代码
```csharp
using Kingdee.K3.SCM.App.Core.ConvertBusinessService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kingdee.K3.SCM.App.Core.ConvertBusinessService.LotPickArgs;
using Kingdee.BOS.Util;
using System.Data;
namespace SamplePlugIn
{
public class MatchLotPickingPlugIn : AbstractLotPickPlugIn
{
//根据拣货当前行数据处理匹配到的技术库存记录
public override DataRow[] RegexSelectResultByCurRowData(RegexSelectResultByCurRowDataArgs e)
{
string stockFilterString = Convert.ToString(e.Entity.DataEntity["FStockFilterString"]);//获取仓库范围
if (!stockFilterString.IsNullOrEmptyOrWhiteSpace())
{
List<long> stockIds = stockFilterString.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt64(x)).ToList();
List<DataRow> sort = new List<DataRow>();//整理后的即时库存记录
sort.AddRange(e.SelResults.Where(x => Convert.ToInt64(x["FSTOCKID"]) == stockIds.FirstOrDefault()));//先考虑发料仓库的库存(发料仓库默认放在stockIds第一位)
stockIds.RemoveAt(0);
sort.AddRange(e.SelResults.Where(x => stockIds.Contains(Convert.ToInt64(x["FSTOCKID"]))));//按照仓库范围过滤已经获取的库存
e.SelResults = sort.ToArray();
}
return e.SelResults;
}
}
}
```
## 实现效果



预期效果:按CK002+仓库范围test,CK003等仓库进行匹配,但不考虑D仓库的库存
