import clr clr.AddReference("System") clr.AddReference("Kingdee.BOS") clr.AddReference("Kingdee.BOS.Core") clr.AddReference("Kingdee.BOS.DataEntity") clr.AddReference("Kingdee.BOS.App") clr.AddReference("Kingdee.BOS.Contracts") clr.AddReference("Kingdee.BOS.ServiceHelper") from Kingdee.BOS import* from Kingdee.BOS.Contracts import* from Kingdee.BOS.Contracts.Report import* from Kingdee.BOS.Core import * from Kingdee.BOS.Core.Metadata import * from Kingdee.BOS.Core.Report import* from Kingdee.BOS.Core.SqlBuilder import* from Kingdee.BOS.Core.Enums import * from Kingdee.BOS.App.Data import* from Kingdee.BOS.Orm.DataEntity import* from System import* from System.ComponentModel import* from System.Collections.Generic import* from System.Text import* from System.Threading.Tasks import* from Kingdee.BOS.ServiceHelper import * #初始化,在此事件中设置报表的属性全局参数 def Initialize(): this.ReportProperty.ReportType=ReportType.REPORTTYPE_NORMAL; this.IsCreateTempTableByPlugin=True; #是否支持分组汇总,在后面GetSummaryColumnInfo方法中添加汇总字段, #要在BOS中过滤框的汇总页签配置汇总信息,可参考:简单账表分组汇总设置 this.ReportProperty.IsGroupSummary=True; #IsUIDesignerColumns=False,表示报表的列通过插件控制,后续在GetReportHeaders中构建列头 #需要在BOS过滤框的显示隐藏列中维护,字段标识与临时表字段保持一致 #账表列头构建更多详细说明参考:账表列构建 this.ReportProperty.IsUIDesignerColumns=False; #创建临时报表,正式进入账表取数sql拼接并取数,把账表取数结果放到创建的临时表中 #如果参数(this.IsCreateTempTableByPlugin=True),即调用BuilderReportSqlAndTempTable构建临时表 #否则调用以下3个接口,完成账表取数逻辑的sql指令即:BuilderSelectFieldSQL、BuilderTempTableOrderBySQL、BuilderFormWhereSQL #rptfilter:账表参数,可以从这里获取过滤条件等 #tableName:系统自动创建的账表临时表名,具备唯一性,最终报表页面展示的数据绑定此临时表,所以最终的报表结果数据要写入此临时表中 def BuilderReportSqlAndTempTable(rptfilter,tableName): #baseDataTemp=filter.BaseDataTempTable;#基础资料临时表;若设置了数据范围权限,该表会把根据数据范围过滤出来的内码存入临时表; #循环获取所有基础资料数据范围的数据,可用来拼接到报表SQL里面实现数据权限过滤 #for b in baseDataTemp: # baseType=b.BaseDataFormId;#基础资料FormId # PKFldName=b.PKFieldName;#临时表中基础资料主键字段名,例如,FORGID # baseTempTab=b.TempTable;#基础资料数据范围临时表名 #filterStr=filter.FilterParameter.FilterString;#过滤框条件页签过滤表达式 #过滤框快捷过滤页签的实体数据包,从这里面获取自定义的过滤字段值 #DynamicObject类型,用前面讲的实体数据包操作方式取值,用绑定实体属性标识 custFilter = rptfilter.FilterParameter.CustomFilter; if(custFilter==None): return; orgObj=custFilter["F_BPW_OrgId"];#获取组织 whereOrgs=""; if(orgObj != None): orgId=("{0}").format(orgObj["Id"]);#组织ID whereOrgs=(" and a.FPURCHASEORGID in ({0}) ").format(orgId);#选择了组织,拼接组织过滤 materials=custFilter["F_BPW_Materials"];#物料多选过滤 matList=List[str](); if(materials != None): for m in materials: materialNum="'"+str(m["F_BPW_Materials"]["Number"])+"'";#取出过滤框选择的多个物料编码 matList.Add(materialNum); whereMat=(" and m.FNumber in ({0})").format(str.Join(",",matList)) if(matList.Count>0) else "";#拼接物料多选过滤 beginDate=str(custFilter["F_BPW_BeginDate"]);#获取开始日期 EndDate=str(custFilter["F_BPW_EndDate"]);#获取结束日期 beginDate=str(DateTime.Parse(("{0}").format(beginDate)).AddDays(-1));#开始日期的前一天 itemDate=beginDate; fldsSql=List[str]();#动态列头SQL,相当于Select后面的部分字段是动态拼接的,以此来实现动态列 #从开始日期起,循环加1天,一直到结束日期,过滤界面要控制录入的开始日期必须<结束日期,在过滤界面注册表单插件即可实现 while(itemDate != EndDate): myDate=DateTime.Parse(("{0}").format(itemDate)); fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day);#根据每个日期构建唯一的列名 ss=("{0}=SUM(Case when a.FDATE='{1}' then b.FQty else 0 end)").format(fldKey,myDate);#构建每天订单数量合计SQL fldsSql.Add(ss);#将SQL添加到动态列SQL集合中备用 nextDate=myDate.AddDays(1); itemDate=str(nextDate);#迭代+1天 myDate=DateTime.Parse(("{0}").format(itemDate));#这里是选择的截止日期,由于循环到最后一天跳出了,这里补充一天的数据 fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day); ss=("{0}=SUM(Case when a.FDATE='{1}' then b.FQty else 0 end)").format(fldKey,myDate); fldsSql.Add(ss);#将SQL添加到动态列SQL集合中备用 #raise Exception(str.Join(',',fldsSql));#调试时,可用此行代码,看看构建的动态列SQL对不对 #组装最终写入报表临时表的SQL #注意!!!: 最终临时表一定要有FIDENTITYID ,要从1开始,且不重复 ,不断号,不然前台显示空白!!!! sql=("""/*dialect*/?select row_Number() Over(order by a.orgName,a.MaterialNum) FIDENTITYID, a.* into {0} from (select orgL.FNAME orgName,m.FNUMBER MaterialNum,mL.FNAME materialName,mL.FSPECIFICATION SpecNum,unitL.FNAME unit, {1} from t_PUR_POOrder a inner join T_ORG_ORGANIZATIONS org on org.FORGID=a.FPURCHASEORGID inner join T_ORG_ORGANIZATIONS_L orgL on orgL.FORGID=org.FORGID and orgL.FLOCALEID=2052 inner join t_PUR_POOrderEntry b on a.FID=b.FID inner join T_BD_MATERIAL m on m.FMATERIALID=b.FMATERIALID inner join T_BD_MATERIAL_L mL on mL.FMATERIALID=m.FMATERIALID and mL.FLOCALEID=2052 inner Join T_BD_UNIT_L unitL on unitL.FUNITID=b.FUNITID and unitL.FLOCALEID=2052 where a.FDATE>='{3}' and a.FDATE<='{4}' {2} {5} group by orgL.FNAME,m.FNUMBER,mL.FNAME,mL.FSPECIFICATION,unitL.FNAME ) a """).format(tableName,str.Join(',',fldsSql),whereOrgs,beginDate,EndDate,whereMat); #raise Exception(sql);#可以通过此方法弹出Sql语句进行调试验证 DBUtils.Execute(this.Context,sql);#执行SQL,将报表数据写入临时表 #构建账表列头 def GetReportHeaders(Filter): header=ReportHeader(); localEid=this.Context.UserLocale.LCID;#获取当前语言环境代码,中文为2052 header.AddChild("orgName",LocaleValue("采购组织",localEid));#字段名,列头标题,字段名与临时表中的字段名保持对应,相当于每一个列头对应临时表的哪个字段 header.AddChild("MaterialNum",LocaleValue("物料编码",localEid)); header.AddChild("materialName",LocaleValue("物料名称",localEid)); header.AddChild("SpecNum",LocaleValue("规格型号",localEid)); header.AddChild("unit",LocaleValue("采购单位",localEid)); #下面根据过滤条件选择的日期区间,动态构建列头,和上面构建SQL字段的逻辑类似 custFilter = Filter.FilterParameter.CustomFilter; beginDate=str(custFilter["F_BPW_BeginDate"]);#获取开始日期 EndDate=str(custFilter["F_BPW_EndDate"]);#获取结束日期 itemDate=beginDate; fldsSql=List[str](); while(itemDate != EndDate): myDate=DateTime.Parse(("{0}").format(itemDate)); fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day);#这里的字段名要和前面构建的SQL字段对应 header.AddChild(fldKey,LocaleValue(str(("{0}-{1}-{2}").format(myDate.Year,myDate.Month,myDate.Day)),localEid),SqlStorageType.SqlDecimal); nextDate=myDate.AddDays(1); itemDate=str(nextDate); myDate=DateTime.Parse(("{0}").format(itemDate)); fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day);#这里的字段名要和前面构建的SQL字段对应 header.AddChild(fldKey,LocaleValue(str(("{0}-{1}-{2}").format(myDate.Year,myDate.Month,myDate.Day)),localEid),SqlStorageType.SqlDecimal); #设置列的索引,使其可以按照以上列头构建的顺序显示 colIndex=0; for child in header.GetChilds(): if(child.GetChildCount()==0): child.ColIndex=colIndex; colIndex=colIndex+1; else: child.ColIndex = colIndex; colIndex=colIndex+1; for childHeader in child.GetChilds(): childHeader.ColIndex=colIndex; colIndex=colIndex+1; return header; #设置报表表头字段值 #这里主要是把过滤框设置的字段值,显示到报表表头 def GetReportTitles(Filter): reportTitles=ReportTitles(); custFilter=Filter.FilterParameter.CustomFilter;#获取过滤框的数据包 orgObj=custFilter["F_BPW_OrgId"];#获取组织 beginDate=str(custFilter["F_BPW_BeginDate"]);#获取开始日期 EndDate=str(custFilter["F_BPW_EndDate"]);#获取结束日期 if(orgObj != None): reportTitles.AddTitle("F_BPW_OrgId", orgObj["Name"]); reportTitles.AddTitle("F_BPW_BeginDate", beginDate); reportTitles.AddTitle("F_BPW_EndDate", EndDate); return reportTitles; #设置报表底部合计列 def GetSummaryColumnInfo(rptfilter): result=List[SummaryField](); #由于这里的数量字段是动态构建的,所以也需要动态添加合计列,字段名与前面保持一致 custFilter = rptfilter.FilterParameter.CustomFilter; beginDate=str(custFilter["F_BPW_BeginDate"]);#获取开始日期 EndDate=str(custFilter["F_BPW_EndDate"]);#获取结束日期 itemDate=beginDate; fldsSql=List[str](); while(itemDate != EndDate): myDate=DateTime.Parse(("{0}").format(itemDate)); fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day);#这里的字段名要和前面构建的SQL字段对应 result.Add(SummaryField(fldKey,BOSEnums.Enu_SummaryType.SUM)); nextDate=myDate.AddDays(1); itemDate=str(nextDate); myDate=DateTime.Parse(("{0}").format(itemDate)); fldKey=("F{0}_{1}_{2}").format(myDate.Year,myDate.Month,myDate.Day); result.Add(SummaryField(fldKey,BOSEnums.Enu_SummaryType.SUM)); return result; #报表关闭触发,通常在此处清理报表过程产生的临时表 def CloseReport(): this.DropTempTable();