Print SSRS report from C# code outside of Epicor

Has anyone successfully printed an Epicor SSRS report from outside of Epicor (not running the Epicor client)?
I have read many posts here about printing an SSRS report from C# but all are inside Epicor (BPM, screen customization, etc). We have a WinForms app that is external to Epicor calling Epicor BOs and we want to print an Epicor Packing Slip. I believe I have followed the steps found in a Trace of printing a Pack Slip in Epicor but the report doesn’t print… until I open the Epicor client, then it prints. Which leads me to believe the Report Monitor and/or System Monitor steps are not correct.
The code below is doing a print preview for testing purposes but ultimately we want to print.

 private void PrintDD250(int packNum)
        {
            try
            {
                ReportMonitorAdapter adpRptMon = new ReportMonitorAdapter(EpiUser.EpiLaunch);
                adpRptMon.BOConnect();

                PackingSlipPrintAdapter adpPackSlip = new PackingSlipPrintAdapter(EpiUser.EpiLaunch);
                adpPackSlip.BOConnect();
                adpPackSlip.GetNewParameters();
                adpPackSlip.ReportData.PackingSlipParam[0].PackNum = packNum;
                adpPackSlip.ReportData.PackingSlipParam[0].PrintingOptions = "S";
                adpPackSlip.ReportData.PackingSlipParam[0].AutoAction = "SSRSPREVIEW";
                //adpPackSlip.ReportData.PackingSlipParam[0].AutoAction = "SSRSClientPrint";
                //adpPackSlip.ReportData.PackingSlipParam[0].PrinterName = Properties.Settings.Default.DocumentPrinter;
                adpPackSlip.ReportData.PackingSlipParam[0].SSRSRenderFormat = "PDF";
                adpPackSlip.ReportData.PackingSlipParam[0].AgentID = "System Task Agent";
                adpPackSlip.ReportData.PackingSlipParam[0].ReportStyleNum = 1006;
                adpPackSlip.ReportData.PackingSlipParam[0].WorkstationID = Ice.Lib.Report.EpiReportFunctions.GetWorkStationID(EpiUser.EpiSession);
                adpPackSlip.ReportData.PackingSlipParam[0].ProcessTaskNum = 0;
                adpPackSlip.ReportData.PackingSlipParam[0].RowMod = "A";
                adpPackSlip.SubmitToAgent("System Task Agent", 0, 0);

                SysMonitorAdapter adpSysMonitor = new SysMonitorAdapter(EpiUser.EpiLaunch);
                adpSysMonitor.BOConnect();

                SearchOptions opts = new SearchOptions(SearchMode.AutoSearch);
                opts.NamedSearch.WhereClauses.Add("SysRptLst", "(PrintDriver='SSRS' AND (AutoAction='PREVIEW' OR AutoAction='PRINT') AND LastAction='SSRSREADY') AND WorkStationID='my-workstation-id'");
                opts.NamedSearch.WhereClauses.Add("SysTask", "history = true and  SubmitUser = 'my-user-id'");
                opts.NamedSearch.WhereClauses.Add("SysTaskLog", "");
                SysMonitorTasksAdapter adpSysMonTasks = new SysMonitorTasksAdapter(EpiUser.EpiLaunch);
                adpSysMonTasks.BOConnect();
                SysMonitorTasksDataSet sysMonitorData = adpSysMonTasks.SysMonitorTasksData;

                if (adpRptMon.GetRowsKeepIdleTimeWithBallonInfo(opts, false, out sysMonitorData))
                {
                    if (adpRptMon.ReportMonitorData.SysRptLst.Count > 0)
                    {
                        adpRptMon.ReportMonitorData.SysRptLst[0].AutoAction = "";
                        adpRptMon.ReportMonitorData.SysRptLst[0].LastAction = "Process";
                        adpRptMon.Update();

                        Byte[] returnRpt = adpRptMon.GetReportBytes(adpRptMon.ReportMonitorData.SysRptLst[0].SysRowID);

                        //adpRptMon.ReportMonitorData.SysRptLst[0].LastAction = "PRINT";
                        adpRptMon.ReportMonitorData.SysRptLst[0].LastAction = "PREVIEW";
                        adpRptMon.Update();
                    }
                    else
                    {
                        Misc.TraceLog.Write(string.Format("ReportMonitor didn't find Rpt for PackNumber [{0}].", packNum));
                    }
                }
                else
                {
                    Misc.TraceLog.Write(string.Format("ReportMonitor didn't find Rpt for PackNumber [{0}].", packNum));
                }

                SysMonitorDataSet dsSysMon = adpSysMonitor.GetReports(EpiUser.UserID, "", "Days", 1);

                opts = new SearchOptions(SearchMode.AutoSearch);
                opts.NamedSearch.WhereClauses.Add("SysTask", "history = false and SubmitUser = 'my-user-id'");
                opts.NamedSearch.WhereClauses.Add("SysTaskLog", "");
                opts.PageSize = 0;
                opts.AbsolutePage = 0;
                DataSet dsReport = adpSysMonTasks.GetRows(opts, out bool morePages);
                Misc.TraceLog.Write(string.Format("Pause to look at DataSet from SysMonTasks.GetRows for PackNumber [{0}].", packNum));
            }
            catch (Exception ex)
            {
                Misc.TraceLog.Write(string.Format("Exception caught trying to print DD 250 form for PackNumber [{0}]. Exception: {1}", packNum, ex.ToString()));
            }
        }

