Skip to main content

I have the following code set up which prints to a specific hard coded printer name on the devicehub. I’m stumped as to how to create the selector to get a list of printers from the devicehub.  This is what I have so far which doesn’t work correctly as clicking on the selector gives an error: Object reference not set to an instance of an object.

 

The code is below:

using System;
using PX.Data;
using PX.Objects.SO;
using PX.Data.BQL.Fluent;
using PX.TM;
using PX.Common;
using System.Collections.Generic;
using PX.Objects.CR;
using PX.SM;
using PX.Reports;
using System.Threading.Tasks;
using System.Threading;

namespace PPCustomOrderProcess
{

public class AIProcessOrdersCust : PXGraph<AIProcessOrdersCust>
{

/PXString]
/PXUIField(DisplayName = "Printer")]
/PXSelector(
typeof(Search<SMPrinter.printerID>),
typeof(SMPrinter.printerName),
typeof(SMPrinter.description),
SubstituteKey = typeof(SMPrinter.printerName),
DescriptionField = typeof(SMPrinter.description))]
public virtual Guid? SelectedPrinter { get; set; }
public abstract class selectedPrinter : PX.Data.BQL.BqlGuid.Field<selectedPrinter> { }

public class wOOrderType: PX.Data.BQL.BqlString.Constant<wOOrderType> {
public wOOrderType() : base("WO") { }
}

public class paymentMethodAFFIRM: PX.Data.BQL.BqlString.Constant<paymentMethodAFFIRM> {
public paymentMethodAFFIRM() : base("AFFIRM") { }
}

public class paymentMethodAFTERPAY: PX.Data.BQL.BqlString.Constant<paymentMethodAFTERPAY> {
public paymentMethodAFTERPAY() : base("AFTERPAY") { }
}

public class paymentMethodPAYPAL: PX.Data.BQL.BqlString.Constant<paymentMethodPAYPAL> {
public paymentMethodPAYPAL() : base("PAYPAL") { }
}

public class paymentMethodCCARD: PX.Data.BQL.BqlString.Constant<paymentMethodCCARD> {
public paymentMethodCCARD() : base("CCARD") { }
}

public class dropShipStart: PX.Data.BQL.BqlString.Constant<dropShipStart> {
public dropShipStart() : base("DS%") { }
}

public class signatureWaived: PX.Data.BQL.BqlString.Constant<signatureWaived> {
public signatureWaived() : base("%SIGNATURE WAIVED%") { }
}

public class intlShipVia: PX.Data.BQL.BqlString.Constant<intlShipVia> {
public intlShipVia() : base("%intl%") { }
}

public class orderTotalMaxSpend: PX.Data.BQL.BqlDecimal.Constant<orderTotalMaxSpend> {
public orderTotalMaxSpend() : base(500m) { }
}

public PXCancel<SOOrder> Cancel;

// Create an alias for clarity
public class OuterSOOrder : SOOrder { }

public SelectFrom<SOOrder>
.LeftJoin<Note>.On<SOOrder.noteID.IsEqual<Note.noteID>>
.Where<
SOOrder.orderType.IsEqual<wOOrderType>
.And<
SOOrder.shipVia.IsNotLike<intlShipVia>
>
.And<
SOOrder.shipVia.IsNotLike<dropShipStart>
>
.And<
SOOrder.status.IsEqual<SOOrderStatus.open>
>
.And<
Note.noteID.IsNull
.Or<Note.noteText.IsNull>
.Or<Note.noteText.IsEqual<Empty>>
.Or<Note.noteText.IsLike<signatureWaived>>
>
.And<
SOOrder.curyOrderTotal.IsLessEqual<orderTotalMaxSpend>
>
.And<
SOOrder.paymentMethodID.IsEqual<paymentMethodAFFIRM>
.Or<SOOrder.paymentMethodID.IsEqual<paymentMethodPAYPAL>>
.Or<SOOrder.paymentMethodID.IsEqual<paymentMethodAFTERPAY>>
.Or<
SOOrder.paymentMethodID.IsEqual<paymentMethodCCARD>
.And<
Exists<SelectFrom<SOOrder>
.Where<
SOOrder.paymentMethodID.IsEqual<paymentMethodCCARD>
.And<
SOOrder.customerID.IsEqual<OuterSOOrder.customerID>
>
.And<
SOOrder.status.IsEqual<SOOrderStatus.shipping> // Change shipping to completed before final publish
>
>
>
>
>
>
>
.ProcessingView AISOOrder;


