本文介绍了在特定项目中,由于现有MES系统与外网星空产品在数据集成时遇到的标准导入功能不匹配问题,需要自定义导入功能实现系统间数据交互。MES系统已开发完成且不愿修改其导出模板,因此通过读取MES系统导出的Excel文件内容,构建简单入库单并自动下推销售出库单,实现自动保存、提交和审核。具体步骤包括读取Excel文件、构建入库单视图、绑定实体信息并调用保存、提交、审核方法,最终实现数据自动流转。
现在项目中发现有很多场景,用我们标准的导入功能无法实现其想要的场景,并且希望在导入时还能根据导入的一些信息实现其他的一些单据能自动下推,并自动保存、提交和审核,下面就以实际项目中的一个场景分享给大家在未来项目中做参考,具体场景时,客户使用的MES系统是内网,星空产品是外网,只能通过导出、导入方式实现系统数据集成,但MES系统已经开发完成,其MES供应商导出的模板也不再想做开发,因此导出的模板,如果不通过手工操作根本无法导入到星空系统,因为我们的导入模板是含数据库字段的,另外想通过导入到简单入库单后还可以根据导入的MES单据里含有的订单号码及订单项号能自动下推销售出库单,这些单据都希望是系统自动实现,因此这个导入功能必须自己来实现,并且在读取EXCEL信息后,再调用销售订单下推销售出库单的下推方法,然后再调用下推后的保存方法,并实现其自动保存、提交和审核,实现过程:
一、读取需导入的EXCEL字段内容,并模拟构建简单入库单的视图、实体信息绑定、调保存、提交、审核方法
int exportprogressValue = 0;
this._processTips = Kingdee.BOS.Resource.ResManager.LoadKDString("开始引入...", "002013030003982", Kingdee.BOS.Resource.SubSystemType.BOS);
if (this._progressBar != null)
{
this._progressBar.Start(1);
this._progressBar.Visible = true;
}
//读取excel数据
this._processTips = Kingdee.BOS.Resource.ResManager.LoadKDString("开始读取引入文件...", "002013030003991", Kingdee.BOS.Resource.SubSystemType.BOS);
this._processRate = 1;
using (ExcelOperation helper = new ExcelOperation(this.View))
{
DataSet ds = helper.ReadFromFile(_filePath, 1, 0);
//不能选择在Excel转DataSet帮助方法内跳过“枚举值对应表”页签,因为是通用的帮助方法,所以改在外面移除DataTable表。
//而ExcelOperation.ReadFromFile()方法里,能跳过“引入模板说明”页签是因为最后有值得列序号colIndex == 0
bool hasData = ds.Tables.Cast<DataTable>().Any(p => p.Rows.Count > 0);
if (!hasData)
{
this.View.Session["ProcessRateValue"] = 100;
ResultErrInfo= "引入数据为空!";
this.View.ShowErrMessage(Kingdee.BOS.Resource.ResManager.LoadKDString(ResultErrInfo, "002013030003994", Kingdee.BOS.Resource.SubSystemType.BOS));
return;
}
else
{
if (!ds.Tables[0].Columns.Contains("销售单号") || !ds.Tables[0].Columns.Contains("任务单号") || !ds.Tables[0].Columns.Contains("客户编码")
|| !ds.Tables[0].Columns.Contains("产品代码") || !ds.Tables[0].Columns.Contains("产品名称") || !ds.Tables[0].Columns.Contains("批量数量")
|| !ds.Tables[0].Columns.Contains("已出库数量") || !ds.Tables[0].Columns.Contains("出库数量") || !ds.Tables[0].Columns.Contains("出库日期"))
{
this.View.Session["ProcessRateValue"] = 100;
ResultErrInfo = "非标准模板,不能执行导入,请使用标准模板进行引人";
this.View.ShowErrMessage(ResultErrInfo);
return;
}
if (ds.Tables.Contains(Kingdee.BOS.Resource.ResManager.LoadKDString("枚举值对应表", "002013000006565", Kingdee.BOS.Resource.SubSystemType.BOS)))
{
ds.Tables.Remove(Kingdee.BOS.Resource.ResManager.LoadKDString("枚举值对应表", "002013000006565", Kingdee.BOS.Resource.SubSystemType.BOS));
}
//获取EXCEL读取的值
exportTotalCount = ds.Tables[0].Rows.Count;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
//获取EXCEL字段的信息,然后绑定信息到构建的简单入库单实体里,然后调保存、提交和审核,这里忽略了这部分实现
}
}
二、构建简单入库单视图,跟入库单实体赋值,并调保存、提交和审核代码参考如下:
//模拟简单生产单保存
IBillView billView = this.CreateObjectView("SP_InStock"); //创建简单生产视图
((IBillViewService)billView).LoadData(); //加载视图数据
// 触发插件的OnLoad事件:
// 组织控制基类插件,在OnLoad事件中,对主业务组织改变是否提示选项进行初始化。
// 如果不触发OnLoad事件,会导致主业务组织赋值不成功
DynamicFormViewPlugInProxy eventProxy = billView.GetService<DynamicFormViewPlugInProxy>();
eventProxy.FireOnLoad();
FillOutStockPropertys(billView,ProductNo,OutStockQty, OutStockCdate);
OperateOption outStocksaveOption = OperateOption.Create();
string InstockErrInfo="";
bool issuccess = this.Saveinportobject(billView, outStocksaveOption, out InstockErrInfo);
/// 创建对象视图
private IBillView CreateObjectView(string objectname)
{
// 读取物料的元数据
FormMetadata meta = MetaDataServiceHelper.Load(this.Context, objectname) as FormMetadata;
// BusinessDataServiceHelper.loa
Form form = meta.BusinessInfo.GetForm();
// 创建用于引入数据的单据view
Type type = Type.GetType("Kingdee.BOS.Web.Import.ImportBillView,Kingdee.BOS.Web");
var billView = (IDynamicFormViewService)Activator.CreateInstance(type);
// 开始初始化billView:
// 创建视图加载参数对象,指定各种参数,如FormId, 视图(LayoutId)等
BillOpenParameter openParam = CreateOpenParameter(meta);
// 动态领域模型服务提供类,通过此类,构建MVC实例
var provider = form.GetFormServiceProvider();
billView.Initialize(openParam, provider);
return billView as IBillView;
}
/// <summary>
/// 创建视图加载参数对象,指定各种初始化视图时,需要指定的属性
/// </summary>
/// <param name="meta">元数据</param>
/// <returns>视图加载参数对象</returns>
private BillOpenParameter CreateOpenParameter(FormMetadata meta)
{
Form form = meta.BusinessInfo.GetForm();
// 指定FormId, LayoutId
BillOpenParameter openParam = new BillOpenParameter(form.Id, meta.GetLayoutInfo().Id);
// 数据库上下文
openParam.Context = this.Context;
// 本单据模型使用的MVC框架
openParam.ServiceName = form.FormServiceName;
// 随机产生一个不重复的PageId,作为视图的标识
openParam.PageId = Guid.NewGuid().ToString();
// 元数据
openParam.FormMetaData = meta;
// 界面状态:新增 (修改、查看)
openParam.Status = OperationStatus.ADDNEW;
// 单据主键:本案例演示新建物料,不需要设置主键
openParam.PkValue = null;
// 界面创建目的:普通无特殊目的 (为工作流、为下推、为复制等)
openParam.CreateFrom = CreateFrom.Default;
// 基础资料分组维度:基础资料允许添加多个分组字段,每个分组字段会有一个分组维度
// 具体分组维度Id,请参阅 form.FormGroups 属性
openParam.GroupId = "";
// 基础资料分组:如果需要为新建的基础资料指定所在分组,请设置此属性
openParam.ParentId = 0;
// 单据类型
openParam.DefaultBillTypeId = "";
// 业务流程
openParam.DefaultBusinessFlowId = "";
// 主业务组织改变时,不用弹出提示界面
openParam.SetCustomParameter("ShowConfirmDialogWhenChangeOrg", false);
// 插件
List<AbstractDynamicFormPlugIn> plugs = form.CreateFormPlugIns();
openParam.SetCustomParameter(FormConst.PlugIns, plugs);
PreOpenFormEventArgs args = new PreOpenFormEventArgs(this.Context, openParam);
foreach (var plug in plugs)
{// 触发插件PreOpenForm事件,供插件确认是否允许打开界面
plug.PreOpenForm(args);
}
if (args.Cancel == true)
{// 插件不允许打开界面
// 本案例不理会插件的诉求,继续....
}
// 返回
return openParam;
}
/// <summary>
/// 把简单生产入库单和导入记录基础资料保存及自动提交和审核
/// </summary>
/// <param name="billView"></param>
private bool Saveinportobject(IBillView billView, OperateOption saveOption, out string errinfo)
{
// 设置FormId
Form form = billView.BillBusinessInfo.GetForm();
var obj = billView.Model.DataObject;
if (form.FormIdDynamicProperty != null)
{
form.FormIdDynamicProperty.SetValue(billView.Model.DataObject, form.Id);
}
// billView.Model.ClearNoDataRow();
string number = "";
string fid = "";
errinfo = "";
IOperationResult saveResult = BusinessDataServiceHelper.Save(this.Context, billView.BillBusinessInfo, billView.Model.DataObject, saveOption, "Save");
if (saveResult.IsSuccess)
{
fid = saveResult.OperateResult[0].PKValue.ToString();
number = saveResult.OperateResult[0].Number.ToString();
// fid = saveResult.OperateResult["Number"].ToString();
IOperationResult submitResult = BusinessDataServiceHelper.Submit(this.Context, billView.BillBusinessInfo, new object[] { fid }, "submit");//保存时自动提交
List<KeyValuePair<object, object>> lstKeyValuePairs = new List<KeyValuePair<object, object>>();
KeyValuePair<object, object> keyValuePair = new KeyValuePair<object, object>(fid, "");
lstKeyValuePairs.Add(keyValuePair);
IOperationResult auditResult = BusinessDataServiceHelper.SetBillStatus(this.Context, billView.BillBusinessInfo, lstKeyValuePairs, null, "Audit"); //保存时自动审核
//sucessinfo = "导入成功,生产入库单号为:" + number;
}
else
{
BusinessDataServiceHelper.Draft(this.Model.Context, billView.BillBusinessInfo, billView.Model.DataObject, saveOption);
var ValidationErrors = string.Join(";", saveResult.ValidationErrors.Select(x => x.Message));
errinfo = ValidationErrors.SubStr(0, 254);
}
return saveResult.IsSuccess;
}
三、调销售出库单下推销售出库单的下推接口
var pushArgs = this.CreatePushArgs(pushOption, SalesNo, TaskNo); //构建下推参数
try
{
var convertResult = ConvertServiceHelper.Push(this.Context, pushArgs, pushOption);//调用下推接口
pushStatus = "成功";
var targetObjs = (from p in convertResult.TargetDataEntities select p.DataEntity).ToArray();//得到目标单据数据包
var targetBInfo = this.GetBusinessInfo(pushArgs.ConvertRule.TargetFormId, pushArgs.ConvertRule.TargetFormMetadata);
// this.ShowTargetForm(targetBInfo, targetObjs);
//对转换结果进行处理
//1. 直接调用保存接口,对数据进行保存
string stockKey = getStocktkey("002");//导入MES的发货单统一入002成品仓
bool isSavesuccess = this.SaveTargetBill(targetBInfo, targetObjs, OutStockQty, stockKey, out outStockSaveError);
}
这就是实现整个过程的思路。
推荐阅读