Any suggestions would be appreciated!
Kelly

Yes. You can do it with REST.

Also, the System Monitor is what retrieves the report when finished. That’s why logging into Epicor brings it up. Using the RunDirect method would work but you might have to retrieve it with the ReportMonitor service as shown in this thread.

And you’ll need to go ahead and tell it that it printed, or it’s going to print again when the client is opened.

Let me look.

1 Like

See this from your code, that is your pdf file data, You will need to print that yourself.

Also, you are using SubmitToAgent and then immediately checking for the report, instead of waiting for it.
Use RunDirect. Then it should be available when RunDirect Completes.

1 Like

And if you keep using the dlls, you’ll need to remember to update them at every client update!

There is a few things more wrong with that code above too. :thinking:

I do this via REST.

private static bool TryDownloadingJobSSRS(string jobNum, int numCopies, string reportStyleID, string printerName, string suffix)
        {
            var reportGUID = Guid.NewGuid().ToString();
            var pData = new
            {
                ds = new
                {
                    JobTravParam = new[]
                    {
                        new
                        {
                            PrntAllMassPrnt = false,
                            Jobs = jobNum,
                            Assembly = "0",
                            ReportStyleNum = reportStyleID,
                            AutoAction = "SSRSPREVIEW",
                            SSRSRenderFormat = "PDF",
                            TaskNote = reportGUID,
                            ShpSchd = true,
                            BarCodes = true,
                        },
                    },
                },
            };
            var pdfFileName = $@"{Settings.Default.TempPDFLocation}{jobNum}{suffix}.pdf";
            EpicorRest.DynamicPost("Erp.RPT.JobTravSvc", "RunDirect", pData);
            if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK)
            {
                Log.Error($"[{jobNum}] FAILED TO GENERATE REPORT. See error:");
                Log.Error(EpicorRest.LastCallErrorMessage);
                critialErrors += 1;
                return false;
            }

            var reports = EpicorRest.DynamicGet("BaqSvc", "Production-DownloadTravRpt", new Dictionary<string, string>() { { "GUID", reportGUID } });
            if (EpicorRest.LastCallResult != System.Net.HttpStatusCode.OK)
            {
                Log.Error($"[{jobNum}] FAILED TO DOWNLOAD REPORT. See error:");
                Log.Error(EpicorRest.LastCallErrorMessage);
                critialErrors += 1;
                return false;
            }
            else if (reports["value"].Count <= 0)
            {
                Log.Error($"[{jobNum}] ERROR: BAQ 'Production-DownloadTravRpt' returned no results, so no report could be downloaded.");
                critialErrors += 1;
                return false;
            }

            try
            {
                File.WriteAllBytes(pdfFileName, Convert.FromBase64String(reports["value"].Last.SysRptLst_RptData.ToString()));
                return true;
            }
            catch (Exception e)
            {
                Log.Error($"[{jobNum}]: Could not save report pdf. File path: {pdfFileName}");
                Log.Error($"[{jobNum}]: Error: {e}");
                critialErrors += 1;
                return false;
            }
        }

BAQ is simple:

2 Likes

