Acumatica 以编程方式生成报告

Acumatica 以编程方式生成报告,acumatica,acumatica-kb,Acumatica,Acumatica Kb,假设我已经使用Acumatica报表设计器创建了一个报表,它链接到相关的DAC 我还有一个带有动作的自定义屏幕。当用户执行此操作时,我希望生成报告,以便用户将其作为pdf下载 通过Acumatica API以编程方式以PDF格式生成报告的方法是什么?请参考下面的代码片段,以了解如何以编程方式以PDF格式生成报告,并显示SaveFileDialog以下载/保存生成的PDF: public PXAction<IOITInboundTestWorkOrder> GenerateReport

假设我已经使用Acumatica报表设计器创建了一个报表,它链接到相关的DAC

我还有一个带有动作的自定义屏幕。当用户执行此操作时,我希望生成报告,以便用户将其作为pdf下载


通过Acumatica API以编程方式以PDF格式生成报告的方法是什么?

请参考下面的代码片段,以了解如何以编程方式以PDF格式生成报告,并显示SaveFileDialog以下载/保存生成的PDF:

public PXAction<IOITInboundTestWorkOrder> GenerateReportAndRedirectToFile;
[PXButton]
[PXUIField(DisplayName = "Generate Report and Download as PDF")]
protected void generateReportAndSaveToDB()
{
    Actions.PressSave();
    PXLongOperation.StartOperation(this, () =>
    {
        PX.SM.FileInfo file = null;
        using (Report report = PXReportTools.LoadReport("SO641012", null))
        {
            var orderNbr = ITWO.Current.OrderNbr;
            if (report == null) throw new Exception("Unable to access Acumatica report writter for specified report : " + "SO641012");
            Dictionary<string, string> prams = new Dictionary<string, string>();
            prams["ITWONbr"] = orderNbr;
            PXReportTools.InitReportParameters(report, prams, PXSettingProvider.Instance.Default);
            ReportNode repNode = ReportProcessor.ProcessReport(report);
            IRenderFilter renderFilter = ReportProcessor.GetRenderer(ReportProcessor.FilterPdf);

            using (StreamManager streamMgr = new StreamManager())
            {
                renderFilter.Render(repNode, null, streamMgr);
                string fileName = string.Format("Inbound Test Work Order #{0}.pdf", orderNbr);
                file = new PX.SM.FileInfo(fileName, null, streamMgr.MainStream.GetBytes());
            }
        }
        if (file != null)
        {
            throw new PXRedirectToFileException(file, true);
        }
    });
}
public PXAction generatereportandredirectofile;
[按钮]
[PXUIField(DisplayName=“生成报告并下载为PDF”)]
受保护的void generateReportAndSaveToDB()
{
操作。按Save();
PXLongOperation.StartOperation(此,()=>
{
PX.SM.FileInfo file=null;
使用(Report-Report=PXReportTools.LoadReport(“SO641012”,null))
{
var orderNbr=ITWO.Current.orderNbr;
if(report==null)抛出新异常(“无法访问指定报表的Acumatica报表写入程序:”+“SO641012”);
字典prams=新字典();
婴儿车[“ITWONbr”]=订单编号;
InitReportParameters(report、prams、PXSettingProvider.Instance.Default);
ReportNode repNode=ReportProcessor.ProcessReport(报告);
IRenderFilter renderFilter=ReportProcessor.GetRenderer(ReportProcessor.FilterPdf);
使用(StreamManager streamMgr=new StreamManager())
{
renderFilter.Render(repNode,null,streamMgr);
string fileName=string.Format(“入站测试工单#{0}.pdf”,orderNbr);
file=new PX.SM.FileInfo(fileName,null,streamMgr.maintal.GetBytes());
}
}
如果(文件!=null)
{
抛出新的PXRedirectToFileException(文件,true);
}
});
}

我在接受答案时遇到了问题,因为我使用的是REST API,而且由于某种原因,PXRedirectToFileException在那里确实有效(它不返回位置头)。我提出了一个非常笨拙的解决方案,它会导致文件URL在异常中公开。请原谅我粗鲁的名字。:-)

