如何从Business Central客户文档布局获取自定义报表布局ID
问题:Business Central销售订单PDF导出需适配客户自定义文档布局
我正在开发Business Central扩展,在销售订单列表页面添加按钮,以Sales Order [订单号].pdf格式保存销售订单确认单PDF。部分客户会在客户卡片 > 客户 > 文档布局中定义自定义报表布局,该布局优先级要高于报表布局选择中的设置。但Report.SaveAs、Report.Execute这类保存报表的方法需要指定报表ID,我找不到如何从客户文档布局中获取自定义报表布局ID,也没找到对应的文档布局表。目前代码除了自定义报表布局的适配问题外,其他功能正常。
现有代码:
pageextension 50100 SalesOrderExt extends "Sales Order List" { actions { addafter("Print Confirmation") { action("Save Confirmation as PDF") { Caption = 'Save Confirmation As PDF'; ApplicationArea = All; Image = ExportFile; Promoted = true; PromotedCategory = Category8; PromotedIsBig = true; ToolTip = 'Save the order confirmation as a PDF'; trigger OnAction() var SalesHeader: Record "Sales Header"; TempBlob: Codeunit "Temp Blob"; FileManagement: Codeunit "File Management"; RecRef: RecordRef; OStream: OutStream; XmlParameters: Text; begin XmlParameters := '<?xml version="1.0" standalone="yes"?>' + '<ReportParameters name="Sales Order" id="' + System.Format(Report::"Sales Order") + '">' + '<Options>' + '<Field name="NoCopies">0</Field>' + '<Field name="PrintCompany">false</Field>' + '<Field name="ArchiveDocument">false</Field>' + '<Field name="LogInteraction">false</Field>' + '<Field name="DisplayAssemblyInformation">false</Field>' + '</Options>' + '<DataItems>' + '<DataItem name="Sales Header">VERSION(1) SORTING(Field1,Field3) WHERE(Field3=1(' + Rec."No." + '))</DataItem>' + '<DataItem name="Sales Line">VERSION(1) SORTING(Field1,Field3,Field4)</DataItem>' + '<DataItem name="SalesLineComments">VERSION(1) SORTING(Field1,Field2,Field7,Field3)</DataItem>' + '<DataItem name="Sales Comment Line">VERSION(1) SORTING(Field1,Field2,Field7,Field3)</DataItem>' + '<DataItem name="CopyLoop">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="PageLoop">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="SalesLine">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="AsmLoop">VERSION(1) SORTING(Field1)</DataItem>' + '</DataItems>' + '</ReportParameters>'; SalesHeader.Reset(); SalesHeader.SetRange("Document Type", Rec."Document Type"); SalesHeader.SetRange("No.", Rec."No."); SalesHeader.FindFirst(); Clear(OStream); CurrPage.SetSelectionFilter(SalesHeader); RecRef.GetTable(SalesHeader); TempBlob.CreateOutStream(OStream, TextEncoding::UTF8); Report.SaveAs(Report::"Sales Order", XmlParameters, ReportFormat::Pdf, OStream, RecRef); FileManagement.BLOBExport(TempBlob, 'Sales Order ' + Rec."No." + '.pdf', true); end; } } } }
解决方案
1. 找到对应的文档布局表
客户自定义的文档布局存储在Document Layout表(ID:9650)中,该表关联了客户、文档类型和对应的报表布局ID。
2. 获取客户的自定义报表ID逻辑
- 先获取销售订单关联的客户编号
- 查询
Document Layout表,筛选条件为当前公司、客户编号、文档类型(销售订单对应Order) - 若查询到记录,则使用该记录的
Report ID;否则使用默认的Sales Order报表ID
3. 修改后的完整代码
pageextension 50100 SalesOrderExt extends "Sales Order List" { actions { addafter("Print Confirmation") { action("Save Confirmation as PDF") { Caption = 'Save Confirmation As PDF'; ApplicationArea = All; Image = ExportFile; Promoted = true; PromotedCategory = Category8; PromotedIsBig = true; ToolTip = 'Save the order confirmation as a PDF'; trigger OnAction() var SalesHeader: Record "Sales Header"; DocumentLayout: Record "Document Layout"; TempBlob: Codeunit "Temp Blob"; FileManagement: Codeunit "File Management"; RecRef: RecordRef; OStream: OutStream; XmlParameters: Text; TargetReportId: Integer; begin // 获取销售订单头部信息 SalesHeader.Reset(); SalesHeader.SetRange("Document Type", Rec."Document Type"); SalesHeader.SetRange("No.", Rec."No."); if not SalesHeader.FindFirst() then exit; // 获取客户对应的自定义报表ID,无自定义则用默认 TargetReportId := Report::"Sales Order"; DocumentLayout.Reset(); DocumentLayout.SetRange("Company Name", CompanyName); DocumentLayout.SetRange("Customer No.", SalesHeader."Sell-to Customer No."); DocumentLayout.SetRange("Document Type", DocumentLayout."Document Type"::Order); if DocumentLayout.FindFirst() then TargetReportId := DocumentLayout."Report ID"; // 构建XML参数,替换报表ID为目标ID XmlParameters := '<?xml version="1.0" standalone="yes"?>' + '<ReportParameters name="Sales Order" id="' + System.Format(TargetReportId) + '">' + '<Options>' + '<Field name="NoCopies">0</Field>' + '<Field name="PrintCompany">false</Field>' + '<Field name="ArchiveDocument">false</Field>' + '<Field name="LogInteraction">false</Field>' + '<Field name="DisplayAssemblyInformation">false</Field>' + '</Options>' + '<DataItems>' + '<DataItem name="Sales Header">VERSION(1) SORTING(Field1,Field3) WHERE(Field3=1(' + Rec."No." + '))</DataItem>' + '<DataItem name="Sales Line">VERSION(1) SORTING(Field1,Field3,Field4)</DataItem>' + '<DataItem name="SalesLineComments">VERSION(1) SORTING(Field1,Field2,Field7,Field3)</DataItem>' + '<DataItem name="Sales Comment Line">VERSION(1) SORTING(Field1,Field2,Field7,Field3)</DataItem>' + '<DataItem name="CopyLoop">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="PageLoop">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="SalesLine">VERSION(1) SORTING(Field1)</DataItem>' + '<DataItem name="AsmLoop">VERSION(1) SORTING(Field1)</DataItem>' + '</DataItems>' + '</ReportParameters>'; // 执行PDF导出 Clear(OStream); CurrPage.SetSelectionFilter(SalesHeader); RecRef.GetTable(SalesHeader); TempBlob.CreateOutStream(OStream, TextEncoding::UTF8); Report.SaveAs(TargetReportId, XmlParameters, ReportFormat::Pdf, OStream, RecRef); FileManagement.BLOBExport(TempBlob, 'Sales Order ' + Rec."No." + '.pdf', true); end; } } } }
关键注意点
- 必须同步修改XML参数中的报表ID,否则会出现参数与实际调用报表不匹配的问题
Document Layout表的筛选条件要包含当前公司名称,避免跨公司布局干扰- 若客户没有设置自定义布局,会自动 fallback 到默认报表,保证原有逻辑正常运行
内容的提问来源于stack exchange,提问作者SeekingSigma
相关产品推荐
相关产品推荐

