Warehouse picking completed
Fires when warehouse management (WHS) picking work for an order is closed: sales picking, transfer order issue, production raw material picking, or kanban picking work with at least one completed Pick line. The payload carries the work order type, the order, shipment and load references, and one entry per completed Pick line with its own item, quantity, unit, location, and the warehouse user who picked it. Downstream WMS, OMS, or customer-notification systems can use it as a "pick completed with quantities" signal without querying the work lines. It's raised from the same hook as Warehouse Work Completed, and each of the two can be activated on its own.
| Event class | MGCLatticeWarehousePickingCompletedBusinessEvent |
| Contract class | MGCLatticeWarehousePickingCompletedBusinessEventContract |
| Category | Warehouse management |
| Module | ModuleAxapta::Warehouse |
| Label IDs | WarehousePickingCompletedBusinessEventName / WarehousePickingCompletedBusinessEventDescription |
| Trigger | WHSWorkTable.update() -> WorkStatus changes to WHSWorkStatus::Closed for picking work with at least one closed Pick line |
Trigger / Hook
- Extension class:
MGCLatticeWHSWorkTable_Table_Extension, decorated with[ExtensionOf(tableStr(WHSWorkTable))]. - CoC method signature:
public void update()(Chain of Command wrap ofWHSWorkTable.update()). - Firing condition: the original
WorkStatusis captured withthis.orig().WorkStatusbeforenext update(). After the update, when the status actually changed and the new status isWHSWorkStatus::Closed, and the event is activated,newFromWorkIfPicking(this):- returns null unless the work order type (
WorkTransType) isSales,TransferIssue,ProdPickorKanbanPick; - returns null unless the work has at least one
WHSWorkLinewithWorkType == PickandWorkStatus == Closed. No event is sent when it returns null.
- returns null unless the work order type (
- Which work qualifies: order picking only. Put-away, replenishment, movement, counting and other work whose template starts with a Pick line (the pick half of a pick and put pair) doesn't qualify. Packed container picking and sorted inventory picking don't qualify either, because they move goods that the order's picking work has already picked.
- Not raised: when work is closed by a set-based update, because the hook wraps
update()only. Picking work isn't created already closed by the standard application, so there's no insert hook for this event (a work header is inserted before its lines). - Transaction: the event is sent inside the work-closing transaction; it's written to the business events commit log and delivered only if that transaction commits.
- Enablement gate:
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeWarehousePickingCompletedBusinessEvent))is checked before any lookup, so nothing runs when the event isn't activated.
public static MGCLatticeWarehousePickingCompletedBusinessEvent newFromWorkIfPicking(WHSWorkTable _whsWorkTable)
{
WHSWorkLine workLine;
if (!MGCLatticeWarehousePickingCompletedBusinessEvent::isPickingWorkTransType(_whsWorkTable.WorkTransType))
{
return null;
}
select firstonly RecId from workLine
where workLine.WorkId == _whsWorkTable.WorkId
&& workLine.WorkType == WHSWorkType::Pick
&& workLine.WorkStatus == WHSWorkStatus::Closed;
if (!workLine.RecId)
{
return null;
}
// ... builds the event ...
}
Payload Contract
One row per [DataMember], in declaration order. Header fields come from the closed WHSWorkTable record; lines is read from the work's closed Pick lines (WHSWorkLine with WorkType == Pick and WorkStatus == Closed, in line number order) in initialize(). Canceled and skipped Pick lines picked nothing and aren't listed.
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | WHSWorkTable.DataAreaId | Company of the work |
workId | Work ID | WHSWorkId | WHSWorkTable.WorkId | |
workTransType | Work Transaction Type | int | enum2int(WHSWorkTable.WorkTransType) | WHSWorkTransType value: 2 = Sales, 3 = ProdPick, 5 = TransferIssue, 13 = KanbanPick |
workTransTypeName | Work Transaction Type Name | str | enum2Symbol(enumNum(WHSWorkTransType), ...) | Symbol of the work order type, for example Sales |
orderNumber | Order Number | WHSOrderNum | WHSWorkTable.OrderNum | Order that generated the work |
shipmentId | Shipment ID | WHSShipmentId | WHSWorkTable.ShipmentId | Blank when the work has no shipment |
loadId | Load ID | WHSLoadId | WHSWorkTable.LoadId | Blank when the work has no load |
warehouseId | Warehouse ID | InventLocationId | WHSWorkTable.InventLocationId | |
siteId | Site ID | InventSiteId | WHSWorkTable.InventSiteId | |
pickLineCount | Pick Line Count | int | Number of entries in lines | Closed Pick lines only |
workClosedDateTime | Work Closed Date Time | WHSWorkClosedUTCDateTime | WHSWorkTable.WorkClosedUTCDateTime | UTC date and time the work closed |
lines | Lines | List of MGCLatticeWarehousePickLineContract | See below | JSON array, one element per closed Pick line |
Each element of lines (MGCLatticeWarehousePickLineContract, built by newFromWHSWorkLine() from a closed Pick line):
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
lineNumber | Line Number | LineNum | WHSWorkLine.LineNum | Work line number |
itemId | Item Number | ItemId | WHSWorkLine.ItemId | |
quantity | Quantity | Qty | WHSWorkLine.QtyWork | Quantity picked on the line, in unitId |
unitId | Unit | UnitOfMeasureSymbol | WHSWorkLine.UnitId | Unit of quantity |
inventoryQuantity | Inventory Quantity | InventQty | WHSWorkLine.InventQtyWork | Quantity picked on the line, in the item's inventory unit; add these up to total an item across lines |
locationId | Location | WMSLocationId | WHSWorkLine.WMSLocationId | Location picked from |
inventTransId | Inventory Transaction ID | InventTransId | WHSWorkLine.InventTransId | Lot ID of the order line the pick is for |
pickedByUser | Picked By User | WHSUserId | WHSWorkLine.UserId | Warehouse (mobile device) user who picked the line |
pickedDateTime | Picked Date Time | WHSWorkClosedUTCDateTime | WHSWorkLine.WorkClosedUTCDateTime | UTC date and time the line was closed |
Every Lattice event also carries the Lattice ordering and correlation envelope, inherited from MGCLatticeBusinessEventContractBase: eventSequence (Int64 - increasing across the whole catalog and all companies, allocated when the event is raised inside the business transaction rather than when it commits; it orders the events of one business record, gaps are permanent and normal, and it must not be used to re-sequence the whole stream), correlationId (String, always Scope:Key - groups emissions that belong to one logical run; Event:<GUID> unique to this emission when the event belongs to no run) and schemaVersion (Int - the payload shape version; 1 for this contract). D365 F&O also adds its standard envelope fields to every business event payload: BusinessEventId, BusinessEventLegalEntity, ContextRecordSubject, ControlNumber, EventId, EventTime, EventTimeIso8601, InitiatingUserAADObjectId, MajorVersion, MinorVersion, and ParentContextRecordSubjects. Do not rely on the order of members in the delivered JSON.
Example Payload
{
"BusinessEventId": "MGCLatticeWarehousePickingCompletedBusinessEvent",
"ControlNumber": 5637146377,
"EventId": "2F6A9D31-7B04-4E5C-9C28-E1B3F07A6D94",
"EventTime": "\/Date(1790268112000)\/",
"EventTimeIso8601": "2026-09-24T16:41:52.5147490Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{4B42D8BA-0B64-11F3-2278-EF002884D372}",
"ParentContextRecordSubjects": [],
"eventSequence": 48519,
"correlationId": "Event:74f6e9e7-a50f-4523-8f6f-e63b402299e5",
"schemaVersion": 1,
"legalEntity": "usmf",
"workId": "USMF-004821",
"workTransType": 2,
"workTransTypeName": "Sales",
"orderNumber": "000874",
"shipmentId": "USMF-000291",
"loadId": "USMF-000137",
"warehouseId": "24",
"siteId": "2",
"pickLineCount": 2,
"workClosedDateTime": "\/Date(1790268110000)\/",
"lines": [
{
"lineNumber": 1.0,
"itemId": "A0001",
"quantity": 24.0,
"unitId": "ea",
"inventoryQuantity": 24.0,
"locationId": "24-01-01",
"inventTransId": "012587",
"pickedByUser": "24",
"pickedDateTime": "\/Date(1790267950000)\/"
},
{
"lineNumber": 3.0,
"itemId": "A0002",
"quantity": 1.0,
"unitId": "box",
"inventoryQuantity": 12.0,
"locationId": "24-02-03",
"inventTransId": "012588",
"pickedByUser": "24",
"pickedDateTime": "\/Date(1790268080000)\/"
}
]
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Warehouse picking completed") or by filtering the Category column to Warehouse management. Select it and use Activate to bind it to a configured endpoint (for example, an Azure Service Bus queue, Event Grid topic, or HTTPS webhook).
No other setup is needed; the event doesn't depend on Warehouse Work Completed being activated.