使用SiteStatus=PX.Objects.IN.Overrides.INDocumentRelease.SiteStatus;
使用System.Linq;
使用PX.Common;
使用CRLocation=PX.Objects.CR.Standalone.Location;
使用PX.Objects.AR.CCPaymentProcessing;
使用PX.Objects.AR.CCPaymentProcessing.Common;
使用PX.Objects.AR.CCPaymentProcessing.Helpers;
使用PX.Objects.Common;
使用PX.Objects;
使用PX.Objects.SO;
使用PX.报告;
使用PX.Reports.Data;
使用PX.Data.Reports;
使用PX.SM;
命名空间PX.Objects.SO
{
公共类SOInvoiceEntry_扩展名:pxGrapherExtension
{
#区域事件处理程序
已选择受保护的虚拟缓存(PXCache缓存,PXRowSelectedEventArgs e){
CreateInvoicePDF.SetEnabled(true);
}
公共行动创建发票PDF;
[按钮]
[PXUIField(DisplayName=“创建发票PDF”,Enabled=true,Visible=false)]
公共虚拟void createInvoicePDF()
{
//报告参数
字典参数=新字典();
参数[“DocType”]=Base.Document.Current.DocType;
参数[“RefNbr”]=Base.Document.Current.RefNbr;
//报表处理
PX.Reports.Controls.Report _Report=PXReportTools.LoadReport(“SO643000”,null);
PXReportTools.InitReportParameters(_report,parameters,SettingsProvider.Instance.Default);
ReportNode ReportNode=ReportProcessor.ProcessReport(_report);
//生成PDF
byte[]data=PX.Reports.Mail.Message.GenerateReport(reportNode,ReportProcessor.FilterPdf).First();
FileInfo file=newfileinfo(Guid.NewGuid(),“Invoice”+Base.Document.Current.RefNbr+“.pdf”,null,数据);
//在会话中存储数据
PXContext.SessionTyped().FileInfo[file.UID.ToString()]=file;
//在异常中包含文件URL。客户端将解析文件名并在后续请求中获取URL。
PXRedirectToFileException e=新的PXRedirectToFileException(file.UID,0,true,true);
字符串url=e.url;
抛出新AcumaticaIsFullOfShitException(url);
}
#端区
}
类AcumaticaIsFullOfShitException:PXException{
公共AcumaticaIsFullOfShitException(字符串消息):基(消息){
}
}
}
缺点是此操作只能通过API使用。
我将该操作添加到web服务端点。另一方面,我使用正则表达式从异常消息中提取字符串,并执行get请求以获取文件。

如果不想公开URL,公认的方法似乎是调用一种方法,将文件存储到Acumatica记录中,然后通过API检索文件:

请不要将文件保存到Acumatica,而是通过API提供报告生成功能!
using SiteStatus = PX.Objects.IN.Overrides.INDocumentRelease.SiteStatus;
using System.Linq;
using PX.Common;
using CRLocation = PX.Objects.CR.Standalone.Location;
using PX.Objects.AR.CCPaymentProcessing;
using PX.Objects.AR.CCPaymentProcessing.Common;
using PX.Objects.AR.CCPaymentProcessing.Helpers;
using PX.Objects.Common;
using PX.Objects;
using PX.Objects.SO;
using PX.Reports;
using PX.Reports.Data;
using PX.Data.Reports;
using PX.SM;

namespace PX.Objects.SO
{

  public class SOInvoiceEntry_Extension:PXGraphExtension<SOInvoiceEntry>
  {

    #region Event Handlers
    protected virtual void ARInvoice_RowSelected(PXCache cache, PXRowSelectedEventArgs e){
        CreateInvoicePDF.SetEnabled(true);
    }

     public PXAction<ARInvoice> CreateInvoicePDF;
     [PXButton]
     [PXUIField(DisplayName = "Create Invoice PDF", Enabled = true, Visible = false)]
     public virtual void createInvoicePDF()
     {
            //Report Paramenters
            Dictionary<String, String> parameters = new Dictionary<String, String>();
            parameters["DocType"] = Base.Document.Current.DocType;
            parameters["RefNbr"] = Base.Document.Current.RefNbr;

            //Report Processing
            PX.Reports.Controls.Report _report = PXReportTools.LoadReport("SO643000",null);
            PXReportTools.InitReportParameters(_report, parameters, SettingsProvider.Instance.Default);
            ReportNode reportNode = ReportProcessor.ProcessReport(_report);

            // Generate PDF
            byte[] data = PX.Reports.Mail.Message.GenerateReport(reportNode, ReportProcessor.FilterPdf).First();
            FileInfo file = new FileInfo(Guid.NewGuid(), "Invoice" + Base.Document.Current.RefNbr + ".pdf", null, data);

            // Store data in session
            PXContext.SessionTyped<PXSessionStatePXData>().FileInfo[file.UID.ToString()] = file;

            // Include file URL in exception. The client will parse the filname and fetch the URL in a subsequent request.
            PXRedirectToFileException e =  new PXRedirectToFileException(file.UID, 0, true, true);

            string url = e.Url;

            throw new AcumaticaIsFullOfShitException(url);
     }

    #endregion

    }

    class AcumaticaIsFullOfShitException : PXException {
        public AcumaticaIsFullOfShitException(string message) : base(message) {

        }
    }

}