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") clr.AddReference("ExtensionMethods") # clr.AddReference("K3CExttensionMethods") 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 * from ExtensionMethods import BooleanExtension as boolObjEx from ExtensionMethods import DateTimeExtension as dateObjEx from ExtensionMethods import ObjectExtension as objEx from ExtensionMethods import StringExtension as strObjEx # from K3CExttensionMethods import ListHeaderExtension as lhObjEx #初始化,在此事件中设置报表的属性全局参数 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; this.ReportProperty.PrimaryKeyFieldName = "FID"; #创建临时报表,正式进入账表取数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; whereSql = ""; # 产品id _proMaterialId = custFilter["ProMaterialId"]; if(_proMaterialId != None): whereSql = whereSql + " AND t0e.FMATERIALID = " + str(_proMaterialId["Id"]); # 物料id _materialId = custFilter["MaterialId"]; if(_materialId != None): whereSql = whereSql + " AND t1e.FMATERIALID = " + str(_materialId["Id"]); # 生产任务单 _billNo = objEx.ToSafeString(custFilter["BILLNO"]); if(_billNo != ""): whereSql = whereSql + " AND t0.FBILLNO LIKE '%{0}%'".format(_billNo); # 生产投料单 _PPBomBillNo = objEx.ToSafeString(custFilter["PPBOMBILLNO"]); if(_PPBomBillNo != ""): whereSql = whereSql + " AND t1.FBILLNO LIKE '%{0}%'".format(_PPBomBillNo); # 销售订单 _saleOrderNo = objEx.ToSafeString(custFilter["SALEORDERNO"]); if(_saleOrderNo != ""): whereSql = whereSql + " AND t0e.FSALEORDERNO LIKE '%{0}%'".format(_saleOrderNo); _lcId = this.Context.UserLocale.LCID; #raise Exception(str.Join(',',fldsSql));#调试时,可用此行代码,看看构建的动态列SQL对不对 #组装最终写入报表临时表的SQL #注意!!!: 最终临时表一定要有FIDENTITYID ,要从1开始,且不重复 ,不断号,不然前台显示空白!!!! sql=("""/*dialect*/  DECLARE @LCID int SET @LCID = {1} SELECT ROW_NUMBER() OVER(ORDER BY t0.FDATE DESC,t0.FID DESC,t0e.FSEQ ASC) AS FIDENTITYID--1.行号 ,t0.FID ,t0e.FSEQ ,t0e.FENTRYID ,t0.FDATE --2.单据日期 ,t1.FBILLNO AS 'FPPBOMBILLNO'--3.生产投料单号 ,t1.FID AS 'FPPBOMID' ,t0e.FSALEORDERNO --4.销售订单号 ,t0.FBILLNO--7.生产任务单号 ,t0e.FPLANSTARTDATE--38.计划开工日期 ,t0e.FPLANFINISHDATE--39.计划完工日期 ,t0e.FQTY--12.产品生产数量 ,t0e.FYIELDRATE ,t0e.FROUTINGID ,t0e.FMATERIALID AS 'ProMaterialId' ,t0e.FUNITID AS 'PrdUnitId' ,t1e.FENTRYID AS 'PPBOMENTRYID' ,t1e.FMATERIALID ,(t1e.FNUMERATOR / t1e.FDENOMINATOR) AS 'FUnitNeedQty' --18.物料单位用量 ,t1e.FNEEDQTY --22.物料总需求 ,t1e.FUNITID ,t1e.FBOMENTRYID ,t1e.FSTDQTY --标准用量 --29.标准数量 ,t1e.FMUSTQTY --应发数量 --30.应发数量 ,t1.FWORKSHOPID ,t0.FCUSTOMERID --客户id ,(CASE t0e.FPRODUCTTYPE WHEN 1 THEN '主产品' WHEN 2 THEN '联产品' WHEN 3 THEN '副产品' ELSE '' END) AS 'PRODUCTTYPE'--43.生产类型 ,(CASE t0e_a.FSTATUS WHEN 6 THEN '已结案'ELSE '' END) AS 'StatusIs6'--45.生产任务单结案否 ,(CASE t1.FDOCUMENTSTATUS WHEN 'A' THEN '创建' WHEN 'B' THEN '审核中' WHEN 'C' THEN '已审核' WHEN 'D' THEN '重新审核' WHEN 'Z' THEN '暂存' ELSE '' END) AS 'PPBOMStatus'--46.生产投料单状态 INTO #TmpTable0 FROM T_PRD_MO t0 INNER JOIN T_PRD_MOENTRY t0e on t0.FID = t0e.FID INNER JOIN T_PRD_MOENTRY_A t0e_a on t0e_a.FENTRYID = t0e.FENTRYID INNER JOIN T_PRD_PPBOM t1 on t1.FMOENTRYID = t0e.FENTRYID AND t1.FMOID = t0e.FID INNER JOIN T_PRD_PPBOMENTRY t1e on t1e.FID = t1.FID WHERE 1 = 1 {2} SELECT tt.* ,t0e_q.FBASEWIPQTY --23.当前在制品数量 ,t0e_q.FPICKEDQTY --27.已领数量 ,t0e_q.FNOPICKEDQTY --28.未领数量 ,t0e_l.FMEMO --31.备注 ,t0e_q.FPICKEDQTY * (100 - tt.FYIELDRATE) AS 'FLossQty'--32.损耗数量 ,t0e_q.FSCRAPQTY --33.报废数量 ,t0e_q.FREPICKEDQTY --37.补料数量 ,t0e_q.FINVENTORYQTY ,t0e_c.FSTOCKID ,t0e_c.FSTOCKLOCID INTO #TmpTable1 FROM #TmpTable0 tt LEFT JOIN T_PRD_PPBOMENTRY_Q t0e_q ON t0e_q.FENTRYID = tt.PPBOMENTRYID --生产用料清单数量拆分表 LEFT JOIN T_PRD_PPBOMENTRY_C t0e_c ON t0e_c.FENTRYID = tt.PPBOMENTRYID LEFT JOIN T_PRD_PPBOMENTRY_L t0e_l on t0e_l.FENTRYID = tt.PPBOMENTRYID AND t0e_l.FLOCALEID = @LCID SELECT tt.* ,t1.FMNEMONICCODE AS 'ProMnemonicCode'--6.助记码 ,t1.FNUMBER AS 'ProNumber'--8.产品编码 ,t1_l.FNAME AS 'ProName'--9.产品名称 ,t1_l.FSPECIFICATION AS 'ProSpecification'--10.产品规格型号 ,t2_l.FNAME AS 'ProUnitName'--11.产品单位 ,t3.FNUMBER AS 'MaterialNumber'--8.物料编码 ,t3_l.FNAME AS 'MaterialName'--9.物料名称 ,t3_l.FSPECIFICATION AS 'MaterialSpecification'--10.物料规格型号 ,t4_l.FNAME AS 'MaterialUnitName'--11.物料单位 ,(CASE t3.FMATERIALSRC WHEN 'A' THEN 'PLM' WHEN 'B' THEN 'ERP' ELSE '' END) AS 'Materialsrc' --15.物料来源 ,t6_l.FNAME AS 'WORKSHOPNAME' --44.生产车间 ,t3.FMASTERID ,t3.FUSEORGID ,t7_l.FMEMO AS 'BOMMEMO' --42.BOM备注项 ,t5_l.FNAME AS 'FSTOCKNAME' ,t8.FNUMBER AS SaleUnitNumber --5.购货单位代码 INTO #TmpTable2 FROM #TmpTable1 tt LEFT JOIN T_BD_MATERIAL t1 ON t1.FMATERIALID = tt.ProMaterialId LEFT JOIN T_BD_MATERIAL_L t1_l ON t1_l.FMATERIALID = tt.ProMaterialId AND t1_l.FLOCALEID = @LCID LEFT JOIN T_BD_UNIT_L t2_l ON t2_l.FUNITID = tt.PrdUnitId AND t2_l.FLOCALEID = @LCID LEFT JOIN T_BD_MATERIAL t3 ON t3.FMATERIALID = tt.FMATERIALID LEFT JOIN T_BD_MATERIAL_L t3_l ON t3_l.FMATERIALID = tt.FMATERIALID AND t3_l.FLOCALEID = @LCID LEFT JOIN T_BD_UNIT_L t4_l ON t4_l.FUNITID = tt.FUNITID AND t4_l.FLOCALEID = @LCID LEFT JOIN T_BD_STOCK_L t5_l ON t5_l.FSTOCKID = tt.FSTOCKID AND t5_l.FLOCALEID =@LCID LEFT JOIN T_BD_DEPARTMENT_L t6_l on t6_l.FDEPTID = tt.FWORKSHOPID AND t6_l.FLOCALEID = @LCID LEFT JOIN T_ENG_BOMCHILD_L t7_l ON t7_l.FENTRYID = tt.FBOMENTRYID AND t7_l.FLOCALEID = @LCID LEFT JOIN T_BD_CUSTOMER t8 on t8.FCUSTID = tt.FCUSTOMERID SELECT tt.* ,t1.FBASEQTY ,t2_l.FNAME AS 'ROUTENAME' ,t3e_A.FBASEINVQTY ,t3e.FBASELACKQTY AS 'FBASELACKQTY'--24.欠料 ,t3e_A.FBASEONORDERQTY AS 'FBASEONORDERQTY' --25.物料在途数 ,t3e_A.FPURCHASEQTY --采购在途数量 ,t3e_A.FREQUISITIONQTY --采购申请在途数量 ,6 AS 'LOWEST6' ,t3e_A.FREQUISITIONQTY - t3e_A.FPURCHASEQTY AS 'PR_C2PO_QTY' ,0 AS 'ToBeInspectQTY' ,0 AS 'PlanThrowInQty' ,'' AS 'PlanThrowInDate' ,'' AS 'CubicleName' ,'' AS 'OTHERMEMO' INTO {0} FROM #TmpTable2 tt LEFT JOIN ( SELECT t0.FMATERIALID ,t0.FSTOCKORGID ,sum(t0.FBASEQTY) AS FBASEQTY FROM T_STK_INVENTORY t0 GROUP BY t0.FMATERIALID ,t0.FSTOCKORGID ) t1 on t1.FMATERIALID = tt.FMASTERID AND t1.FSTOCKORGID = tt.FUSEORGID LEFT JOIN T_ENG_ROUTE_L t2_L on t2_L.FID = tt.FROUTINGID AND t2_L.FLOCALEID = @LCID LEFT JOIN T_PRD_PMPPBOMENTRY t3e on t3e.FPPBOMENTRYID = tt.PPBOMENTRYID AND t3e.FMATERIALIDSUB = tt.FMATERIALID --AND t3e.FMATERIALID = t0.FMATERIALID LEFT JOIN T_PRD_PMPPBOMENTRY_A t3e_A ON t3e_A.FENTRYID = t3e.FENTRYID DROP TABLE #TmpTable0 DROP TABLE #TmpTable1 DROP TABLE #TmpTable2 """).format(tableName,_lcId,whereSql); # raise Exception(sql);#可以通过此方法弹出Sql语句进行调试验证 DBUtils.Execute(this.Context,sql);#执行SQL,将报表数据写入临时表 #构建账表列头 def GetReportHeaders(rptfilter): header = ReportHeader(); localEid = this.Context.UserLocale.LCID;#获取当前语言环境代码,中文为2052 # 索引 global _colIndex _colIndex = 0; def Incr1(val = 1): global _colIndex _resNum = _colIndex _colIndex += val return _resNum datas = [ {"fieldName" :"FDATE", "showName" :"单据日期","Mergeable" : True,"dataType":SqlStorageType.SqlDatetime } ,{"fieldName" :"FPPBOMBILLNO", "showName" :"生产投料单号","Mergeable" : True,"IsHyperlink":True } ,{"fieldName" :"FSALEORDERNO", "showName" :"销售订单号","Mergeable" : True } ,{"fieldName" :"SaleUnitNumber", "showName" :"购货单位代码","Mergeable" : True } ,{"fieldName" :"ProMnemoniccode", "showName" :"助记码","Mergeable" : True } ,{"fieldName" :"FBILLNO", "showName" :"生产任务单号","Mergeable" : True } ,{"fieldName" :"ProNumber", "showName" :"产品代码","Mergeable" : True } ,{"fieldName" :"ProName", "showName" :"产品名称","Mergeable" : True } ,{"fieldName" :"ProSpecification", "showName" :"产品规格型号","Mergeable" : True } ,{"fieldName" :"ProUnitName", "showName" :"产品单位","Mergeable" : True } ,{"fieldName" :"FQTY", "showName" :"产品生产数量","Mergeable" : True,"dataType":SqlStorageType.SqlDecimal } ,{"fieldName" :"MaterialNumber", "showName" :"物料代码" } ,{"fieldName" :"MaterialName", "showName" :"物料名称" } ,{"fieldName" :"Materialsrc", "showName" :"物料来源" } ,{"fieldName" :"MaterialSpecification", "showName" :"物料规格型号" } ,{"fieldName" :"ROUTENAME", "showName" :"物料技术标准" } ,{"fieldName" :"FUnitNeedQty", "showName" :"物料单位用量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"MaterialUnitName", "showName" :"物料单位" } ,{"fieldName" :"FBASEINVQTY", "showName" :"物料库存量","dataType":SqlStorageType.SqlDecimal } ,{"fieldName" :"ToBeInspectQTY", "showName" :"物料待检数","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FNEEDQTY", "showName" :"物料总需求","dataType":SqlStorageType.SqlDecimal } ,{"fieldName" :"FBASEWIPQTY", "showName" :"当前在制品数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FBASELACKQTY", "showName" :"欠料","dataType":SqlStorageType.SqlDecimal } ,{"fieldName" :"FBASEONORDERQTY", "showName" :"物料在途数","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"PlanThrowInQty", "showName" :"计划投料数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FPICKEDQTY", "showName" :"已领数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FNOPICKEDQTY", "showName" :"未领数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FSTDQTY", "showName" :"标准数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FMUSTQTY", "showName" :"应发数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FMEMO", "showName" :"备注"} ,{"fieldName" :"FLossQty", "showName" :"损耗数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FSCRAPQTY", "showName" :"报废数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"PlanThrowInDate", "showName" :"计划发料日期","dataType":SqlStorageType.SqlDatetime } ,{"fieldName" :"FSTOCKNAME", "showName" :"仓库" } ,{"fieldName" :"FSTOCKLOCNAME", "showName" :"仓位" } ,{"fieldName" :"FREPICKEDQTY", "showName" :"补料数量","dataType":SqlStorageType.SqlDecimal} ,{"fieldName" :"FPLANSTARTDATE", "showName" :"计划开工日期","dataType":SqlStorageType.SqlDatetime } ,{"fieldName" :"FPLANFINISHDATE", "showName" :"计划完工日期","dataType":SqlStorageType.SqlDatetime } ,{"fieldName" :"CubicleName", "showName" :"工位" } ,{"fieldName" :"OTHERMEMO", "showName" :"其他备注项" } ,{"fieldName" :"BOMMEMO", "showName" :"BOM备注项" } ,{"fieldName" :"PRODUCTTYPE", "showName" :"生产类型" } ,{"fieldName" :"WORKSHOPNAME", "showName" :"生产车间" } ,{"fieldName" :"StatusIs6", "showName" :"生产任务单结案否" } ,{"fieldName" :"PPBOMStatus", "showName" :"生产投料单状态" } ,{"fieldName" :"PR_C2PO_QTY", "showName" :"PR已审未转PO数量","dataType":SqlStorageType.SqlDecimal} ]; for item in datas: head = header.AddChild(item["fieldName"], LocaleValue(item["showName"], localEid), Incr1()) if "dataType" in item: head.ColType = item["dataType"] if "Mergeable" in item: head.Mergeable = item["Mergeable"] if "IsLeaf" in item: head.IsHyperlink = item["IsHyperlink"] return header; #设置报表表头字段值 #这里主要是把过滤框设置的字段值,显示到报表表头 def GetReportTitles(rptfilter): reportTitles = ReportTitles(); custFilter = rptfilter.FilterParameter.CustomFilter; if(custFilter == None): return; _proMaterialId = custFilter["ProMaterialId"]; _materialId = custFilter["MaterialId"]; _billNo = objEx.ToSafeString(custFilter["BILLNO"]); _PPBomBillNo = objEx.ToSafeString(custFilter["PPBOMBILLNO"]); _saleOrderNo = objEx.ToSafeString(custFilter["SALEORDERNO"]); if(_proMaterialId != None): reportTitles.AddTitle("FTitleProMaterialId", _proMaterialId["Name"]); if(_materialId != None): reportTitles.AddTitle("FTitleMaterialId", _materialId["Name"]); if(_billNo != ""): reportTitles.AddTitle("FTitleBILLNO", _billNo); if(_PPBomBillNo != ""): reportTitles.AddTitle("FTitlePPBOMBILLNO", _PPBomBillNo); if(_saleOrderNo != ""): reportTitles.AddTitle("FTitleSALEORDERNO", _saleOrderNo); return reportTitles; #报表关闭触发,通常在此处清理报表过程产生的临时表 def CloseReport(): this.DropTempTable();