Transfer order received
Fires when an inventory transfer order completes receiving at the destination warehouse and its status transitions to Received. This signals that goods shipped between warehouses have physically arrived and been put into receiving inventory, allowing downstream systems to reconcile in-transit stock, close the transfer cycle, and update availability at the receiving location.
| Event class | MGCLatticeTransferOrderReceivedBusinessEvent |
| Contract class | MGCLatticeTransferOrderReceivedBusinessEventContract |
| Category | Inventory management |
| Module | ModuleAxapta::Inventory |
| Label IDs | TransferOrderReceivedBusinessEventName / TransferOrderReceivedBusinessEventDescription |
| Trigger | InventTransferUpdReceive.run() -> status delta into InventTransferStatus::Received (partial-receipt safe) |
Trigger / Hook
- Extension class:
MGCLatticeInventTransferUpdReceive_Class_Extension,[ExtensionOf(classStr(InventTransferUpdReceive))] - CoC method signature:
void run()(no parameters) - Hooked on the receipt update process method rather than the
InventTransferTable.update()table write, so entity/import writes and set-based updates of the transfer order don't fire it. - Firing condition: the pre-update status is captured via
InventTransferTable::find(transferId).TransferStatusBEFOREnext run()(the transfer id comes from the publicthis.parmParmBuffer(), read as anInventTransferParmTable, since the protectedinventTransferTablemember has no accessor), then the committed record is re-read afterward. The event fires only on a genuine transition intoReceived:origStatus != InventTransferStatus::Received && transferTable.TransferStatus == InventTransferStatus::Received.run()is also invoked for partial receipts and for document-return/scrap receipts, so the delta guard is mandatory - only a fully-received order flips the status; partial receipts do not. - Enablement gate: guarded by
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeTransferOrderReceivedBusinessEvent))beforesend(). - The tts boundary lives in the parent
InventTransferUpd.run(), so firing afternextis post-commit. When the receipt update runs inside a larger transaction, the event is written to the business events commit log inside it and is delivered only if that transaction commits.
void run()
{
// The activation check is a cached lookup and comes first, so an environment that has not activated the
// event pays no database read. next run() is always called.
boolean eventEnabled = BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeTransferOrderReceivedBusinessEvent));
InventTransferId transferId;
InventTransferStatus origStatus;
if (eventEnabled)
{
// parmParmBuffer() is typed as the ParmBuffer map; assign to the concrete parm table to reach TransferId.
InventTransferParmTable parmTable = this.parmParmBuffer();
transferId = parmTable.TransferId;
origStatus = InventTransferTable::find(transferId).TransferStatus;
}
next run();
if (eventEnabled)
{
InventTransferTable transferTable = InventTransferTable::find(transferId);
if (origStatus != InventTransferStatus::Received && transferTable.TransferStatus == InventTransferStatus::Received)
{
MGCLatticeTransferOrderReceivedBusinessEvent::newFromInventTransferTable(transferTable).send();
}
}
}
Payload Contract
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
| legalEntity | Legal Entity | DataAreaId | _inventTransferTable.DataAreaId | Company / data area of the transfer order |
| transferOrderId | Transfer Order ID | InventTransferId | _inventTransferTable.TransferId | Transfer order number |
| fromWarehouse | From Warehouse | InventLocationId | _inventTransferTable.InventLocationIdFrom | Source (shipping) warehouse |
| toWarehouse | To Warehouse | InventLocationId | _inventTransferTable.InventLocationIdTo | Destination (receiving) warehouse |
| transferStatus | Transfer Status | int | enum2int(_inventTransferTable.TransferStatus) | Integer value of InventTransferStatus (0 = Created, 1 = Shipped, 2 = Received); 2 at fire time |
| transferStatusName | Transfer Status Name | str | enum2Symbol(enumNum(InventTransferStatus), enum2int(_inventTransferTable.TransferStatus)) | Symbolic name of the InventTransferStatus enum value (e.g. "Received") |
| crossReferences | Cross references | List of MGCLatticeCrossReferenceEventContract | MGCLatticeCrossReferenceEventHelper::listFor(_inventTransferTable) | Keys external systems hold for the transfer order: one { externalSystem, externalKey } object per external system, ordered by external system, historical keys included; [] when it has none. See Cross-reference keys. |
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": "MGCLatticeTransferOrderReceivedBusinessEvent",
"ControlNumber": 558102,
"EventId": "5F3B2A1C-7D8E-4F90-B1C2-3D4E5F6A7B8C",
"EventTime": "\/Date(1790286931000)\/",
"EventTimeIso8601": "2026-09-24T21:55:31.2329896Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{553A3A7D-83BB-EF5D-D226-E61F1892CE3F}",
"ParentContextRecordSubjects": [],
"eventSequence": 48602,
"correlationId": "Event:475c845c-b8ad-4a9a-87a3-3797c6e94ea9",
"schemaVersion": 1,
"legalEntity": "usmf",
"transferOrderId": "TRO00042",
"fromWarehouseId": "13",
"toWarehouseId": "24",
"transferStatus": 2,
"transferStatusName": "Received",
"crossReferences": [
{
"externalSystem": "WMS",
"externalKey": "TO-557201"
}
]
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Transfer order received") or by filtering the Category column to Inventory 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).
Related Events
- Transfer Order Shipped - sibling event raised from
MGCLatticeInventTransferUpdShip_Class_Extension.run()when the status transitions toInventTransferStatus::Shipped. - Transfer order picking list created - raised earlier in the cycle, when a picking list is generated for the transfer order.
- Item Back In Stock - can follow a receipt that makes an item available again at the receiving warehouse.