5

I have the exact situation described in this question: Device Hub communication with printer queue

Due to the question having neither an accepted, nor an acceptable answer, I am asking the question again.

I have configured DeviceHub with Acumatica, and my printer is shown. I am sending the print job via a PXAction. Upon executing the action, DeviceHub logs the successful reception of the job, but the printer queue never receives it.

Here's my code, because this is StackOverflow:

public PXAction<PX.Objects.CR.BAccount> PrintAddressLabel;

[PXButton(CommitChanges=true)]
[PXUIField(DisplayName = "Print Label")]
protected void printAddressLabel()
{
  BAccount baccount = Base.Caches[typeof(BAccount)].Current as BAccount;
  string bAccountID = baccount.BAccountID.ToString();

  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters["BAccountID"] = bAccountID;

  PXReportRequiredException ex = null;
  ex = PXReportRequiredException.CombineReport(ex, "ZRCRADDR", parameters);
  SMPrintJobMaint.CreatePrintJobGroup("DYMOLABEL", ex, "Address Label");
}

Could someone point me in a helpful direction?

EDIT:

Upon further testing, I found the following:

Acumatica will print successfully to my DeviceHub printer using the built in printing processes. However, when printing one of those jobs, the DeviceHub logs show a POLL event. When attempting to print from my code, DeviceHub records an NT event, which never makes it to the printer queue.

Upon further testing, in 2019 R1 the logs have changed slightly. Printing Invoices from Acumatica results in an NT event as well. However, there is one line different from a job created in Acumatica versus a job created in code.

Green = job from Acumatica

Orange = job from code

The line Printer DYMOLABEL - printing PDF to \\*printer* is missing in the job sent from code.

Deetz
  • 329
  • 1
  • 16

2 Answers2

3

If I understand correctly ,then you need to add report through Automation Steps screen and associate it with DeviceHub.
Example was written for Invoices,when the process will work under which need print Invoice, then will use these settings :

public class CustomEntry : PXGraph<CustomEntry>
{
 [PXQuickProcess.Step.IsBoundToAttribute(typeof(UsrPath.SO303000.Balanced.Report.PrintLabelReport), false)][PXQuickProcess.Step.RequiresStepsAttribute(typeof(SOQuickProcessParameters.prepareInvoice))]
 [PXQuickProcess.Step.IsInsertedJustAfterAttribute(typeof(SOQuickProcessParameters.prepareInvoice))]
 [PXQuickProcess.Step.IsApplicableAttribute(typeof(Where<Current<SOOrderType.behavior>, In3<SOOrderTypeConstants.salesOrder, SOOrderTypeConstants.invoiceOrder, SOOrderTypeConstants.creditMemo>, And<Current<SOOrderType.aRDocType>, NotEqual<ARDocType.noUpdate>>>))]
 protected virtual void SOQuickProcessParameters_PrintInvoice_CacheAttached(PXCache sender)
 {
 }
}
public static class UsrPath
{
 public static class SO303000
 {
    public static readonly Type GroupGraph = typeof(SOInvoiceEntry);
    public static class Balanced
    {
        public const string GroupStepID = "Balanced";
        public static class Report
        {
            public const string GroupActionID = "Report";
            public class PrintLabelReport : PXQuickProcess.Step.IDefinition
            {
                public Type Graph
                {
                    get
                    {
                        return UsrPath.SO303000.GroupGraph;
                    }
                }
                public string StepID
                {
                    get
                    {
                        return "Balanced";
                    }
                }
                public string ActionID
                {
                    get
                    {
                        return "Report";
                    }
                }
                public string MenuID
                {
                    get
                    {
                        return "Print Label";
                    }
                }
                public string OnSuccessMessage
                {
                    get
                    {
                        return "<Invoice form> is prepared";
                    }
                }
                public string OnFailureMessage
                {
                    get
                    {
                        return "Preparing Invoice form";
                    }
                }
            }
        }
     }
  }
}  

Updated answer

 public PXAction<BAccount> PrintAddressLabel;
    [PXButton(CommitChanges = true)]
    [PXUIField(DisplayName = "Print Label")]
    protected virtual IEnumerable printAddressLabel(PXAdapter adapter)
    {
        List<BAccount> list = adapter.Get<BAccount>().ToList<BAccount>();
        int? branchID = this.Base.Accessinfo.BranchID;
        const string reportID = "YOUR_REPORT_ID";
        Dictionary<string, string> dictionary = new Dictionary<string, string>();
        Dictionary<string, PXReportRequiredException> dictionary2 = new Dictionary<string, PXReportRequiredException>();
        PXReportRequiredException ex = null;
        foreach (BAccount account in list)
        {
            dictionary["BAccountID"] = account.AcctCD;
            ex = PXReportRequiredException.CombineReport(ex, null, dictionary);
            object row = PXSelectorAttribute.Select<BAccount.bAccountID>(this.Base.BAccount.Cache, account);
            string text = new NotificationUtility(this.Base).SearchReport(null, row, reportID, branchID);
            //I think you get this problem due to absence of this line
            PrintParameters printParams = new PrintParameters
            {
                PrintWithDeviceHub = true,
                DefinePrinterManually = true,
                PrinterName = "DYMOLABEL"
            };
            dictionary2 = SMPrintJobMaint.AssignPrintJobToPrinter(dictionary2, dictionary, printParams, new NotificationUtility(this.Base).SearchPrinter, null, reportID, reportID, this.Base.Accessinfo.BranchID);
        }
        if (ex != null)
        {
            SMPrintJobMaint.CreatePrintJobGroups(dictionary2);
            throw ex;
        }
        return adapter.Get();
    }

    [Serializable]
    [PXCacheName("Print Parameters")]
    public partial class PrintParameters : IBqlTable, IPrintable
    {
        #region PrintWithDeviceHub
        [PXDBBool]
        [PXDefault(typeof(FeatureInstalled<FeaturesSet.deviceHub>))]
        public virtual bool? PrintWithDeviceHub { get; set; }
        public abstract class printWithDeviceHub : IBqlField { }
        #endregion

        #region DefinePrinterManually
        [PXDBBool]
        [PXDefault(true)]
        public virtual bool? DefinePrinterManually { get; set; }
        public abstract class definePrinterManually : IBqlField { }
        #endregion

        #region PrinterName
        [PXPrinterSelector]
        public virtual string PrinterName { get; set; }
        public abstract class printerName : IBqlField { }
        #endregion
    }  

