using System; using System.Collections.Generic; using System.Linq; using System.Text; using Kingdee.K3.Core.MFG.EntityHelper; using Kingdee.K3.FIN.App.Core; using System.ComponentModel; using Kingdee.BOS; using Kingdee.BOS.Util; using Kingdee.BOS.Core; using Kingdee.BOS.Core.Const; using Kingdee.BOS.Core.DynamicForm; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Core.DynamicForm.Operation; using Kingdee.BOS.Core.List; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.Core.Metadata.ConvertElement; using Kingdee.BOS.Core.Metadata.ConvertElement.ServiceArgs; using Kingdee.BOS.Core.Interaction; using Kingdee.BOS.Core.Validation; using Kingdee.BOS.Contracts; using Kingdee.BOS.App; using Kingdee.BOS.Orm; using Kingdee.BOS.Orm.DataEntity; using Kingdee.BOS.App.Data; using System.Data; using System.Collections; using Kingdee.BOS.Core.Metadata.EntityElement; namespace aoyuPlugIn { //其他出库单审核时自动生成其他出库单,在审核操作的服务插件中 [Description("自动生成其他入库单")]//自动下推生产审核的调入调出单STK_MISCELLANEOUS public class MJ_xtqtrk : AbstractOperationServicePlugIn { private string entityKey = "FEntity";//其他出库单单据标识 int rowIndex; string scddfid; int scddRow; //public override void OnPreparePropertys(PreparePropertysEventArgs e) //{ // base.OnPreparePropertys(e); // e.FieldKeys.Add("F_QBOY_JKDH");//缴库单号 // e.FieldKeys.Add("F_QBOY_YDEntryID");//生产订单单据体ID // e.FieldKeys.Add("F_QBOY_YDHH");//生产订单行号 // e.FieldKeys.Add("F_QBOY_SKYTLed");//已退量 // e.FieldKeys.Add("F_QBOY_SKL");//水口量 // e.FieldKeys.Add("F_QBOY_SKYTL");//应退量 //} /// /// 审核操作完成,单据状态已经更改,但是还没有提交事务时,触发此事件: /// /// /// /// 因为此事件触发时,还在事务保护中,因此适合进行数据同步; /// 审核后自动下推,如果下推失败,需要放弃审核,因此,放在此事件中处理(事务中) /// public override void EndOperationTransaction(EndOperationTransactionArgs e) { Entity entityObj = this.BusinessInfo.GetEntity(entityKey); foreach (DynamicObject d in e.DataEntitys) { if (d["BillEntry"] == null) { return; } DynamicObjectCollection FentryRow = d["BillEntry"] as DynamicObjectCollection; //scddfid = FentryRow[0][7].ToString();//生产订单单据体ID //scddRow = Convert.ToInt32(FentryRow[0][6]);//生产订单行号 //if (Convert.ToDouble(FentryRow[0][5]) + Convert.ToDouble(FentryRow[0][4]) < Convert.ToDouble(FentryRow[0][3])) //{ // return; //} //String sSql2 = String.Format(@" select FID FROM T_PRD_MO where FBILLNO='{0}' ", FentryRow[0][2]); //DynamicObjectCollection dr = DBUtils.ExecuteDynamicObject(this.Context, sSql2); this.DoPush("STK_MisDelivery", "STK_MISCELLANEOUS", (from p in e.DataEntitys select Convert.ToInt64(p[0])).ToList(), e); //using (IDataReader dr = DBUtils.ExecuteReader(this.Context, sSql2)) //{ // while (dr.Read()) // { // var scddfid = Convert.ToInt64(dr["F_PCDN_INMD"]); // //this.DoPush("k246ba461a1494a348dc7c9996f609b60", "PRD_INSTOCK", // // (from p in e.DataEntitys select Convert.ToInt64(p[0])).ToList(), e); // } // dr.Close(); //} } } //this.DoPush("k246ba461a1494a348dc7c9996f609b60", "PRD_INSTOCK", // (from p in e.DataEntitys select Convert.ToInt64(p[0])).ToList(), e); /// /// 自动下推并保存 /// /// 源单FormId /// 目标单FormId /// 源单内码 private void DoPush(string sourceFormId, string targetFormId, List sourceBillIds, EndOperationTransactionArgs e) { // 获取源单与目标单的转换规则 IConvertService convertService = ServiceHelper.GetService(); var rules = convertService.GetConvertRules(this.Context, sourceFormId, targetFormId); if (rules == null || rules.Count == 0) { throw new KDBusinessException("", string.Format("未找到{0}到{1}之间,启用的转换规则,无法自动下推!", sourceFormId, targetFormId)); } // 取勾选了默认选项的规则 // var rule = rules.FirstOrDefault(t => t.IsDefault); // 如果无默认规则,则取第一个 // if (rule == null) //{ // rule = rules[0]; // } //门店至运营中心,或运营中心至门店 //if (true && rules.Count > 0) if (true && rules.Count > 1) { //var rule = rules[0]; var rule = rules[1]; // 开始构建下推参数: // 待下推的源单数据行 List srcSelectedRows = new List(); foreach (var billId in sourceBillIds) {// 把待下推的源单内码,逐个创建ListSelectedRow对象,添加到集合中 srcSelectedRows.Add(new ListSelectedRow(billId.ToString(), string.Empty, 0, sourceFormId)); // 特别说明:上述代码,是整单下推; // 如果需要指定待下推的单据体行,请参照下句代码,在ListSelectedRow中,指定EntryEntityKey以及EntryId //srcSelectedRows.Add(new ListSelectedRow(billId.ToString(), entityId, 0, sourceFormId) { EntryEntityKey = "FEntity" }); } // 指定目标单单据类型:情况比较复杂,没有合适的案例做参照,示例代码暂略,直接留空,会下推到默认的单据类型 string targetBillTypeId = string.Empty; // 指定目标单据主业务组织:情况更加复杂,需要涉及到业务委托关系,缺少合适案例,示例代码暂略 // 建议在转换规则中,配置好主业务组织字段的映射关系:运行时,由系统根据映射关系,自动从上游单据取主业务组织,避免由插件指定 long targetOrgId = 0; // 自定义参数字典:把一些自定义参数,传递到转换插件中;转换插件再根据这些参数,进行特定处理 Dictionary custParams = new Dictionary(); // 组装下推参数对象 PushArgs pushArgs = new PushArgs(rule, srcSelectedRows.ToArray()) { TargetBillTypeId = targetBillTypeId, TargetOrgId = targetOrgId, CustomParams = custParams }; OperateOption option = OperateOption.Create(); option.SetVariableValue(BOSConst.CST_ConvertValidatePermission, true); // 调用下推服务,生成下游单据数据包 ConvertOperationResult convResult = convertService.Push(this.Context, pushArgs, OperateOption.Create()); // 开始处理下推结果: // 获取下推生成的下游单据数据包 DynamicObject[] destObjs = (from p in convResult.TargetDataEntities select p.DataEntity).ToArray(); if (destObjs.Length == 0) { // 未下推成功目标单,抛出错误,中断审核 throw new KDBusinessException("", string.Format("由{0}自动下推{1},没有成功生成数据包,自动下推失败!", sourceFormId, targetFormId)); } // 对下游单据数据包,进行适当的修订,以避免关键字段为空,自动保存失败 // 示例代码略 // 读取目标单据元数据 IMetaDataService metaService = ServiceHelper.GetService(); FormMetadata destFormMetadata = metaService.Load(this.Context, targetFormId) as FormMetadata; // 构建保存操作参数:设置操作选项值,忽略交互提示 OperateOption saveOption = OperateOption.Create(); // 忽略全部需要交互性质的提示,直接保存; saveOption.SetIgnoreWarning(true); // 忽略交互提示 saveOption.SetInteractionFlag(this.Option.GetInteractionFlag()); // 如果有交互,传入用户选择的交互结果 // using Kingdee.BOS.Core.Interaction; saveOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag()); // 上一步操作成功的目标单 List lastSuccessIdLst = new List(); // 本操作成功的目标单 List successIdLst = new List(); // 操作失败的目标单 List failedobjs = new List(); // 操作结果 IOperationResult result = new OperationResult(); // 错误信息 List errorLst = new List(); ////////////////////////////// 暂存 ////////////////////////////// IDraftService service = Kingdee.BOS.Contracts.ServiceFactory.GetService(this.Context); IOperationResult innerResult = service.Draft(this.Context, destFormMetadata.BusinessInfo, destObjs); // 暂存成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 暂存不通过的目标单 failedobjs = destObjs.Where(o => !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "DraftError", string.Format("{0}暂存失败:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } // 暂存不通过,则操作失败 if (successIdLst.IsEmpty()) { result.IsSuccess = false; } e.DataEntitys = e.DataEntitys.Where(o => successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToArray(); ////////////////////////////// 保存 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; innerResult = AppServiceContext.SaveService.Save(this.Context, destFormMetadata.BusinessInfo, destObjs.Where(o => successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToArray(), option); // 保存成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 校验不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "SaveError", string.Format("{0}保存失败,已暂存:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 提交 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; innerResult = AppServiceContext.SubmitService.Submit(this.Context, destFormMetadata.BusinessInfo, successIdLst.ToArray(), "Submit", option); // 提交成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 校验不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "SubmitError", string.Format("{0}提交失败,已保存:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 审核 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; List> pkIds = new List>(); foreach (var o in successIdLst) { pkIds.Add(new KeyValuePair(o, "")); } //审核 List paraAudit = new List(); //1审核通过 paraAudit.Add("1"); //审核意见 paraAudit.Add(""); innerResult = AppServiceContext.SetStatusService.SetBillStatus(this.Context, destFormMetadata.BusinessInfo, pkIds, paraAudit, "Audit", option); // 审核成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 审核不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "AuditError", string.Format("{0}审核失败,已提交:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 构造错误信息 ////////////////////////////// if (!errorLst.IsNullOrEmpty()) { result.ValidationErrors.AddRange(errorLst); } // 将操作结果合并到空操作结果中 this.OperationResult.IsSuccess = result.IsSuccess; if (!this.OperationResult.IsSuccess) { this.OperationResult.ValidationErrors.Add(new ValidationErrorInfo("", "Id", 0, 0, "Error", string.Format("自动转换失败"), "", ErrorLevel.Error)); } // 调用保存服务,自动保存 // ISaveService saveService = ServiceHelper.GetService(); // var saveResult = saveService.Save(this.Context, targetBillMeta.BusinessInfo, targetBillObjs, saveOption, "Save"); // 判断自动保存结果:只有操作成功,才会继续 // if (!this.CheckOpResult(saveResult, saveOption)) // { // throw new KDBusinessException("", string.Format("由{0}自动下推{1},自动下推失败!", sourceFormId, targetFormId)); // } } //if (true && rules.Count > 1) if (true && rules.Count > 0) { //var rule = rules[1]; var rule = rules[0]; // 开始构建下推参数: // 待下推的源单数据行 // 开始构建下推参数: // 待下推的源单数据行 List srcSelectedRows = new List(); foreach (var billId in sourceBillIds) {// 把待下推的源单内码,逐个创建ListSelectedRow对象,添加到集合中 srcSelectedRows.Add(new ListSelectedRow(billId.ToString(), string.Empty, 0, sourceFormId)); // 特别说明:上述代码,是整单下推; // 如果需要指定待下推的单据体行,请参照下句代码,在ListSelectedRow中,指定EntryEntityKey以及EntryId //srcSelectedRows.Add(new ListSelectedRow(billId.ToString(), scddfid, 0, sourceFormId) { EntryEntityKey = "FTreeEntity" }); //srcSelectedRows.Add(new ListSelectedRow(billId.ToString(), entityId, 0, sourceFormId) { EntryEntityKey = "FEntity" }); } // 指定目标单单据类型:情况比较复杂,没有合适的案例做参照,示例代码暂略,直接留空,会下推到默认的单据类型 string targetBillTypeId = string.Empty; // 指定目标单据主业务组织:情况更加复杂,需要涉及到业务委托关系,缺少合适案例,示例代码暂略 // 建议在转换规则中,配置好主业务组织字段的映射关系:运行时,由系统根据映射关系,自动从上游单据取主业务组织,避免由插件指定 long targetOrgId = 0; // 自定义参数字典:把一些自定义参数,传递到转换插件中;转换插件再根据这些参数,进行特定处理 Dictionary custParams = new Dictionary(); // 组装下推参数对象 PushArgs pushArgs = new PushArgs(rule, srcSelectedRows.ToArray()) { TargetBillTypeId = targetBillTypeId, TargetOrgId = targetOrgId, CustomParams = custParams }; OperateOption option = OperateOption.Create(); option.SetVariableValue(BOSConst.CST_ConvertValidatePermission, true); // 调用下推服务,生成下游单据数据包 ConvertOperationResult convResult = convertService.Push(this.Context, pushArgs, OperateOption.Create()); // 开始处理下推结果: // 获取下推生成的下游单据数据包 DynamicObject[] destObjs = (from p in convResult.TargetDataEntities select p.DataEntity).ToArray(); if (destObjs.Length == 0) { // 未下推成功目标单,抛出错误,中断审核 throw new KDBusinessException("", string.Format("由{0}自动下推{1},没有成功生成数据包,自动下推失败!", sourceFormId, targetFormId)); } // 对下游单据数据包,进行适当的修订,以避免关键字段为空,自动保存失败 // 示例代码略 // 读取目标单据元数据 IMetaDataService metaService = ServiceHelper.GetService(); FormMetadata destFormMetadata = metaService.Load(this.Context, targetFormId) as FormMetadata; // 构建保存操作参数:设置操作选项值,忽略交互提示 OperateOption saveOption = OperateOption.Create(); // 忽略全部需要交互性质的提示,直接保存; saveOption.SetIgnoreWarning(true); // 忽略交互提示 saveOption.SetInteractionFlag(this.Option.GetInteractionFlag()); // 如果有交互,传入用户选择的交互结果 // using Kingdee.BOS.Core.Interaction; saveOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag()); // 上一步操作成功的目标单 List lastSuccessIdLst = new List(); // 本操作成功的目标单 List successIdLst = new List(); // 操作失败的目标单 List failedobjs = new List(); // 操作结果 IOperationResult result = new OperationResult(); // 错误信息 List errorLst = new List(); ////////////////////////////// 暂存 ////////////////////////////// IDraftService service = Kingdee.BOS.Contracts.ServiceFactory.GetService(this.Context); IOperationResult innerResult = service.Draft(this.Context, destFormMetadata.BusinessInfo, destObjs); // 暂存成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 暂存不通过的目标单 failedobjs = destObjs.Where(o => !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "DraftError", string.Format("{0}暂存失败:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } // 暂存不通过,则操作失败 if (successIdLst.IsEmpty()) { result.IsSuccess = false; } e.DataEntitys = e.DataEntitys.Where(o => successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToArray(); ////////////////////////////// 保存 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; innerResult = AppServiceContext.SaveService.Save(this.Context, destFormMetadata.BusinessInfo, destObjs.Where(o => successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToArray(), option); // 保存成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 校验不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "SaveError", string.Format("{0}保存失败,已暂存:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 提交 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; innerResult = AppServiceContext.SubmitService.Submit(this.Context, destFormMetadata.BusinessInfo, successIdLst.ToArray(), "Submit", option); // 提交成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 校验不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "SubmitError", string.Format("{0}提交失败,已保存:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 审核 ////////////////////////////// if (!successIdLst.IsEmpty()) { lastSuccessIdLst = successIdLst; List> pkIds = new List>(); foreach (var o in successIdLst) { pkIds.Add(new KeyValuePair(o, "")); } //审核 List paraAudit = new List(); //1审核通过 paraAudit.Add("1"); //审核意见 paraAudit.Add(""); innerResult = AppServiceContext.SetStatusService.SetBillStatus(this.Context, destFormMetadata.BusinessInfo, pkIds, paraAudit, "Audit", option); // 审核成功的目标单 successIdLst = innerResult.OperateResult.Select(o => o.PKValue).Distinct().ToList(); // 审核不通过的目标单 failedobjs = destObjs.Where(o => lastSuccessIdLst.Contains(o.GetDynamicObjectItemValue("Id")) && !successIdLst.Contains(o.GetDynamicObjectItemValue("Id"))).ToList(); if (failedobjs != null && !failedobjs.IsEmpty()) { errorLst.Add(new ValidationErrorInfo("", "Id", 0, 0, "AuditError", string.Format("{0}审核失败,已提交:{1}", string.Join(",", failedobjs.Select(o => o.GetDynamicObjectItemValue("BillNo"))), string.Join("\n", innerResult.ValidationErrors.Select(o => o.Message))), "", ErrorLevel.Error)); } } ////////////////////////////// 构造错误信息 ////////////////////////////// if (!errorLst.IsNullOrEmpty()) { result.ValidationErrors.AddRange(errorLst); } // 将操作结果合并到空操作结果中 this.OperationResult.IsSuccess = result.IsSuccess; if (!this.OperationResult.IsSuccess) { this.OperationResult.ValidationErrors.Add(new ValidationErrorInfo("", "Id", 0, 0, "Error", string.Format("自动转换失败"), "", ErrorLevel.Error)); } } return; } /// /// 判断操作结果是否成功,如果不成功,则直接抛错中断进程 /// /// 操作结果 /// 操作参数 /// private bool CheckOpResult(IOperationResult opResult, OperateOption opOption) { bool isSuccess = false; if (opResult.IsSuccess == true) { // 操作成功 isSuccess = true; } else { if (opResult.InteractionContext != null && opResult.InteractionContext.Option.GetInteractionFlag().Count > 0) {// 有交互性提示 // 传出交互提示完整信息对象 this.OperationResult.InteractionContext = opResult.InteractionContext; // 传出本次交互的标识, // 用户在确认继续后,会重新进入操作; // 将以此标识取本交互是否已经确认过,避免重复交互 this.OperationResult.Sponsor = opResult.Sponsor; // 抛出交互错误,把交互信息传递给前端 new KDInteractionException(opOption, opResult.Sponsor); } else { // 操作失败,拼接失败原因,然后抛出中断 opResult.MergeValidateErrors(); if (opResult.OperateResult == null) {// 未知原因导致提交失败 throw new KDBusinessException("", "未知原因导致自动提交、审核失败!"); } else { StringBuilder sb = new StringBuilder(); sb.AppendLine("自动操作失败:"); foreach (var operateResult in opResult.OperateResult) { sb.AppendLine(operateResult.Message); } throw new KDBusinessException("", sb.ToString()); } } } return isSuccess; } } }