二开案例.执行计划.获取并保存账表数据
【应用场景】需要周期性的将账表在某个过滤方案下的所有数据保存起来,提供给第三方应用使用。
【案例演示】实现一个定时任务,定期将存货收发存汇总表和存货收发存汇总表的指定过滤方案下的数据存储到指定的表中。
执行计划入门演示可参考:
【二开案例.执行计划.从零开发执行计划】https://vip.kingdee.com/article/109330633939560192
【注意】此案例代码仅适用于简单账表,不适用于分页账表。
【实现步骤】
<1>编写执行计划,代码如下。
using Kingdee.BOS; using Kingdee.BOS.App.Core; using Kingdee.BOS.App.Data; using Kingdee.BOS.Contracts; using Kingdee.BOS.Core; using Kingdee.BOS.Core.DynamicForm; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.Core.Report; using Kingdee.BOS.Log; using Kingdee.BOS.Model.ReportFilter; using Kingdee.BOS.Orm.DataEntity; using Kingdee.BOS.Serialization; using Kingdee.BOS.Util; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; namespace Jac.XkDemo.BOS.App.PlugIn { /// <summary> /// 【执行计划】获取并保存账表数据 /// https://vip.kingdee.com/article/109345564135072000 /// </summary> public class GetReportDataScheduleService : IScheduleService { /// <summary> /// 执行计划 /// </summary> /// <param name="ctx"></param> /// <param name="schedule"></param> public void Run(Context ctx, Schedule schedule) { if (schedule.Parameters.IsNullOrEmpty()) { return; } var parameters = JsonConvert.DeserializeObject<List<RptHelper.SaveReportDataParameter>>(schedule.Parameters); foreach (var parameter in parameters) { try { RptHelper.SaveReportData(ctx, parameter); } catch (Exception ex) { var errMsg = string.Format("读取报表数据异常:{0}", JsonConvert.SerializeObject(parameter)); Logger.Error("Jac", errMsg, ex); } } } } /// <summary> /// 账表辅助类 /// </summary> public class RptHelper { #region method /// <summary> /// 保存账表数据 /// </summary> /// <param name="scheduleCtx">上下文</param> /// <param name="parameter">保存账表数据参数</param> /// <param name="typeId"></param> public static void SaveReportData(Context scheduleCtx, SaveReportDataParameter parameter, string typeId = "0") { var ctx = GetContext(scheduleCtx, parameter.UserName); // 读取账表数据(存货收发存汇总表) var reportData = GetReportData(ctx, parameter); // 将账表数据保存到指定的表中 #region 方式1:直接在数据库拷贝一份,如果不再加工数据,推荐用此方式 if (typeId == "0") { var sql = string.Format(@"/*dialect*/ IF EXISTS(SELECT * FROM sys.objects WHERE object_id=OBJECT_ID(N'{0}') AND type IN (N'U')) DROP TABLE {0} SELECT * INTO {0} FROM {1}", parameter.TableName, reportData.DataSource.TableName); DBUtils.Execute(ctx, sql); } #endregion #region 方式2:使用内存表批量插入数据库 else if (typeId == "1") { // 创建临时表 var createTableSql = BuildCreateTableSql(reportData.DataSource, parameter.TableName); DBUtils.Execute(ctx, createTableSql); // 将账表数据存入临时表 var dataSource = reportData.DataSource.Clone(); dataSource.TableName = parameter.TableName; foreach (DataRow row in reportData.DataSource.Rows) { dataSource.Rows.Add(row.ItemArray); } DBUtils.BulkInserts(ctx, dataSource); } #endregion } /// <summary> /// 获取简单账表数据 /// </summary> /// <param name="ctx">上下文</param> /// <param name="parameter">账表数据保存参数</param> /// <returns></returns> public static IReportData GetReportData(Context ctx, SaveReportDataParameter parameter) { var metaDataService = new MetaDataService(); var filterMetadata = new CommonFilterService().GetFilterMetaData(ctx, ""); //加载过滤元数据。 var reportMetadata = (FormMetadata)metaDataService.Load(ctx, parameter.RptFormId); //加载账表元数据 var reportFilterMetadata = (FormMetadata)metaDataService.Load(ctx, parameter.RptFilterFormId); //加载账表的过滤窗体的元数据。 var reportFilterServiceProvider = reportFilterMetadata.BusinessInfo.GetForm().GetFormServiceProvider(); var model = new SysReportFilterModel(); model.SetContext(ctx, reportFilterMetadata.BusinessInfo, reportFilterServiceProvider); model.FormId = reportFilterMetadata.BusinessInfo.GetForm().Id; model.FilterObject.FilterMetaData = filterMetadata; model.InitFieldList(reportMetadata, reportFilterMetadata); model.GetSchemeList(); var entity = model.Load(parameter.SchemeId); var dyn = DeserializeCustomFilter(reportFilterMetadata.BusinessInfo, entity.CustomFilterSetting); model.DataObject = dyn; var filter = model.GetFilterParameter(); IRptParams rptParams = new RptParams(); rptParams.FormId = reportMetadata.BusinessInfo.GetForm().Id; rptParams.FilterParameter = filter; rptParams.FilterFieldInfo = model.FilterFieldInfo; rptParams.ParameterData = GetUserParamters(ctx, reportMetadata.BusinessInfo); rptParams.IsOnlyQuerySumData = GetOnlyDspSumData(rptParams.ParameterData); rptParams.CurrentPosition = 0; rptParams.StartRow = 1; rptParams.EndRow = int.MaxValue; var param = new ReportServiceParameter(ctx, reportMetadata.BusinessInfo, Guid.NewGuid().ToString(), rptParams); return new SysReportService().GetReportData(param); } /// <summary> /// 获取指定用户上下文 /// </summary> /// <param name="ctx">上下文</param> /// <param name="userName">用户名</param> /// <returns></returns> public static Context GetContext(Context ctx, string userName) { if (userName.IsNullOrEmpty()) { return ctx; } var userId = DBUtils.ExecuteScalar(ctx, string.Format("SELECT FUSERID FROM T_SEC_USER WHERE FNAME='{0}'", userName), 0); if (userId <= 0) { return ctx; } var newCtx = (Context)ctx.Clone(); newCtx.UserId = userId; newCtx.UserName = userName; return newCtx; } /// <summary> /// 获取过滤窗体的自定义参数 /// </summary> /// <param name="businessInfo">过滤窗体元数据</param> /// <param name="xml">自定义过滤参数XML</param> /// <returns></returns> private static DynamicObject DeserializeCustomFilter(BusinessInfo businessInfo, string xml) { var binder = new DynamicObjectDcxmlBinder(businessInfo); binder.OnlyDbProperty = false; var target = new DcxmlSerializer(binder); binder.Culture = CultureInfo.InvariantCulture; target.ColloctionIgnorePKValue = true; var obj = (DynamicObject)target.DeserializeFromString(xml); return obj; } /// <summary> /// 获取账表的用户参数 /// </summary> /// <param name="ctx">上下文</param> /// <param name="reportBusinessInfo"></param> /// <returns></returns> private static DynamicObject GetUserParamters(Context ctx, BusinessInfo reportBusinessInfo) { string formId = reportBusinessInfo.GetForm().ParameterObjectId; if (formId == null || formId.Trim().Length == 0) { formId = FormIdConst.BOS_ReportUserParameter; } var formMetadata = (FormMetadata)new MetaDataService().Load(ctx, formId); return new UserParameterService().Load(ctx, formMetadata.BusinessInfo, ctx.UserId, reportBusinessInfo.GetForm().Id); } /// <summary> /// 用户参数是否仅显示汇总 /// </summary> /// <returns></returns> private static bool GetOnlyDspSumData(DynamicObject userParameterData) { var result = false; if (userParameterData != null && userParameterData.DynamicObjectType.Properties.ContainsKey(KeyConst.FDSPSUMDATA_KEY)) { result = (bool)userParameterData[KeyConst.FDSPSUMDATA_KEY]; } return result; } /// <summary> /// 根据DataTable构建建表脚本 /// </summary> /// <param name="dt"></param> /// <param name="tableName"></param> /// <returns></returns> public static string BuildCreateTableSql(DataTable dt, string tableName) { var columnInfos = GetColumnInfos(dt); var sql = string.Format(@"/*dialect*/ IF EXISTS(SELECT * FROM sys.objects WHERE object_id=OBJECT_ID(N'{0}') AND type IN (N'U')) DROP TABLE {0} CREATE TABLE {0} ({1})", tableName, string.Join(",", columnInfos.Select(o => o.Item1 + " " + o.Item2))); return sql; } /// <summary> /// 根据DataTable生成创建列脚本 /// </summary> /// <param name="dt"></param> /// <returns></returns> private static List<Tuple<string, string>> GetColumnInfos(DataTable dt) { var list = new List<Tuple<string, string>>(); foreach (DataColumn column in dt.Columns) { list.Add(new Tuple<string, string>(column.ColumnName, GetDbType(column.DataType))); } return list; } /// <summary> /// 根据数据类型倒推字段的数据库类型 /// </summary> /// <param name="type"></param> /// <returns></returns> private static string GetDbType(Type type) { if (type == typeof(int) || type == typeof(short)) { return "INT"; } if (type == typeof(long)) { return "BIGINT"; } if (type == typeof(decimal) || type == typeof(float) || type == typeof(double)) { return "DECIMAL(23,10)"; } if (type == typeof(bool)) { return "BIT"; } if (type == typeof(DateTime)) { return "DATETIME"; } if (type == typeof(byte[])) { return "IMAGE"; } return "NVARCHAR(4000)"; } #endregion #region class /// <summary> /// 账表数据保存参数 /// </summary> public class SaveReportDataParameter { /// <summary> /// 用户名(登录账号) /// </summary> public string UserName { get; set; } /// <summary> /// 账表FormId /// </summary> public string RptFormId { get; set; } /// <summary> /// 账表的过滤窗体的FormId /// </summary> public string RptFilterFormId { get; set; } /// <summary> /// 过滤方案内码 /// </summary> public string SchemeId { get; set; } /// <summary> /// 存储账表数据的表名 /// </summary> public string TableName { get; set; } } #endregion } } /* -- 获取存货收发存汇总表下的demo用户的某个过滤方案 SELECT * FROM T_BAS_FILTERSCHEME WHERE FFORMID='HS_INOUTSTOCKSUMMARYRPT' AND FUSERID=100008 -- 获取指定用户的UserID SELECT FUSERID FROM T_SEC_USER WHERE FNAME='demo' */
<2>拷贝插件组件到应用站点的WebSite\Bin目录下,重启IIS。
<3>登录业务站点,打开【执行计划列表】,新增执行计划,如下图所示,保存,开发完毕。
主菜单上点击【测试】,即可马上启动执行计划。
【案例解说】
服务插件:Jac.XkDemo.BOS.App.PlugIn.GetReportDataScheduleService,Jac.XkDemo.BOS.App.PlugIn
逗号前半部分是执行计划实现类的类型全名(含命名空间),逗号后半部分是执行计划实现类所在程序集名称(项目名称)。
执行计划参数(基于SaveReportDataParameter对象序列化而来,各属性的含义可参考类型定义中的说明):
[{
"UserName": "demo",
"RptFormId": "HS_INOUTSTOCKSUMMARYRPT",
"RptFilterFormId": "HS_INOUTSTOCKSUMMARYFILTER",
"SchemeId": "5d42a0bc94827b",
"TableName": "存货收发存汇总表"
},
{
"UserName": "demo",
"RptFormId": "PUR_PurchaseOrderDetailRpt",
"RptFilterFormId": "PUR_RPT_PurchaseOrderExecuteFilter",
"SchemeId": "5f69afc0dc99e5",
"TableName": "采购订单执行明细表"
}]
此参数的含义是:用demo用户的身份去获取存货收发存汇总表的指定过滤方案的报表数据并存入表【存货收发存汇总表】中;用demo用户的身份去获取采购订单执行明细表的指定过滤方案的报表数据并存入表【采购订单执行明细表】中。
【存货收发存汇总表】FormId获取方式:
【采购订单执行明细表】FormId获取方式:
账表的过滤方案内码获取方式:
先登录业务站点配置好账表的过滤方案:
再去数据库查询过滤方案内码:
查询【存货收发存汇总表】的过滤方案【test】的内码
查询【采购订单执行明细表】的过滤方案【test】的内码
验证执行计划是否正确执行:
先查下业务站点下的对应报表的指定过滤方案的数据:
再去数据库查下新保存的账表数据和界面上看到的数据是否一致:
验证通过后,开发就正式完成啦,后台Job会按照我们设置好的执行频率,定期执行该执行计划,完成报表数据的转储。
【金蝶云星空BOS二次开发案例演示】https://vip.kingdee.com/article/94751030918525696
二开案例.执行计划.获取并保存账表数据
本文2024-09-23 04:00:52发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-162553.html