Calling BAQ Report Using REST - Error - RunTask: Root element is missing

Hello All,

I am using swagger to submit a BAQ report to the task agent in hopes that it previews.

I filled out the parameters and get a 200 response code, but when I go into the system monitor I see the message quoted below… When I look at the trace I see a huge xml string being passed in filter1 and another, smaller one passed in filter2.

I am keeping both of those blank at the moment, because when I fill in the values using what I see in the trace I get a 400 response in swagger saying it can’t find the “ds” parameter anymore.

In short, has anyone seen this error before? If I need to upload more please let me know.

Thank in advance for any pointers or help.

-Utah

System Monitor Error Message:

Program Ice.Services.Lib.RunTask raised an unexpected exception with the following message: RunTask: Root element is missing.
Stack Trace:
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlReader.MoveToContent()
at System.Data.DataSet.ReadXml(XmlReader reader, Boolean denyResolving)
at Ice.Internal.XA.BAQReport.LoadFilterDataIntoDataSet(String filterData) in C:_Releases\ICE\ICE3.2.400.0\Source\Server\Internal\XA\XABaqRpt\BAQReport.cs:line 113
at Ice.Internal.XA.BAQReport.SetUpFilterAndOptionData() in C:_Releases\ICE\ICE3.2.400.0\Source\Server\Internal\XA\XABaqRpt\BAQReport.cs:line 82
at Ice.Internal.XA.BAQReport.RunProcess(Int64 instanceTaskNum, String outputFileName) in C:_Releases\ICE\ICE3.2.400.0\Source\Server\Internal\XA\XABaqRpt\BAQReport.cs:line 39
at Ice.Core.TaskBase`1.StartProcess(Int64 instanceTaskNum, String outputFileName) in C:_Releases\ICE\ICE3.2.400.23\Source\Server\Internal\Lib\TaskLib\TaskBase\TaskBase.cs:line 47
at Ice.Hosting.TaskCaller.InnerExecuteTask(IceDataContext newContext) in C:_Releases\ICE\ICE3.2.400.23\Source\Framework\Epicor.Ice\Hosting\TaskCaller\TaskCaller.cs:line 98
at Ice.Hosting.TaskCaller.ExecuteTask() in C:_Releases\ICE\ICE3.2.400.23\Source\Framework\Epicor.Ice\Hosting\TaskCaller\TaskCaller.cs:line 57
at Ice.Lib.RunTask.BpmFriendlyTaskLauncher.Run(String sessionIdPrefix, IceContext db, Action taskRunner) in C:_Releases\ICE\ICE3.2.400.0\Source\Server\Services\Lib\RunTask\BpmFriendlyTaskLauncher.cs:line 63
at Ice.Services.Lib.RunTaskSvc.InnerRunTask(Int64 ipTaskNum, Boolean suppressTransaction) in C:_Releases\ICE\ICE3.2.400.0\Source\Server\Services\Lib\RunTask\RunTask.cs:line 592

It was the xml value in filter 1… it just had to be formatted correctly. Now working the the error on the ssrs server saying:

An exception has occurred in data set ‘BAQReportParameter’. Details: Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: Query execution failed for dataset ‘BAQReportParameter’. —> System.Data.SqlClient.SqlException: Invalid column name ‘Cur-TaskClientID’.

So, the easiest way I found to resolve this error was to just remove the Cur-TaskClientID column from the BAQReportParameter dataset in the RDL. The reports we print using REST are really basic and this column wasn’t being used anywhere, and it hasn’t seemed to hurt printing with this parameter removed.

Tyler, that is good idea… I will try that. As far as you know, there are no downsides to doing that?

Very strange behavior, I just want to understand it. I don’t even see those fields when I do a trace, but if you query the BAQReportParam_GUID table when you run the report you see those fields.

Very interesting.

So far so good. It was working in 10.2.300 and is working in 10.2.600 without any issues. We’re using server-side printers to print the reports via the task agent.

I don’t remember the exact details but I think the fields are in either the Filter 1 dataset or another context dataset that’s sent with the call. I remember trying to manually add it during the REST call, but I could never get it to take it.

From what I understand, the BAQ Report engine takes the XML parameters and context and formats it into the BAQReportParameter_GUID table. Since REST doesn’t add the Cur-TaskClientID XML tag, this column isn’t created in the parameters temp table.

How are you getting the dynamic report data set? I have to pass it in filter 1, but the way I got it was by scheduling the report to run on a schedule and then calling the Getparameters rest call which returned to me what filter 1 should be… It is a large xml value. Is there another method to call that will generate that xml for me so I can pass it to the rest call?

I make a call to DynamicReportSvc/DynamicReports(baqReportID) to get the BAQ Report dataset, then call DynamicReportSvc/DynamicReports(baqReportID)/BAQRptOptionFlds to get the option fields for the report.
Once I have the BAQ report dataset and option fields loaded into objects, I serialize them into XML and set that value to Filter1

I’ve attached the code that gets the Filter1 XML. First, DynamicReport.Read is called, then .ToXML is called on the resulting DynamicReport object. This report is a Bill of Lading report and takes the BOL number as the (only) field option, so if your report doesn’t have any options, you may be able to get away without using that. This report doesn’t use Filters, so I’m not sure how those would be integrated.

DynamicReport.cs (Warning: Long)
/// <summary>
    ///     Represents a BAQ Report and allows retrieval of required properties.
    /// </summary>
    [XmlRoot(ElementName = "DynamicReportDataSet"

            //, Namespace = "http://www.epicor.com/Ice/300/BO/DynamicReport/DynamicReport"
        )]
    public class DynamicReport
    {
        /// <summary>
        ///     BAQ Report dataset.
        /// </summary>
        [XmlElement("BAQReport")]
        public BAQReportDs BAQReport { get; set; }

        /// <summary>
        ///     List of BAQ Report Option fields.
        /// </summary>
        [XmlElement("BAQRptOptionFld")]
        public List<BAQRptOptionFld> OptionFields { get; set; }

        /// <summary>
        ///     Gets the Dynamic Report dataset from Epicor for the given BAQ report ID.
        /// </summary>
        /// <param name="baqReportID">The BAQ report to read from Epicor.</param>
        /// <returns>The Dynamic Report dataset.</returns>
        public static DynamicReport Read(string baqReportID)
        {
            var callContext = new CallContextHeader();
            var statusCode = new EpicorRestStatusCode();

            JObject response = EpicorRest.DynamicGet("Ice.BO.DynamicReportSvc", $"DynamicReports({baqReportID})", null,
                                                     statusCode, callContext);

            if (statusCode.RestCallStatusCode != HttpStatusCode.OK)
            {
                return null;
            }

            var dynReport = new DynamicReport
                            {
                                BAQReport = response.ToObject<BAQReportDs>(),
                                OptionFields = BAQRptOptionFld.Read(baqReportID)
                            };

            return dynReport.OptionFields != null ? dynReport : null;
        }

        /// <summary>
        ///     Serializes this Dynamic Report dataset to XML with the given BOL#.
        /// </summary>
        /// <param name="bolNum">The BOL# of the report to print.</param>
        /// <returns>The XML serialization of this dataset.</returns>
        public string ToXml(string bolNum)
        {
            this.OptionFields.First().FieldValue = bolNum;

            var ns = new XmlSerializerNamespaces();
            ns.Add(string.Empty, "http://www.epicor.com/Ice/300/BO/DynamicReport/DynamicReport");

            var settings = new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true};

            var serializer = new XmlSerializer(this.GetType(),
                                               "http://www.epicor.com/Ice/300/BO/DynamicReport/DynamicReport");

            using (var stream = new StringWriter())
            {
                using (var writer = XmlWriter.Create(stream, settings))
                {
                    serializer.Serialize(writer, this, ns);
                    return stream.ToString();
                }
            }
        }
    }

    /// <summary>
    ///     BAQ Report dataset
    /// </summary>
    public class BAQReportDs
    {
        /// <summary>
        ///     The ID of this report.
        /// </summary>
        public string BAQRptID { get; set; }

        /// <summary>
        ///     Bit flag indicating row information.
        /// </summary>
        public int BitFlag { get; set; }

        /// <summary>
        ///     Country group code.
        /// </summary>
        public string CGCCode { get; set; }

        /// <summary>
        ///     The company this report is running in.
        /// </summary>
        public string Company { get; set; }

        /// <summary>
        ///     Whether or not this report has been finished.
        /// </summary>
        public bool Completed { get; set; }

        /// <summary>
        ///     The name of the crystal report.
        /// </summary>
        public string CrystalReportName { get; set; }

        /// <summary>
        ///     Description of the BAQ report.
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        ///     ID used for report export.
        /// </summary>
        public string ExportID { get; set; }

        /// <summary>
        ///     Title shown on the report header.
        /// </summary>
        public string FormTitle { get; set; }

        /// <summary>
        ///     Whether or not this is a multi-company report.
        /// </summary>
        public bool GlobalReport { get; set; }

        /// <summary>
        ///     Whether or not this is a crystal report.
        /// </summary>
        public bool IsCrystalReport { get; set; }

        /// <summary>
        ///     This report's ID.
        /// </summary>
        public string ReportID { get; set; }

        /// <summary>
        ///     Report title.
        /// </summary>
        public string ReportTitle { get; set; }

        /// <summary>
        ///     Flag indicating row state.
        /// </summary>
        public string RowMod { get; set; }

        /// <summary>
        ///     SSRS Report Name.
        /// </summary>
        public string SSRSReportName { get; set; }

        /// <summary>
        ///     Row revision ID.
        /// </summary>
        public string SysRevID { get; set; }

        /// <summary>
        ///     Row GUID.
        /// </summary>
        public string SysRowID { get; set; }

        /// <summary>
        ///     Whether or not this report is a system report.
        /// </summary>
        public bool SystemFlag { get; set; }

        /// <summary>
        ///     Temporary row ID.
        /// </summary>
        public string TempRowID { get; set; }
    }

    /// <summary>
    ///     BAQ Report option/filter fields.
    /// </summary>
    public class BAQRptOptionFld
    {
        /// <summary>
        ///     The parent BAQ Report.
        /// </summary>
        public string BAQRptID { get; set; }

        /// <summary>
        ///     Bit flag indicating row information.
        /// </summary>
        public int BitFlag { get; set; }

        /// <summary>
        ///     The parent company.
        /// </summary>
        public string Company { get; set; }

        /// <summary>
        ///     Comparison operator
        /// </summary>
        public string CompOp { get; set; }

        /// <summary>
        ///     The table this filter acts on.
        /// </summary>
        public string DataTableID { get; set; }

        /// <summary>
        ///     The data-type of this filter.
        /// </summary>
        public string DataType { get; set; }

        /// <summary>
        ///     This field's default value.
        /// </summary>
        public string DefaultValue { get; set; }

        /// <summary>
        ///     The human-readable name for this field.
        /// </summary>
        public string DisplayName { get; set; }

        /// <summary>
        ///     Order the fields are displayed in.
        /// </summary>
        public int DispOrder { get; set; }

        /// <summary>
        ///     GUID
        /// </summary>
        public string EpiGuid { get; set; }

        /// <summary>
        ///     The format for this field.
        /// </summary>
        public string FieldFormat { get; set; }

        /// <summary>
        ///     The label to use for this field.
        /// </summary>
        public string FieldLabel { get; set; }

        /// <summary>
        ///     The name of this field.
        /// </summary>
        public string FieldName { get; set; }

        /// <summary>
        ///     The value input into this filter field.
        /// </summary>
        public string FieldValue { get; set; }

        /// <summary>
        ///     Whether or not this record is visible.
        /// </summary>
        public bool IsVisible { get; set; }

        /// <summary>
        ///     Flag indicating row state.
        /// </summary>
        public string RowMod { get; set; }

        /// <summary>
        ///     Sequence ID
        /// </summary>
        public int Seq { get; set; }

        /// <summary>
        ///     Row revision ID.
        /// </summary>
        public string SysRevID { get; set; }

        /// <summary>
        ///     Row GUID.
        /// </summary>
        public string SysRowID { get; set; }

        /// <summary>
        ///     Whether or not this is a system record.
        /// </summary>
        public bool SystemFlag { get; set; }

        /// <summary>
        ///     Temporary row ID.
        /// </summary>
        public string TempRowID { get; set; }

        /// <summary>
        ///     Gets the BAQ Report option fields from Epicor for the given BAQ report.
        /// </summary>
        /// <param name="baqReportID">The BAQ Report to get options for.</param>
        /// <returns>List of options fields.</returns>
        public static List<BAQRptOptionFld> Read(string baqReportID)
        {
            var callContext = new CallContextHeader();
            var statusCode = new EpicorRestStatusCode();

            JObject response = EpicorRest.DynamicGet("Ice.BO.DynamicReportSvc",
                                                     $"DynamicReports({baqReportID})/BAQRptOptionFlds", null,
                                                     statusCode, callContext);

            if (statusCode.RestCallStatusCode != HttpStatusCode.OK)
            {
                return null;
            }

            var list = response["value"].ToObject<List<BAQRptOptionFld>>();
            foreach (BAQRptOptionFld item in list)
            {
                item.TempRowID = "Field1";
                item.IsVisible = true;
            }

            return list;
        }
    }

Did you put this in Epicor so you can use it (i.e. BPM/customization) or is it an external application/program where you click a button and perform the print?

It’s an external shipping program for our handheld devices that I built to follow our workflow. Our shipping personnel build out our packs and BOLs and hit a button to print a custom BAQ report we use as the BOL print-out.