Skip to main content
Answer

Trying to update a custom field on SOLine after shipment has been created

  • November 13, 2025
  • 4 replies
  • 49 views

Joe Schmucker
Captain II
Forum|alt.badge.img+3

When a user clicks Create Shipment on the Sales Order screen, I want to update each line of the Sales Order with the current date if the line was shipped.

I tried 10 different ways to do this.  The easiest way I though of was to use the SOShipLine Row Persisting or Row Persisted method on the Shipments graph extension.  In those methods, I tried to get the SOLine related to the SOShipmentLine being saved to the DB and update the SOLine custom field.  This throws an error the the SOLine is already updated and the update to SOLine is rolled back.

My next approach is to override the CreateShipmentIssue method that is called when you click Create Shipment.  I am invoking the method, then trying to update the SOLine after the method has been invoked.

After the method has been invoked, I try to get the SOShipLine where the SOLine has the SOShipLine.origOrderNbr, SOShipLine.origLineNbr, and SOShipLine.origOrderType fields.

However, the select returns null.  I think this is because the Shipment has not been committed yet.

My question is, how and where can I capture the shipment lines that were processed and go back to the Sales Order lines to update them?

This is my override.  Note that it fires, but the Shipment doesn’t seem to be committed yet, so the SOShipLine comes back null.

public delegate IEnumerable CreateShipmentIssueDelegate(PXAdapter adapter, [PXDate] DateTime?
shipDate, [PXInt] int? siteID, [PXDate] DateTime? endDate);
[PXButton(CommitChanges = true), PXUIField(DisplayName = "Create Shipment", MapEnableRights = PXCacheRights.Select)]
[PXOverride]
public virtual IEnumerable CreateShipmentIssue(PXAdapter adapter, [PXDate] DateTime?
shipDate, [PXInt] int? siteID, [PXDate] DateTime? endDate, CreateShipmentIssueDelegate baseMethod)
{

var result = baseMethod.Invoke(adapter, shipDate, siteID, endDate);

foreach (SOLine line in Base.Transactions.Select())
{
SOShipLine shipLine = SelectFrom<SOShipLine>
.Where<SOShipLine.origOrderNbr.IsEqual<@P.AsString>
.And<SOShipLine.origLineNbr.IsEqual<@P.AsInt>>
.And<SOShipLine.origOrderType.IsEqual<@P.AsString>>>
.View.Select(Base, line.OrderNbr, line.LineNbr, line.OrderType);
if (shipLine != null)
{
SOShipment shipment = SelectFrom<SOShipment>
.Where<SOShipment.shipmentNbr.IsEqual<@P.AsString>
.And<SOShipment.shipmentType.IsEqual<@P.AsString>>>
.View.Select(Base, shipLine.ShipmentNbr, shipLine.ShipmentType);


if (shipment.Confirmed == true && shipLine.ShippedQty > 0)
{
SCGCSOLineExt ext = line.GetExtension<SCGCSOLineExt>();
if (ext != null)
{
if (ext.UsrCreatedShipmentDate != null)
{
ext.UsrCreatedShipmentDate = PX.Common.PXTimeZoneInfo.Now;
Base.Transactions.Update(line);
}
}
}
}
}
return result;
}

 

Best answer by Django

One option is to override the SOShipmentEntry.Persist event. Call the Base method and then you’ll have access to the contents of the committed shipment. That will let you go through the shipment lines and update the SOLine records (via an SOOrderEntry graph extension).

You can also look to see if the adapter variable in your code contains the shipment number that you can use to load up the shipment and then update the SOLine records.

4 replies

Forum|alt.badge.img+7
  • Captain II
  • Answer
  • November 13, 2025

One option is to override the SOShipmentEntry.Persist event. Call the Base method and then you’ll have access to the contents of the committed shipment. That will let you go through the shipment lines and update the SOLine records (via an SOOrderEntry graph extension).

You can also look to see if the adapter variable in your code contains the shipment number that you can use to load up the shipment and then update the SOLine records.


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • November 14, 2025

Hi ​@Django, I’ve never did an override on persist event.  I’ll try to find how to do that.  I did look at the adapter in debug after the call, but I didn’t see anything data related.  Getting info from an adapter is also something I’ve never needed to do, so it might just be that I’m a noob.  I’ll try looking at it again, but the Persist is probably the way to go. 

Thanks for the tips!


Forum|alt.badge.img+7
  • Captain II
  • November 14, 2025

It’s pretty straight forward to override the Persist method.

 

    public delegate void PersistDelegate();
[PXOverride]
public void Persist(Action del)
{
//stuff you need to do before persisting the data to the database
del();
//stuff you need to do after persisting the data to the database
//for your requirements, you'd update the SO records here
}

 


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • November 14, 2025

Thank you so much!

This was the code I ended up with that is working.  There is probably a better way to do it, but it works.

		public delegate void PersistDelegate(Action action);
[PXOverride]
public void Persist(Action del)
{
SOShipment shipment = Base.Document.Current;

try
{
del();
if (shipment != null)
{
UpdateSOLines(shipment);
}
}
catch (Exception ex)
{
PXTrace.WriteError(ex.Message);
}
}

public void UpdateSOLines(SOShipment shipment)
{
if (shipment == null) return;

bool changesMade = false;

var myGraph = PXGraph.CreateInstance<SOOrderEntry>();

//do this to get the original order and original order type
SOShipLine temp = SelectFrom<SOShipLine>
.Where<SOShipLine.shipmentNbr.IsEqual<@P.AsString>
.And<SOShipLine.shipmentType.IsEqual<@P.AsString>>>
.View.Select(myGraph, shipment.ShipmentNbr, shipment.ShipmentType).FirstOrDefault();
if (temp != null)
{
SOOrder soOrder = SelectFrom<SOOrder>.Where<SOOrder.orderNbr.IsEqual<@P.AsString>.And<SOOrder.orderType.IsEqual<@P.AsString>>>
.View.Select(myGraph, temp.OrigOrderNbr, temp.OrigOrderType);
if (soOrder != null)
{
myGraph.Document.Current = soOrder;

foreach (SOLine soLine in myGraph.Transactions.Select())
{
SOShipLine shipLine = SelectFrom<SOShipLine>
.Where<SOShipLine.origOrderNbr.IsEqual<@P.AsString>
.And<SOShipLine.origOrderType.IsEqual<@P.AsString>>
.And<SOShipLine.origLineNbr.IsEqual<@P.AsInt>>>
.View.Select(Base, soLine.OrderNbr, soLine.OrderType, soLine.LineNbr);
if (shipLine != null && shipLine.ShippedQty > 0)
{
SCGCSOLineExt ext = soLine.GetExtension<SCGCSOLineExt>();
if (ext != null)
{
if (ext.UsrCreatedShipmentDate == null)
{
PXDatabase.Update<SOLine>(
new PXDataFieldAssign(typeof(SCGCSOLineExt.usrCreatedShipmentDate).Name, PXDbType.DateTime, PX.Common.PXTimeZoneInfo.Now),
new PXDataFieldRestrict(typeof(SOLine.orderNbr).Name, PXDbType.VarChar, shipLine.OrigOrderNbr),
new PXDataFieldRestrict(typeof(SOLine.orderType).Name, PXDbType.VarChar, shipLine.OrigOrderType),
new PXDataFieldRestrict(typeof(SOLine.lineNbr).Name, PXDbType.Int, shipLine.OrigLineNbr));

changesMade = true;
}
}
}
}
if (changesMade == true)
{
myGraph.Persist();
}
}
}
}