You’re code is formatted like Picasso having a stroke, but it’s clean and I like it. :rofl:

1 Like

I think it just didn’t copy from visual studio well, if you mean the indentation.

Our prod server has a self-signed SSL certificate so it’s not ready for REST. I was working on that on our test server and in the process of converting this entire WinForms app to REST when this new request came up. I will see if I can get one of the other suggestions working but this will be the final solution.
Thanks for your time, Mark!
Kelly

I’ve just about got your original code fixed up.

I will try your suggestions and report back.
Thanks Kevin!

If you hold on, I fixed it for you :rofl:

Thanks Evan for sharing your code! I will definitely come back to this when we get our prod server REST ready.
Kelly

private void PrintDD250(int packNum, int styleNum)
{
    try
    {
		//Easy to find
		string reportTaskNote = Guid.NewGuid().ToString();

        PackingSlipPrintAdapter adpPackSlip = new PackingSlipPrintAdapter(EpiUser.EpiLaunch);
        adpPackSlip.BOConnect();

        adpPackSlip.GetNewParameters();

		Erp.Rpt.PackingSlipPrintDataSet.PackingSlipParamRow psParam = adpPackSlip.ReportData.PackingSlipParam[0];

        psParam.PackNum = packNum;
        psParam.AutoAction = "SSRSPREVIEW";
        psParam.SSRSRenderFormat = "PDF";
        psParam.AgentID = "System Task Agent";
        psParam.ReportStyleNum = styleNum;
        psParam.ProcessTaskNum = 0;
        psParam.RowMod = "A";
		psParam.TaskNote = reportTaskNote; //Magic

        adpPackSlip.RunDirect();

        SysMonitorAdapter adpSysMonitor = new SysMonitorAdapter(EpiUser.EpiLaunch);
        adpSysMonitor.BOConnect();

		//Find the one with our reporTaskNote from above
        SearchOptions opts = new SearchOptions(SearchMode.AutoSearch);
		opts.NamedSearch.WhereClauses.Add("SysTask", "TaskNote = '" + reportTaskNote + "'");

		using (ReportMonitorAdapter adpRptMon = new ReportMonitorAdapter(EpiUser.EpiLaunch))
		{
			adpRptMon.BOConnect();

			SysMonitorTasksDataSet sysMonitorData = null;
	        if (adpRptMon.GetRowsKeepIdleTimeWithBallonInfo(opts, false, out sysMonitorData))
	        {
	            if (adpRptMon.ReportMonitorData.SysRptLst.Count > 0)
	            {
	                Byte[] returnRpt = adpRptMon.GetReportBytes(adpRptMon.ReportMonitorData.SysRptLst[0].SysRowID);
					if(returnRpt.Length > 0)
					{
						//PRINT HERE (The returnRpt Bytes is the pdf)
						MessageBox.Show(returnRpt.Length.ToString());
					}
	                
					adpRptMon.ReportMonitorData.SysRptLst[0].LastAction = "PREVIEW";
	                adpRptMon.Update();
	            }
	            else
	            {
	                Misc.TraceLog.Write(string.Format("ReportMonitor didn't find Rpt for PackNumber [{0}].", packNum));
	            }
	        }
	        else
	        {
	            Misc.TraceLog.Write(string.Format("ReportMonitor didn't find Rpt for PackNumber [{0}].", packNum));
	        }
		}
    }
    catch (Exception ex)
    {
        Misc.TraceLog.Write(string.Format("Exception caught trying to print DD 250 form for PackNumber [{0}]. Exception: {1}", packNum, ex.ToString()));
    }
}

TaskNote idea from @josecgomez

2 Likes

Thanks Kevin!
I’m still working on the PRINT HERE part. :wink:
I’ll report back soon.
Kelly

Kevin, I can’t thank you enough!
I saw your presentation at Insights this year in Vegas. Had I known you were going to rescue me with this golden code, I would have bought you that cigar you needed to complete your alter identity! :wink:
Thanks again,
Kelly

I just put together the pieces of what the greats before me have done :slight_smile:

To be honest, I’ve been needing to do this for a while for some stuff here at work, and
kept putting off learning it all. Your post was the push I needed to do that.

And those cigars were expensive, I would have appreciated it, but been a little miffed! :rofl:

Edit: How did you end up printing it? (Curiosity!)