public AIProcessOrdersCust()
{
AISOOrder.SetProcessCaption("Assign");
AISOOrder.SetProcessAllCaption("Assign All");

AISOOrder.SetProcessDelegate(ProcessOrder);
}

public PXFilter<DetailsTable> DetailsView;

/Serializable]
public class DetailsTable : IBqlTable
{

}

/// <summary>
/// Processing Method to Assign Owner to Logged-in User
/// </summary>
private static void ProcessOrder(SOOrder order)
{
var graph = PXGraph.CreateInstance<SOOrderEntry>();

// Select the order
graph.Document.Current = graph.Document.Search<SOOrder.orderNbr>(order.OrderNbr, order.OrderType);

if (graph.Document.Current != null)
{
int? currentUserContactID = PXAccess.GetContactID();
if (currentUserContactID != null)
{
graph.Document.Cache.SetValueExt<SOOrder.ownerID>(graph.Document.Current, currentUserContactID);
graph.Document.Cache.MarkUpdated(graph.Document.Current);

// Log the new OwnerID for verification
PXTrace.WriteInformation($"Setting OwnerID to {currentUserContactID} for Order {order.OrderNbr}");

// Save the changes
graph.Actions.PressSave();

// Create a shipment for the order

bool shipmentCreated = CreateShipmentFromButton(graph);

// Confirm the shipmnent is created before pressing the new button

if (shipmentCreated)
{
// Retrieve the Shipment Number
var shipmentNbr = GetShipmentNumber(order);

if (!string.IsNullOrEmpty(shipmentNbr))
{
// Load shipment graph and print the shipment confirmation
var shipmentGraph = PXGraph.CreateInstance<SOShipmentEntry>();
var shipment = shipmentGraph.Document.Search<SOShipment.shipmentNbr>(shipmentNbr);

if (shipment != null)
{
bool printedShipmentConfirmation = PrintShipmentConfirmation(shipmentGraph, shipmentNbr);

if (printedShipmentConfirmation)
{
PXProcessing<SOOrder>.SetInfo($"Order {order.OrderNbr} successfully assigned to user with ContactID: {currentUserContactID} and shipment {shipmentNbr} printed.");
}
else
{
PXProcessing<SOOrder>.SetInfo($"Order {order.OrderNbr} successfully assigned to user with ContactID: {currentUserContactID} and shipment {shipmentNbr} created but not printed.");
}
}
else
{
PXProcessing<SOOrder>.SetError($"Order {order.OrderNbr} successfully assigned to user with ContactID: {currentUserContactID}, but shipment could not be retrieved to print.");
}
}
else
{
PXProcessing<SOOrder>.SetWarning($"Shipment created, but no shipment number found for Order {order.OrderNbr}.");
}
}
else
{
PXProcessing<SOOrder>.SetError($"Order {order.OrderNbr} successfully assigned to user with ContactID: {currentUserContactID}, but shipment could not be created.");
}
}
else
{
PXProcessing<SOOrder>.SetError($"Failed to assign OwnerID: No ContactID found for current user.");
}
}
else
{
PXProcessing<SOOrder>.SetError($"Order {order.OrderNbr} not found.");
}
}


private static Guid GetPrinterIdByName(string printerName, PXGraph printGraph)
{
// Query the SMPrinter table for a printer with the specified printerName
var printer = PXSelect<SMPrinter,
Where<SMPrinter.printerName, Equal<Required<SMPrinter.printerName>>>>.Select(printGraph, printerName);

if (printer != null && printer.Count > 0)
{
SMPrinter smPrinter = printerr0];

if (smPrinter.PrinterID.HasValue)
{
return smPrinter.PrinterID.Value; // Return the PrinterID as a non-nullable Guid
}
else
{
// Handle the case where PrinterID is null
throw new Exception($"Printer '{printerName}' has a null PrinterID.");
}
}

// Handle the case where the printer wasn't found
throw new Exception($"Printer '{printerName}' not found.");
}

