Reputation: 122
Hopefully I am missing something easy. This is on 2019R2.
I've added a custom button to my SO form with the idea that it's similar to the Quick Process button. The steps I need to take on the current SO are:
I'm not having a lot of luck getting it to finish properly. I've gotten steps 1 and 2 to work, step 3 seems to work (I don't get an error), but I never get an invoice for the shipment from step 4 (just the error below). Haven't even added step 5 yet.
Error: Another process has updated the 'SOShipment' record. Your changes will be lost.
Here's the implementation code:
public PXAction<PX.Objects.SO.SOOrder> AIquickProcess;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Phone Quick Process")]
protected void aIquickProcess()
{
SOOrder so = Base.CurrentDocument.Current;
if (so == null) return;
if (so.OrderType != "SO" && so.OrderType != "TR") return;
SOOrder ordercopy = (SOOrder)Base.Caches[typeof(SOOrder)].CreateCopy(so);
SOShipmentEntry shipmentEntryGraph = PXGraph.CreateInstance<SOShipmentEntry>();
DocumentList<SOShipment> shipmentDocs = new DocumentList<SOShipment>(shipmentEntryGraph);
SOLine line = PXSelect<SOLine,
Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>>>>
.Select(Base, so.OrderType, so.OrderNbr);
if (line == null) return;
DateTime? shipDate = so.ShipDate == null ? so.OrderDate : so.ShipDate;
try
{
TimeSpan timespan;
Exception ex;
// Create shipment
shipmentEntryGraph.CreateShipment(so, line.SiteID, shipDate, false, line.Operation, shipmentDocs, PXQuickProcess.ActionFlow.NoFlow);
shipmentEntryGraph.CurrentDocument.Current.ControlQty = shipmentEntryGraph.CurrentDocument.Current.ShipmentQty;
shipmentEntryGraph.CurrentDocument.Update(shipmentEntryGraph.CurrentDocument.Current);
shipmentEntryGraph.Save.Press();
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Confirm Shipment
PXAutomation.CompleteSimple(shipmentEntryGraph.Document.View);
PXAdapter adapter2 = new PXAdapter(new DummyView(shipmentEntryGraph, shipmentEntryGraph.Document.View.BqlSelect,
new List<object> { shipmentEntryGraph.Document.Current }));
adapter2.Menu = SOShipmentEntryActionsAttribute.Messages.ConfirmShipment;
adapter2.Arguments = new Dictionary<string, object>
{
{"actionID", SOShipmentEntryActionsAttribute.ConfirmShipment}
};
adapter2.Searches = new object[] { shipmentEntryGraph.Document.Current.ShipmentNbr };
adapter2.SortColumns = new[] { "ShipmentNbr" };
shipmentEntryGraph.action.PressButton(adapter2);
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Update IN
shipmentEntryGraph.UpdateIN.Press();
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
shipmentEntryGraph.CurrentDocument.UpdateCurrent();
// create invoice
adapter2 = new PXAdapter(new DummyView(shipmentEntryGraph, shipmentEntryGraph.Document.View.BqlSelect,
new List<object> { shipmentEntryGraph.Document.Current }));
adapter2.Menu = SOShipmentEntryActionsAttribute.Messages.CreateInvoice;
adapter2.Arguments = new Dictionary<string, object>
{
{"actionID", SOShipmentEntryActionsAttribute.CreateInvoice}
};
adapter2.Searches = new object[] { shipmentEntryGraph.Document.Current.ShipmentNbr };
adapter2.SortColumns = new[] { "ShipmentNbr" };
shipmentEntryGraph.action.PressButton(adapter2);
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
// getting: Error: Another process has updated the 'SOShipment' record. Your changes will be lost.
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
}
catch (SOShipmentException ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
throw;
}
catch (Exception ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
shipmentEntryGraph.Clear();
throw;
}
}
Here's the code for the DummyView
public class DummyView : PXView
{
List<object> _Records;
internal DummyView(PXGraph graph, BqlCommand command, List<object> records) : base(graph, true, command)
{
_Records = records;
}
public override List<object> Select(object[] currents, object[] parameters, object[] searches, string[] sortcolumns,
bool[] descendings, PXFilterRow[] filters, ref int startRow, int maximumRows, ref int totalRows)
{
return _Records;
}
}
Here is a version that sometimes works to create and release the invoice, but I still get the same error. I've noticed that I get the error on the UpdateIN.Press() step when the inventory item would go negative (which is allowed).
public PXAction<PX.Objects.SO.SOOrder> AIquickProcess;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Phone Quick Process")]
protected void aIquickProcess()
{
SOOrder so = Base.CurrentDocument.Current;
if (so == null) return;
if (so.OrderType != "SO" && so.OrderType != "TR") return;
SOOrder ordercopy = (SOOrder)Base.Caches[typeof(SOOrder)].CreateCopy(so);
SOShipmentEntry shipmentEntryGraph = PXGraph.CreateInstance<SOShipmentEntry>();
DocumentList<SOShipment> shipmentDocs = new DocumentList<SOShipment>(shipmentEntryGraph);
SOLine line = PXSelect<SOLine,
Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>>>>
.Select(Base, so.OrderType, so.OrderNbr);
if (line == null) return;
DateTime? shipDate = so.ShipDate == null ? so.OrderDate : so.ShipDate;
try
{
TimeSpan timespan;
Exception ex;
// Create shipment
shipmentEntryGraph.CreateShipment(so, line.SiteID, shipDate, false, line.Operation, shipmentDocs, PXQuickProcess.ActionFlow.NoFlow);
shipmentEntryGraph.CurrentDocument.Current.ControlQty = shipmentEntryGraph.CurrentDocument.Current.ShipmentQty;
shipmentEntryGraph.CurrentDocument.Update(shipmentEntryGraph.CurrentDocument.Current);
shipmentEntryGraph.Save.Press();
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Confirm Shipment
PXAutomation.CompleteSimple(shipmentEntryGraph.Document.View);
PXAdapter adapter2 = new PXAdapter(new DummyView(shipmentEntryGraph, shipmentEntryGraph.Document.View.BqlSelect,
new List<object> { shipmentEntryGraph.Document.Current }));
adapter2.Menu = SOShipmentEntryActionsAttribute.Messages.ConfirmShipment;
adapter2.Arguments = new Dictionary<string, object>
{
{"actionID", SOShipmentEntryActionsAttribute.ConfirmShipment}
};
adapter2.Searches = new object[] { shipmentEntryGraph.Document.Current.ShipmentNbr };
adapter2.SortColumns = new[] { "ShipmentNbr" };
shipmentEntryGraph.action.PressButton(adapter2);
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Update IN
PXAutomation.CompleteSimple(shipmentEntryGraph.Document.View);
shipmentEntryGraph.UpdateIN.Press();
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Create and release invoice
SOInvoiceEntry invoiceEntryGraph = PXGraph.CreateInstance<SOInvoiceEntry>();
DocumentList<ARInvoice, SOInvoice> created = new ShipmentInvoices(shipmentEntryGraph);
shipmentEntryGraph.SelectTimeStamp();
invoiceEntryGraph.SelectTimeStamp();
PXProcessing<SOShipment>.SetCurrentItem(shipmentEntryGraph.CurrentDocument.Current);
shipmentEntryGraph.InvoiceShipment(invoiceEntryGraph, shipmentEntryGraph.CurrentDocument.Current, Base.Accessinfo.BusinessDate.Value, created, PXQuickProcess.ActionFlow.NoFlow);
invoiceEntryGraph.CurrentDocument.Current.CreditHold = false;
invoiceEntryGraph.Save.Press();
invoiceEntryGraph.release.Press();
}
catch (SOShipmentException ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
throw;
}
catch (Exception ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
shipmentEntryGraph.Clear();
throw;
}
}
Upvotes: 0
Views: 212
Reputation: 122
Since I need to invoice in the same step, I don't think the call to Update IN is necessary, and when taking that out, it seems to work fairly reliably.
What I'm currently using is below and I'm open to some feedback on how to make it better.
public PXAction<PX.Objects.SO.SOOrder> AIquickProcess;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Phone Quick Process")]
protected void aIquickProcess()
{
SOOrder so = Base.CurrentDocument.Current;
if (so == null) return;
if (so.OrderType != "SO" && so.OrderType != "TR") return;
SOOrder ordercopy = (SOOrder)Base.Caches[typeof(SOOrder)].CreateCopy(so);
SOShipmentEntry shipmentEntryGraph = PXGraph.CreateInstance<SOShipmentEntry>();
DocumentList<SOShipment> shipmentDocs = new DocumentList<SOShipment>(shipmentEntryGraph);
SOLine line = PXSelect<SOLine,
Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>>>>
.Select(Base, so.OrderType, so.OrderNbr);
if (line == null) return;
DateTime? shipDate = so.ShipDate == null ? so.OrderDate : so.ShipDate;
try
{
TimeSpan timespan;
Exception ex;
// Create shipment
shipmentEntryGraph.CreateShipment(so, line.SiteID, shipDate, false, line.Operation, shipmentDocs, PXQuickProcess.ActionFlow.NoFlow);
shipmentEntryGraph.CurrentDocument.Current.ControlQty = shipmentEntryGraph.CurrentDocument.Current.ShipmentQty;
shipmentEntryGraph.CurrentDocument.Update(shipmentEntryGraph.CurrentDocument.Current);
shipmentEntryGraph.Save.Press();
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Confirm Shipment
PXAutomation.CompleteSimple(shipmentEntryGraph.Document.View);
PXAdapter adapter2 = new PXAdapter(new DummyView(shipmentEntryGraph, shipmentEntryGraph.Document.View.BqlSelect,
new List<object> { shipmentEntryGraph.Document.Current }));
adapter2.Menu = SOShipmentEntryActionsAttribute.Messages.ConfirmShipment;
adapter2.Arguments = new Dictionary<string, object>
{
{"actionID", SOShipmentEntryActionsAttribute.ConfirmShipment}
};
adapter2.Searches = new object[] { shipmentEntryGraph.Document.Current.ShipmentNbr };
adapter2.SortColumns = new[] { "ShipmentNbr" };
shipmentEntryGraph.action.PressButton(adapter2);
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Update IN
//PXAutomation.CompleteSimple(shipmentEntryGraph.Document.View);
//shipmentEntryGraph.UpdateIN.Press();
//while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
//{ }
//if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
// Create and release invoice
SOInvoiceEntry invoiceEntryGraph = PXGraph.CreateInstance<SOInvoiceEntry>();
DocumentList<ARInvoice, SOInvoice> created = new ShipmentInvoices(shipmentEntryGraph);
shipmentEntryGraph.SelectTimeStamp();
invoiceEntryGraph.SelectTimeStamp();
PXProcessing<SOShipment>.SetCurrentItem(shipmentEntryGraph.CurrentDocument.Current);
shipmentEntryGraph.InvoiceShipment(invoiceEntryGraph, shipmentEntryGraph.CurrentDocument.Current, Base.Accessinfo.BusinessDate.Value, created, PXQuickProcess.ActionFlow.NoFlow);
while (PXLongOperation.GetStatus(shipmentEntryGraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
if (ex != null && ex.Message.ToLower() != "nothing in progress" && ex.Message.ToLower() != "the operation has completed.") throw ex;
invoiceEntryGraph.CurrentDocument.Current.CreditHold = false;
invoiceEntryGraph.Save.Press();
invoiceEntryGraph.release.Press();
}
catch (SOShipmentException ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
throw;
}
catch (Exception ex)
{
Base.Caches[typeof(SOOrder)].RestoreCopy(so, ordercopy);
shipmentEntryGraph.Clear();
throw;
}
}
public class DummyView : PXView
{
List<object> _Records;
internal DummyView(PXGraph graph, BqlCommand command, List<object> records) : base(graph, true, command)
{
_Records = records;
}
public override List<object> Select(object[] currents, object[] parameters, object[] searches, string[] sortcolumns,
bool[] descendings, PXFilterRow[] filters, ref int startRow, int maximumRows, ref int totalRows)
{
return _Records;
}
}
Upvotes: 0