Shipments (SO302000) is the fulfillment half of the order-to-cash flow, sitting between Sales Order and AR Invoice. The graph is ShipmentEntry; header is SOShipment, lines are SOShipLine. Confirming a shipment is the point where inventory actually leaves — before confirmation, quantities are allocated but not yet reduced from on-hand; after, an INRegister/INTran issue transaction exists and the cost of goods sold is locked in.
Pick, pack, and ship as distinct steps
Depending on configuration, a shipment can go through separate Pick List and Pack stages before Confirm Shipment — each stage updates different status fields on SOShipLine, and a customization that only hooks the final Confirm action will miss whatever business logic was supposed to happen at Pick or Pack. Warehouses using wave picking or the Warehouse Management System features rely heavily on these intermediate states; customizations built without WMS in mind often break once a client turns those features on.
Key tabs
- Details — the SOShipLine grid: item, quantity shipped, lot/serial detail, and the source Sales Order line each row traces back to.
- Financial — cost information, populated at confirmation from the consumed cost layers.
- Addresses — ship-to address, which can differ from the Sales Order's if it was overridden at shipment time.
Extending ShipmentEntry
Carrier integrations are the most common substantial customization on this screen — implementing Acumatica's shipping plugin interface to call a carrier's rating and label API from the Confirm Shipment action, rather than hand-keying tracking numbers. Smaller customizations tend to be validation: requiring a package weight before confirmation, or blocking confirmation when a lot/serial-tracked line is missing its numbers.
public class ShipmentEntry_Extension : PXGraphExtension<ShipmentEntry>
{
[PXOverride]
public void ConfirmShipment(List<SOShipment> list, Action<List<SOShipment>> baseMethod)
{
foreach (SOShipment shipment in list)
{
bool missingWeight = PXSelect<SOPackageDetail,
Where<SOPackageDetail.shipmentNbr, Equal<Required<SOPackageDetail.shipmentNbr>>,
And<SOPackageDetail.weight, Equal<decimal0>>>>
.Select(Base, shipment.ShipmentNbr).Any();
if (missingWeight)
throw new PXSetPropertyException("Enter package weight before confirming this shipment.");
}
baseMethod(list);
}
}
Custom fields and tabs via the Customization Project Editor
Adding a field to SOShipLine is routine, but like Sales Order lines, shipment data feeds forward into the invoice generated from it — a custom field meant to reach the invoice needs explicit mapping, and one meant to reach the printed Bill of Lading or packing slip needs a Report Designer change as well.
Common validation and event-handler use cases
Beyond carrier integration and weight checks: splitting a single shipment confirmation across multiple orders correctly when a picker consolidates several orders into one shipment run, validating that lot/serial numbers assigned at shipment match what was actually picked (rather than trusting manual entry), and firing a notification when a partial shipment leaves a Sales Order line with a meaningful backorder quantity remaining.
Gotchas
Confirming a shipment that covers multiple Sales Orders splits cost and quantity across each source order's lines — code that assumes a one-to-one relationship between shipment and order will misattribute cost on consolidated shipments. Cost is calculated at confirmation time based on whatever cost layers exist then, which means the same item shipped on two different days can carry two different unit costs even for what looks like an identical order. And reversing a confirmed shipment (Void/Correct) doesn't cleanly undo everything downstream if an invoice has already been generated from it — the invoice has to be dealt with first, which surprises anyone assuming a straightforward document reversal.
Once a shipment is confirmed, cost is locked in and inventory is physically reduced. Any customization meant to adjust cost, quantity, or lot assignment needs to run before confirmation — after that point, it's a correction, not a normal edit.
Wrapping up
The Shipment screen is where allocated inventory becomes an actual outbound movement, and its customizations need to respect the pick/pack/confirm stages rather than treating confirmation as the only meaningful event. Map custom fields explicitly downstream, and remember that consolidated shipments break any assumption of a clean one-to-one order relationship.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.