private static bool PrintShipmentConfirmation(SOShipmentEntry shipmentGraph, string shipmentNbr)
{
bool success = false;

if (string.IsNullOrEmpty(shipmentNbr))
{
throw new PXException("Shipment Number is required for printing.");
}

try
{
const string reportID = "SO642000";
const string description = "Shipment Confirmation";

var parametersDictionary = new Dictionary<string, string>
{
{ "ShipmentNbr", shipmentNbr },
// Add other parameters if necessary
};

PXGraph printGraph = PXGraph.CreateInstance<SMPrintJobMaint>();
// Step 2: Define the print settings
PrintSettings printSettings = new PrintSettings()
{
PrinterID = GetPrinterIdByName("W2PDFHUB", printGraph), // Replace with logic to get the default printer ID
//PrinterID = printerID,
NumberOfCopies = 1,
PrintWithDeviceHub = true,
DefinePrinterManually = true
};

// Step 3: Create the print job
PXGraph.CreateInstance<SMPrintJobMaint>().CreatePrintJob(printSettings, reportID, parametersDictionary, "Shipment Confirmation", CancellationToken.None);

// Log or handle any post-print actions
PXTrace.WriteInformation("Shipment Confirmation print job initiated.");

}
catch (Exception ex)
{
PXTrace.WriteError($"Failed to print Shipment Confirmation for {shipmentNbr}. Error: {ex.Message}");
throw new PXException($"Failed to print Shipment Confirmation for {shipmentNbr}. Please check the printer configuration.");
}
finally
{
success = true;
}

return success;
}

/// <summary>
/// Retrieves the Shipment Number associated with the order.
/// </summary>
private static string GetShipmentNumber(SOOrder order)
{
var shipment = PXSelect<SOOrderShipment,
Where<SOOrderShipment.orderType, Equal<Required<SOOrderShipment.orderType>>,
And<SOOrderShipment.orderNbr, Equal<Required<SOOrderShipment.orderNbr>>>>>
.SelectWindowed(new PXGraph(), 0, 1, order.OrderType, order.OrderNbr);

return shipment != null ? ((SOOrderShipment)shipment).ShipmentNbr : null;
}

private static bool CreateShipmentFromButton(SOOrderEntry graph)
{

// Trigger the "Create Shipment" action on the graph (simulate button click)
PXAction<SOOrder> createShipmentAction = graph.Actionsc"CreateShipment"] as PXAction<SOOrder>;
if (createShipmentAction != null)
{
// If the button exists, press it programmatically
PXTrace.WriteInformation($"Pressing button for create shipment");

createShipmentActionPress(graph);

return true;
}
else
{
PXTrace.WriteError("Create Shipment action not found.");
}
return false;

}

private static void createShipmentActionPress(SOOrderEntry graph)
{
try
{
PXAction<SOOrder> createShipmentAction = graph.Actionsc"CreateShipment"] as PXAction<SOOrder>;
createShipmentAction?.Press();
}
catch (Exception ex)
{
PXTrace.WriteError("Error pressing Create Shipment button: " + ex.Message);
}
}

}
}

 

I wonder if you need to change your declaration from

[PXString]

to

[PXGuid]

The APTran.cs file has the Custodian field which is using EPEmployee.userID like you’re using PrinterID


@Django Thanks.  That was really helpful.  I ended up changing to a Guid but also needed to add a PXFilter :

public PXFilter<PrinterFilter> PrinterView;

>Serializable]
public class PrinterFilter : IBqlTable
{
#region PrinterID
PXGuid]
PXUIField(DisplayName = "Printer")]
PXSelector(
typeof(Search<SMPrinter.printerID>), // Assuming printerID is the GUID field
typeof(SMPrinter.printerName),
typeof(SMPrinter.description),
SubstituteKey = typeof(SMPrinter.printerName),
DescriptionField = typeof(SMPrinter.description),
DirtyRead = true)]
public virtual Guid? PrinterID { get; set; }
public abstract class printerID : PX.Data.BQL.BqlGuid.Field<printerID> { }
#endregion
}

Once I added that to the screen I could select a printer.

 

Thanks for your help,

 

Phil


Reply