业务背景:仓管员手持移动设备,对采购收料进行实际入库,在手机APP、PDA等移动设备上选择收料单,录入仓库、仓位、数量等信息,移动设备回传数据到K\3 Cloud端,Cloud自动进行收料通知单下推采购入库单,并根据传过来的仓库、仓位、数量信息进行保存、拆分分录等操作。
下面讲解怎么自定义API处理将收料单的一条分录进行下推,并进行修改数据和拆分入库分录。
根据需求,我们定义好客户端(发送端/移动设备app端)需要发送的数据字段:
收料单分录id,入库数量,入库仓库,入库仓位。
因为一个收料单分录可能入到不同的仓库仓位,所以我们这里一个收料单分录要可以对应多个入库数量、入库仓库、仓位。
1.客户端发送数据
//客户端发送的json数据
JObject json_root = new JObject();
JArray json_entrys = new JArray();
json_root.Add("entrys", json_entrys);
//收料单分录id为100016
JObject json_entry = new JObject();
json_entry.Add("recEntryId", 100016);
//第一个入库 为数量5,仓库编码为CK_001 ,仓位(id)为100005
JArray json_entrys_details = new JArray();
JObject json_entrys_detail_item = new JObject();
json_entrys_detail_item.Add("qty",5);
json_entrys_detail_item.Add("stocknumber", "CK_001");
json_entrys_detail_item.Add("stockLocId", 100005);
json_entrys_details.Add(json_entrys_detail_item);
//第一个入库 为数量6,仓库编码为CK_001 ,仓位(id)为100006
json_entrys_detail_item = new JObject();
json_entrys_detail_item.Add("qty",6);
json_entrys_detail_item.Add("stocknumber", "CK_001");
json_entrys_detail_item.Add("stockLocId", 100006);
json_entrys_details.Add(json_entrys_detail_item);
json_entry.Add("details", json_entrys_details);
json_entrys.Add(json_entry);
数据结构格式后结果:
2.服务端接收数据
因为cloud通版的api并不支持这类需求,因此需要自己写自定义接口来处理。
首先我们自己新建一个代码类库项目,引用相关的bos组件,然后新建一个接口,继承BOS相关的接口服务。
InstockService : KDBaseService
2.1在自定义接口中,我们搜集下传入的收料单分录id,然后调用下推服务进行下推采购入库单。
JObject jObj_Root = JObject.Parse(parameter);
List
List
JArray jArr_recDataEntrys = jObj_Root["entrys"] as JArray;
foreach (JObject item in jArr_recDataEntrys)
{
long recEntryId = GetNullableLong(item, "recEntryId");
var jObj_entry_detail = item["details"] as JArray;
foreach (JObject detailItem in jObj_entry_detail)
{
decimal qty = GetNullableDecimal(detailItem, "qty");
string stockNumber = Convert.ToString(detailItem["stocknumber"]);
long stockLocId = GetNullableLong(detailItem, "stockLocId");
recData.Add(new RecData()
{
RecEntryId = recEntryId,
Qty = qty,
StockNumber = stockNumber,
StockLocId = stockLocId
});
}
srcEntryIds.Add(recEntryId);
}
srcEntryIds = srcEntryIds.Distinct().ToList();
//通版根据收料单下推入库单单,一行收料单只会生成一行入库单。需要在后面代码中处理关联复制行
DynamicObject[] instockBillDataArr = PushRecBills(this.KDContext.Session.AppContext, srcEntryIds);
if (instockBillDataArr == null || instockBillDataArr.Length <= 0)
{
throw new Exception("下推失败,请检查输入参数");
}
2.2 调用下推后,下推接口会返回下推的入库单的数据包。因为通版的下推功能一行收料单分录只会生成一行入库单,所以我们要处理下推后的数据包,根据客户端发来的json数据的拆分行数量对入库单分录数据进行相当于关联复制行的拆分。即客户端要求拆多少条,我们就关联复制行多少次。
//入库单单据
foreach (var billItem in instockBillDataArr)
{
//入库单分录
var entrys = billItem["InStockEntry"] as DynamicObjectCollection;
List
int index = 0;
foreach (var entryItem in entrys)
{
DynamicObjectCollection links = entryItem["FInStockEntry_Link"] as DynamicObjectCollection;
//从link数据找到上游单据分录id,不考虑合并情况
long srcEntryId = Convert.ToInt64(links[0]["SID"]);
var recEntryData = jArr_recDataEntrys.Where(p => GetNullableLong((JObject)p, "recEntryId") == srcEntryId).FirstOrDefault();
var jObj_entry_detail = recEntryData["details"] as JArray;
int needCopyCount = jObj_entry_detail.Count - 1;
if (needCopyCount > 0)
{
linkCopyCount.Add(new Tuple
}
index++;
}
//关联复制数据
foreach (var tupleItem in linkCopyCount)
{
int indexSeq = tupleItem.Item1;
DynamicObject needCopyDy = entrys[indexSeq];
for (int i = 0; i < tupleItem.Item2; i++)
{
DynamicObject copyedDy = (DynamicObject)Kingdee.BOS.Orm.OrmUtils.Clone(needCopyDy);
copyedDy["seq"] = entrys.Count + 1;
entrys.Add(copyedDy);
}
}
}
2.3 暂存下拆分分录后的入库单数据包
//暂存采购入库单,暂存后才会有内码
IOperationResult draftResult = DraftInstockData(instockBillDataArr);
//private IOperationResult DraftInstockData(DynamicObject[] instockBillDataArr)
//{
// //暂存目标单数据
// OperateOption option = OperateOption.Create();
// //option.SetIgnoreWarning(false);
// FormMetadata formMetaData = (FormMetadata)MetaDataServiceHelper.Load(this.KDContext.Session.AppContext, InstockBillFormId);
// return BusinessDataServiceHelper.Draft(this.KDContext.Session.AppContext, formMetaData.BusinessInfo, instockBillDataArr, option);
//}
2.4 调用通版的入库单保存api对入库单分录进行修改(修改数量、仓库、仓位)
if (draftResult.IsSuccess == false)
{
throw new Exception("暂存采购入库单失败!");
}
List
foreach (var billItem in draftResult.SuccessDataEnity)
{
long instockBillId = Convert.ToInt64(billItem["id"]);
var entrys = billItem["InStockEntry"] as DynamicObjectCollection;
foreach (var entryItem in entrys)
{
long instockEntryId = Convert.ToInt64(entryItem["id"]);
DynamicObjectCollection links = entryItem["FInStockEntry_Link"] as DynamicObjectCollection;
foreach (var linkItem in links)
{
long srcEntryId = Convert.ToInt64(linkItem["SID"]);
lingTracks.Add(new InstockData()
{
InstockBillId = instockBillId,
InstockEntryId = instockEntryId,
RecEntryId = srcEntryId,
});
}
}
}
//根据入库单fid分组,有可能生成多个单据
var billGroupDatas = lingTracks.GroupBy(p => p.InstockBillId);
foreach (var item in billGroupDatas)
{
JObject oJobj_Bill = new JObject();
JObject oJobj_Model = new JObject();
JArray entrys = new JArray();
oJobj_Model.Add("FID", item.Key);
foreach (var subItem in item)
{
var recDetalItem = recData.Where(p => p.RecEntryId == subItem.RecEntryId && p.IsUsed == false).FirstOrDefault();
if (recDetalItem == null)
{
continue;
}
recDetalItem.IsUsed = true;
JObject entryRow = new JObject();
entryRow.Add("FEntryId", subItem.InstockEntryId);
entryRow.Add("FRealQty", recDetalItem.Qty);
JObject baseData = new JObject();
baseData.Add("FNumber", recDetalItem.StockNumber);
entryRow.Add("FStockId", baseData);
entryRow.Add("FStockLocId", recDetalItem.StockLocId);
entrys.Add(entryRow);
}
if (entrys.Count > 0)
{
oJobj_Model.Add("FInStockEntry", entrys);
oJobj_Bill.Add("Model", oJobj_Model);
string jsonStr = oJobj_Bill.ToString();
object saveResult = WebApiServiceCall.Save(this.KDContext.Session.AppContext, InstockBillFormId, jsonStr);
}
}
自此,全部处理就完成了。
入库结果如下:
服务端全部代码在附件中,欢迎交流。
InstockService.rar(3.88KB)
推荐阅读