Configuration of the Device Hub

Vardan Vardanyan
  • 649
  • 5
  • 12
  • Any clarifying comments? What does this have to do with DeviceHub, or how would I 'associate it with DeviceHub'? – Deetz Jun 12 '19 at 13:18
  • This looks much more like I was expecting! I'm slightly confused though. There are several times you've passed both ```"ZRCRADDR"``` and ```reportID``` to a method. ```"ZRCRADDR"``` is my report. Are you operating under that assumption, or did you think that was my printer? In my code, ```"DYMOLABEL"``` is my printer. – Deetz Jun 13 '19 at 13:47
  • using this string value Acumatica **Create Primary Graph** which will be printing `("Customer"=> CustomerMaint,"Vendor"=>VendorMaint)` ,you can put `null` – Vardan Vardanyan Jun 13 '19 at 14:41
  • Your updated code is now reaching DeviceHub. But alas, the same issue exists. Jobs started in Acumatica succeed, while jobs started from code do not. I updated my question with details. – Deetz Jun 14 '19 at 18:32
0

I hesitate to post this as an answer because the code is very similar to what Vardan posted. But that code did not work for me, and this code does. It actually comes from the same link he referenced, but it's from the source code that is linked at the very end, which was added because of my comment on his post. I've modified the code slightly because I don't need it to do everything his did.

Hopefully it can help someone else.

Custom Classes:

[System.SerializableAttribute]
public partial class PrintParameters : IBqlTable, PX.SM.IPrintable
{
  #region PrintWithDeviceHub
  public abstract class printWithDeviceHub : IBqlField { }

  [PXDBBool]
  [PXDefault(typeof(FeatureInstalled<FeaturesSet.deviceHub>))]
  [PXUIField(DisplayName = "Print with DeviceHub")]
  public virtual bool? PrintWithDeviceHub { get; set; }
  #endregion

  #region DefinePrinterManually
  public abstract class definePrinterManually : IBqlField { }

  [PXDBBool]
  [PXDefault(true)]
  [PXUIField(DisplayName = "Define Printer Manually")]
  public virtual bool? DefinePrinterManually { get; set; }
  #endregion

  #region Printer
  public abstract class printerName : PX.Data.IBqlField { }

  [PX.SM.PXPrinterSelector]
  public virtual string PrinterName { get; set; }
  #endregion
}

public class CsPrintMaint : PXGraph<CsPrintMaint>
{
  public void PrintReportInDeviceHub(string reportID, Dictionary<string, string> parametersDictionary, string printerName, int? branchID)
  {
    Dictionary<string, PXReportRequiredException> reportsToPrint = new Dictionary<string, PXReportRequiredException>();
    PrintParameters filter = new PrintParameters();
    filter.PrintWithDeviceHub = true;
    filter.DefinePrinterManually = true;
    filter.PrinterName = printerName;

    reportsToPrint = PX.SM.SMPrintJobMaint.AssignPrintJobToPrinter(reportsToPrint, parametersDictionary, filter, 
           new NotificationUtility(this).SearchPrinter, CRNotificationSource.BAccount, reportID, reportID, branchID);

    if (reportsToPrint != null)
    {
      PX.SM.SMPrintJobMaint.CreatePrintJobGroups(reportsToPrint);
    }
  }
}

BusinessAccountMaint Extension:

public class BusinessAccountMaint_Extension : PXGraphExtension<BusinessAccountMaint>
{
  public PXAction<BAccount> printAddressLabelNH;
  [PXButton(CommitChanges = true)]
  [PXUIField(DisplayName = "Print Label (NH)")]
  public virtual IEnumerable PrintAddressLabelNH(PXAdapter adapter)
  {
    int? branchID = this.Base.Accessinfo.BranchID;
    Dictionary<string, string> parametersDictionary = new Dictionary<string, string>();
    BAccount bAccount = this.Base.Caches[typeof(BAccount)].Current as BAccount;
    parametersDictionary["BAccount.BAccountID"] = bAccount.BAccountID.ToString();

    CsPrintMaint printMaintGraph = PXGraph.CreateInstance<CsPrintMaint>();

    printMaintGraph.PrintReportInDeviceHub("ZRADDRBA", parametersDictionary, "DYMOLBLNH", branchID);

    return adapter.Get();
  }
}
Deetz
  • 329
  • 1
  • 16