Skip to main content

Sales order line changed

Fires when a saved sales order line's quantity, unit price, requested receipt date or requested ship date changes. The payload carries the before and after values of all four fields, so order-management, warehouse and customer-notification systems can act on the delta - re-plan a shipment, re-quote, or tell the customer - without diffing the order themselves. It fills the modification gap between the order-level events such as Sales order confirmed and Sales order canceled.

Event classMGCLatticeSalesOrderLineChangedBusinessEvent
Contract classMGCLatticeSalesOrderLineChangedBusinessEventContract
CategorySales orders
ModuleModuleAxapta::SalesOrder
Label IDsSalesOrderLineChangedBusinessEventName / SalesOrderLineChangedBusinessEventDescription
TriggerSalesLine updated (DataEventType::Updated) -> SalesQty, SalesPrice, ReceiptDateRequested or ShippingDateRequested changed

Trigger / Hook​

  • Handler class: MGCLatticeSalesOrderLineChangedEventHandlers, method SalesLine_onUpdated, decorated with [DataEventHandler(tableStr(SalesLine), DataEventType::Updated)].
  • Method signature: public static void SalesLine_onUpdated(Common _sender, DataEventArgs _e).
  • Firing condition: the handler compares the updated line with orig() and sends the event when at least one of SalesQty, SalesPrice, ReceiptDateRequested or ShippingDateRequested differs. One event per updated line; changes to any other field (discounts, warehouse, confirmed dates, and so on) do not raise it. The previous values come from orig(), which still holds the pre-update record while Updated handlers run.
  • Scope: every SalesLine update qualifies, whoever makes it - users, data entities, or D365's own processing. There is no order-type filter, so return order lines (which carry negative quantities) and other sales order types raise it too. Creating or deleting a line does not.
  • Writes that bypass the table's update pipeline (doUpdate(), or set-based updates run with skipEvents(true)) do not raise it.
  • Timing: send() writes to the business events commit log inside the updating transaction and delivery happens asynchronously after commit, so an update that is rolled back never delivers.
  • Enablement gate: BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeSalesOrderLineChangedBusinessEvent)), evaluated together with the change check.
[DataEventHandler(tableStr(SalesLine), DataEventType::Updated)]
public static void SalesLine_onUpdated(Common _sender, DataEventArgs _e)
{
SalesLine salesLine = _sender as SalesLine;
SalesLine origLine = salesLine.orig();
boolean changed =
salesLine.SalesQty != origLine.SalesQty
|| salesLine.SalesPrice != origLine.SalesPrice
|| salesLine.ReceiptDateRequested != origLine.ReceiptDateRequested
|| salesLine.ShippingDateRequested != origLine.ShippingDateRequested;

if (changed && BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeSalesOrderLineChangedBusinessEvent)))
{
MGCLatticeSalesOrderLineChangedBusinessEvent::newFromSalesLine(
salesLine,
origLine.SalesQty,
origLine.SalesPrice,
origLine.ReceiptDateRequested,
origLine.ShippingDateRequested).send();
}
}

Payload Contract​

One row per [DataMember], in declaration order. Current values come from the updated SalesLine; previous values are the orig() values passed in by the handler. All four before/after pairs are always populated - a pair that did not change carries the same value twice.

JSON fieldDisplay labelType / EDTSourceNotes
legalEntityLegal EntityDataAreaIdSalesLine.DataAreaIdCompany of the order, as stored (lowercase, for example usmf).
salesOrderIdSales Order IDSalesIdSalesLine.SalesIdSales order number.
itemIdItem NumberItemIdSalesLine.ItemIdItem on the line.
inventTransIdInventory Transaction IdInventTransIdSalesLine.InventTransIdLot ID that uniquely identifies the line; use it as the line key.
lineNumberLine NumberLineNumSalesLine.LineNumLine number (a real number in D365, for example 1.0).
previousQuantityPrevious QuantitySalesQtySalesLine.orig().SalesQtyQuantity before the change, in the sales unit.
currentQuantityCurrent QuantitySalesQtySalesLine.SalesQtyQuantity after the change.
previousPricePrevious PriceSalesPriceSalesLine.orig().SalesPriceUnit price before the change, in currencyCode.
currentPriceCurrent PriceSalesPriceSalesLine.SalesPriceUnit price after the change.
previousReceiptDatePrevious Receipt DateTransDateSalesLine.orig().ReceiptDateRequestedRequested receipt date before the change (date, \/Date(milliseconds)\/ form).
currentReceiptDateCurrent Receipt DateTransDateSalesLine.ReceiptDateRequestedRequested receipt date after the change.
previousShippingDatePrevious Shipping DateTransDateSalesLine.orig().ShippingDateRequestedRequested ship date before the change.
currentShippingDateCurrent Shipping DateTransDateSalesLine.ShippingDateRequestedRequested ship date after the change.
currencyCodeCurrency CodeCurrencyCodeSalesLine.CurrencyCodeCurrency of the prices.
crossReferencesCross referencesList of MGCLatticeCrossReferenceEventContractMGCLatticeCrossReferenceEventHelper::listFor(SalesLine)Keys external systems hold for the sales order line: 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 sent inside the business transaction; it orders the events of one record, but two transactions can commit in the opposite order of their values, and gaps are normal and permanent - see the events overview), correlationId (String - always Scope:Key: Event: followed by a GUID unique to this emission, unless the event joins a 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": "MGCLatticeSalesOrderLineChangedBusinessEvent",
"ControlNumber": 5637148768,
"EventId": "7E0D3B95-4A26-4C81-9F3E-1B5C8D2A6F07",
"EventTime": "\/Date(1790331738000)\/",
"EventTimeIso8601": "2026-09-25T10:22:18.4541612Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{673F0A8D-8247-957C-91F0-D9F769A5BE50}",
"ParentContextRecordSubjects": [],
"eventSequence": 48405,
"correlationId": "Event:b321e91a-3341-49f1-b988-d04cc11f79cc",
"schemaVersion": 1,
"legalEntity": "usmf",
"salesOrderId": "000745",
"itemId": "D0001",
"inventTransId": "USMF-001234567",
"lineNumber": 1.0,
"previousQuantity": 10.00,
"currentQuantity": 12.00,
"previousPrice": 185.00,
"currentPrice": 185.00,
"previousReceiptDate": "\/Date(1791158400000)\/",
"currentReceiptDate": "\/Date(1791763200000)\/",
"previousShippingDate": "\/Date(1790812800000)\/",
"currentShippingDate": "\/Date(1791504000000)\/",
"currencyCode": "USD",
"crossReferences": [
{
"externalSystem": "SHOP",
"externalKey": "WEB-1004871-2"
}
]
}

Activation​

In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Sales order line changed") or by filtering the Category column to Sales orders. 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).