Skip to main content

Business event reference

The Lattice model publishes 81 business events across 16 catalog categories. They fill gaps in the Dynamics 365 Finance and Operations event catalog. Each event has its own page: the business moment that raises it, the payload it emits, an example payload, and how to activate it.

See the business events operator guide for discovering, activating and monitoring events.

What every payload contains​

  • The platform envelope. Every business event payload carries the D365 fields BusinessEventId, BusinessEventLegalEntity, ContextRecordSubject, ControlNumber, EventId, EventTime, EventTimeIso8601, InitiatingUserAADObjectId, MajorVersion, MinorVersion and ParentContextRecordSubjects.
  • The Lattice envelope. Every Lattice event adds three fields, inherited from MGCLatticeBusinessEventContractBase:
    • eventSequence increases across the whole catalog and all companies. It is allocated when the event is raised inside the business transaction, not when that transaction commits, so two long transactions can commit in the opposite order of their values. Use it to order the events of one business record (for example one sales order); do not re-sequence the whole stream by it. Gaps are permanent and normal: a value is not reused when the transaction that raised the event rolls back, when a publish fails, or when a payload is built only to describe the schema (catalog schema download, sample payloads). Only events that opt in to Lattice business event logging and support replay are re-published later under their original value; in this release that is Retail assortment published. For every other event a gap can also be an event that was never delivered. Restoring the database to an earlier point in time rewinds the counter.
    • correlationId groups the emissions that belong to one logical run and is always Scope:Key: BatchTask:<id> for events raised by one batch task, BOMCalc:<id>, InventClose:<company>:<voucher> or MRPRun:<plan> for the run-scoped events, and Event:<guid> (a lower-case GUID without braces, unique to the emission) for an event that is not part of a run.
    • schemaVersion is the version of the payload shape, 1 for every event in this release. Members are only added within a version; a payload whose shape changes gets a higher schemaVersion. Consumers should ignore members they do not know. The platform fields MajorVersion and MinorVersion are always 0.
  • How values are written. Every company identifier in the Lattice part of the payload (legalEntity, vendorLegalEntity, ...) is lower case (usmf); the platform field BusinessEventLegalEntity keeps the case of the session and can be USMF. Enums are written as an integer member plus a ...Name member holding the enum symbol. Flags are JSON true/false. Lists of values are JSON arrays. Dates and date-times are written as \/Date(milliseconds)\/ (milliseconds since 1970-01-01 UTC; a date is midnight UTC of that day; an empty date is \/Date(-2208988800000)\/). Amounts with a currency member beside them are in that currency; an amount without one ends in MST and is in the accounting currency of the legal entity. Members ending in RecId or named inventDimId are internal ids that differ between environments. Do not rely on the order of members in the JSON.
  • Shared payloads. The six trade agreement price events share one payload (with changeType/changeTypeName naming the change), and the picking list canceled and transfer order picking list created events share another. Members that only some events of a family fill are empty for the others; each event page lists them.

Before you activate​

Most events need nothing but activation in the business events catalog. These need more, or behave in ways worth knowing first:

Each event's page states its own conditions and limitations in full.

Accounts payable​

EventTriggerDescription
Vendor ASN line changedWHSASNItem.insert()/update() -> purchase ASN line (Module == Purch) created or its quantity changedFires per purchase ASN line with PO, shipment, load, item, quantity, unit and batch expiry, and again with previousQuantity when its quantity changes; outbound ASN lines do not raise it.
Vendor check issuedBankChequeTable.update() -> status Created/NotPrinted/Testprint -> Payment, RecipientType == VendFires when a vendor check is issued (normally at check generation); a check returning to Payment from Cancel pending does not raise it again.
Vendor createdVendTable.insert()Fires for every new vendor record, with account, name, group and currency.
Vendor hold status changedVendTable Updated data event -> Blocked changed; VendTable.insert() -> new vendor on holdFires when a vendor's hold is applied, changed or released, or a vendor is created on hold, carrying the new and previous status.
Vendor payment postedLedgerJournalCheckPost.runInternalPostJournalTransactionEnded -> posted LedgerJournalType::Payment journalFires after a vendor payment journal commits, once per vendor posting (account or offset), with the amount signed from the vendor's side, its debit/credit side, journal, voucher, vendor, payment method, reference and date.
Vendor updatedVendTable.update(boolean, boolean)Fires after every vendor record update (no change filter), carrying account, name, group and currency.

Accounts receivable​

EventTriggerDescription
Collection case changedCustCollectionsCaseDetail::createCase() / closeCase()Fires when a collections case is opened or closed from the Collections page, in the case's own legal entity, carrying customer, case ID, status, action and current balance.
Collection letter postedCustCollectionLetterPost.writeCustCollectionLetterJour() for a posted letterFires when Post collection letters posts a letter, carrying customer, letter number and level, letter and due dates, fee, posting date and fee voucher.
Customer createdCustTable.insert()Fires when a customer master record is inserted; the customer resync job also emits it for every existing customer.
Customer credit limit exceededCustCreditLimit.check() returns falseFires every time the standard credit limit check finds the customer's balance plus the document being checked over the credit limit in effect (agreement, credit management or customer limit), with that limit and all amounts in accounting currency.
Customer hold status changedCustTable.update() when Blocked changesFires when a customer's hold status (Blocked) changes value, carrying the new and the previous status and the credit limit in accounting currency.
Customer updatedCustTable.update()Fires on every save of an existing customer master record, whether or not a field changed.
Dunning level changedCustCollectionLetterJour.updateCollectionLetterCodeCustTrans() when an open transaction's level changesFires once per open customer transaction whose collection letter level a letter changes (normally when it is posted), with the previous and new level; the fee line is not reported.
E-invoice submission status changedBusinessDocumentSubmission Inserted, or Updated when State changesFires when an Electronic invoicing submission is logged (first status) and each time its status changes, carrying legal entity, source document, status and UTC submission time.
Free text invoice postedCustInvoiceJour.insert() with an empty SalesId, not pro formaFires when a free text invoice or free text credit note is posted, carrying invoice number, invoice account, date, the amount in transaction and in accounting currency, and the currency; pro forma printouts do not raise it.

Asset management​

EventTriggerDescription
Maintenance work order completedEntAssetLifecycleStateUpdate_WorkOrderTable.updateStateRecord() -> new state has Set actual endFires when an existing work order enters a state that stamps its actual end (Completed in USMF); takes precedence over Started and Scheduled.
Maintenance work order createdEntAssetWorkOrderTable Inserted data event -> raised when the creating transaction commitsFires once per new work order as its creating transaction commits, with its lines' assets, functional location and first lifecycle state.
Maintenance work order scheduledEntAssetLifecycleStateUpdate_WorkOrderTable.updateStateRecord() -> new state is the lifecycle model's scheduled stateFires when a work order moves to its lifecycle model's scheduled state, as standard scheduling does (Scheduled in USMF).
Maintenance work order startedEntAssetLifecycleStateUpdate_WorkOrderTable.updateStateRecord() -> new state has Set actual start (and not Set actual end)Fires when an existing work order enters a state that stamps its actual start (InProgress in USMF), carrying its assets and actual start.

Bank management​

EventTriggerDescription
Advanced bank reconciliation completedBankReconciliationHeader::reconcile() / reconcileInBatch() when IsReconciled goes from No to YesFires when an Advanced bank reconciliation worksheet is marked as reconciled, with its statements and the counts and bank-currency totals of the matched statement lines and bank transactions; the classic bank account reconciliation does not raise it.
Bank reconciliation completedBankAccountReconcile.updateBankAccountStatementToReconciled() when ReconcileDate is first setFires when a bank statement is reconciled with the classic Reconcile account action, with the count and accounting-currency total of the reconciled transactions; Advanced bank reconciliation does not raise it.

Fixed assets​

EventTriggerDescription
Fixed asset acquisition postedAssetTrans.insert() -> TransType == AcquisitionFires for every acquisition row written, one per book, with isReversal/isReclassification flagging rows from a reversal or reclassification.
Fixed asset disposal postedAssetTrans.insert() -> TransType == DisposalSale/DisposalScrapFires for every sale or scrap disposal row written, one per book, with isReversal/isReclassification flagging rows from a reversal or reclassification.

General ledger​

EventTriggerDescription
General journal postedLedgerJournalCheckPost.runInternalPostJournalTransactionEnded delegateA general (Daily) journal is posted.

Inventory management​

EventTriggerDescription
External item changedCustVendExternalItem Inserted/Updated data events, plus MGCLatticeProcessAllExternalItems resyncFires on every create or update of a customer or vendor external item cross-reference, with the external number, text, account or group, and module type.
Inventory closing completedInventCostLedgerPostingTask.updateLedgerPosting()Fires when an inventory close or recalculation has finished (settlement, adjustments and ledger posting done), with the closing date, voucher and which of the two ran.
Inventory on-hand changedInventUpdateOnhand.onOnHandUpdated, sent after commitFires after a transaction commits, once per item, site and warehouse whose net physical on-hand it changed, with the change and that site and warehouse's on-hand quantities (high volume).
Item back in stockInventUpdateOnhand.onOnHandUpdated, sent after commitFires after a transaction commits when available physical for an item in a site and warehouse moved from 0 or less to above 0, at most once per item, site and warehouse per transaction.
Picking list canceledWMSPickingRoute.cancel() / WMSOrderTransType_Output_OrderPick.cancel()Fires when canceling a picking list cancels at least one line, or when a single picking line is canceled, listing only the lines that were canceled.
Quality order failedInventQualityOrderValidate.run()Fires when quality order validation moves the order to Fail, with quantities, disposition code and validator.
Quality order passedInventQualityOrderValidate.run()Fires when quality order validation moves the order to Pass.
Released product createdEcoResProductReleaseManager.createInventTable() / EcoResProductReleaseManagerItem.release(), plus MGCLatticeProcessAllItems resyncFires when a product is released to a legal entity, in that legal entity, with item, product RecId, search name, item type and lifecycle state.
Transfer order picking list createdInventTransferUpdPick.run()Fires when Generate picking list creates a picking list for a transfer order, listing the lines to pick and whether the list is activated or already complete.
Transfer order receivedInventTransferUpdReceive.run()Fires when a transfer order becomes fully received.
Transfer order shippedInventTransferUpdShip.run()Fires when a transfer order becomes fully shipped.

Master planning​

EventTriggerDescription
MRP run completedReqCalc.run()Fires once when a built-in master planning run finishes calculating a plan (main thread of a ReqCalcScheduleItemTable run only; helper threads, forecast scheduling, firming, explosions and canceled runs don't raise it); never for Planning Optimization runs.

Product information management​

EventTriggerDescription
Retail assortment publishedRetailAssortmentLookupTask.run()Fires when Process assortments publishes an assortment for the first time in a legal entity or its effective item list there changes, with the items and price at publish.

Production control​

EventTriggerDescription
BOM calculation completedBomCalcItem.insertBOMCalcTable()Fires when an item price (BOM) calculation saves its top-level result for an item, with the calculated cost and calculation date.
BOM version approvedBomVersionApprove.run()Fires when the BOM version approval operation (Approve action, engineering change case, or OData approval action) approves a version that was not approved before.
Production order endedProdUpdHistoricalCost.run()Fires when the End update moves a production order to Ended (Completed), with the order's total good and error quantities reported as finished and their unit.
Production order estimatedProdUpdCostEstimation.run()Fires when a cost estimation moves a production order from Created to Estimated.
Production order reported as finishedProdUpdReportFinished.run() / ProdJournalCheckPostProd.run()Fires once when a report-as-finished update or a report-as-finished journal posted on its own moves a production order to Reported as finished, with the order's total good and error quantities and their unit.
Production order scheduledProdUpdScheduling.run() / ReqTransPoMarkFirm.insertMovement()Fires when operations or job scheduling first moves a production order to Scheduled, or when firming a planned order creates it as Scheduled.
Production order startedProdUpdStartUp.run()Fires when a start update first moves a production order to Started.
Production pick list postedProdJournalCheckPostBOM.run()Fires once per posted production picking list journal, listing each posted component line with its own quantity and inventory unit.
Production route card postedProdJournalCheckPostRoute.run()Fires once per posted production route card journal, listing each posted line with its operation, resource, hours and good and error quantities.

Projects​

EventTriggerDescription
Project invoice postedProjInvoiceJour.insert()A project invoice journal header is created during posting, carrying the invoice total and currency; pro forma invoices are excluded.
Project task assignedProjTask::reserveResourceActivity() (work breakdown structure), plus ProjActivityAssignment Inserted/Updated data eventsFires once per resource holding hours on a project task when a published plan's task resources are saved or a draft plan is published (a resource that stays on the task is reported again), carrying project, task, resource, worker and assigned hours; ProjActivityAssignment rows written by customizations and imports also raise it.

Purchase orders​

EventTriggerDescription
Purchase agreement confirmedAgreementConfirm_Purch.createHeaderHistory()Fires on every purchase agreement confirmation, when the agreement header history snapshot is created, with the agreement's buying legal entity.
Purchase requisition approvedPurchReqWFStatusTransitionHelper::setPurchReqTable2Approved()Fires when a purchase requisition's approval workflow completes and the requisition is set to Approved, with the buying legal entities of its lines.
Purchase return order createdPurchTableType_ReturnItem.inserted()Fires when a purchase order header of type Returned order is inserted.

Retail​

EventTriggerDescription
Retail info-code response capturedRetailTransactionInfocodeTrans.insert()Fires when an info code (reason code) response row is inserted in headquarters, with code, subcode, text, amount, transaction and parent line, store, terminal, staff and UTC capture time; store uploads might not raise it.

Sales orders​

EventTriggerDescription
Return credit note postedSalesInvoiceJournalPost.postJournalPost() for a posted return order invoice (SalesType ReturnItem)Fires when a return order is invoiced (its credit note is posted), carrying credit note number, return order, RMA number, customer, amount and currency.
Return order receivedReturn registration (SalesLine.returnLineRegisterUpdate() / SalesReturnNonStockedRegistrationHelper.updateOnRegistration()) when ReturnStatus moves to RegisteredFires when a return order line is registered (goods arrived), carrying RMA number, item, quantity, disposition code and receiving warehouse.
Sales agreement confirmedAgreementConfirm_Sales.createHeaderHistory()A sales agreement is confirmed and its history snapshot written, in the agreement's selling legal entity; every re-confirmation fires again.
Sales order canceledSalesUpdateRemain.cancelOpenOrderLinesDeliveryRemainder() / cancelMultipleOrdersDeliveryRemainder() / MCRSalesOrderCancellation::cancelOrder() / cancelOrderFTC()A sales order's remaining lines are canceled and its status becomes Canceled; from the Cancel action only once the cancellation is final. Return orders raise it too, with the order type and RMA number.
Sales order confirmedSalesConfirmJournalPost.postJournalPost()A sales order confirmation journal is posted, carrying the confirmation total; pro forma confirmations are excluded.
Sales order invoice postedSalesInvoiceJournalPost.postJournalPost() for a posted, non-pro-forma invoice with a SalesIdFires once per posted sales order invoice or credit note, after the totals are written, carrying invoice account, order, invoice number, date, amount and currency; pro forma invoices do not raise it.
Sales order line changedSalesLine Updated when quantity, price or requested dates changeFires when a sales order line's quantity, price, requested receipt date or requested ship date changes, with before and after values.
Sales packing slip postedSalesPackingSlipJournalPost.postJournalPost()A sales packing slip journal is posted; pro forma packing slips, cancellations and return order receipts are excluded.
Sales price agreement createdPriceDiscAdmCheckPost.createOrUpdatePriceDiscTableRecords()A posted journal line inserted a sales price for an agreement (incl. quantity break and dimensions) with no sales price in effect on its From date.
Sales price agreement deletedPriceDiscTable.delete() / PriceDiscAdmTable::deleteMarked()A sales price is deleted by a user, by code or by a posted journal line marked for deletion.
Sales price agreement effectiveMGCLatticeTradeAgreementPriceEffectivityBatch.run()The scheduled batch reports, once and in date order, each sales price whose From date was reached since its last position.
Sales price agreement expiredMGCLatticeTradeAgreementPriceEffectivityBatch.run()The scheduled batch reports each sales price whose To date passed when no other price of the same agreement is in effect the next day.
Sales price agreement modifiedPriceDiscAdmCheckPost.createOrUpdatePriceDiscTableRecords()A posted journal line changed at least one value of an existing sales price, carrying the old amount and the changed fields.
Sales price agreement supersededPriceDiscAdmCheckPost.createOrUpdatePriceDiscTableRecords()A posted journal line added a sales price for an agreement that had a price in effect on its From date, carrying that price's amount and record ID.
Sales price trade agreement changedPriceDiscTable Inserted/Updated with relation PriceSalesRecord-level signal for any insert or update of a sales-price agreement row, carrying its unit, inventory dimensions and record ID; it fires for journal postings only when the Accounts receivable "Skip price agreement insert/update alerts" parameters are No.
Sales quotation confirmedSalesQuotationEditLinesForm_Sales_Confir.createJournal()A sales quotation is confirmed, carrying the quotation number, the confirmation number and the sales order it created.
Sales return order createdSalesTableType_ReturnItem.inserted()A sales return order (SalesTable of type ReturnItem) is created.

System administration​

EventTriggerDescription
Aggregate measurement refresh completedBIMeasurementProcessingStatisticsFull.update()Fires when a full-reset entity store measurement refresh finishes (succeeded or failed), with measurement, status, start/completion times and duration.
Batch job status changedBatchJob.update()Fires when a batch job has its status changed through the job record (for example Change status on the Batch jobs page), in the job's company, unless an enabled batch job event filter matches the job; the batch server's own start/finish transitions do not raise it.
Business event publish failedBusinessEventsPublisher.publish()Fires when publishing an opted-in Lattice event fails outside a database transaction and an Error row is written to the business event log; in this release only Retail assortment published opts in.
Custom ad-hoc business eventMGCLatticeCustomAdHocEventApi::raiseEvent()Raised only by customer X++ code calling the ad-hoc X++ API (not an OData action), carrying a caller-chosen event name, a record reference and a free-form JSON payload.
DMF execution completedDMFDefinitionGroupExecution.update() / DMFEntityDbExporter::generateEntityDBDataV2()Fires per entity when a batch import, copy to target, file export or bring-your-own-database export sets the target status to Finished, Error or Canceled, with the company, a derived outcome and record/error counts; an import run without batch mostly isn't reported.
Integration item parkedMGCLatticeIntegrationDlqAlert.onParked()Fires when a failed Lattice async operation or file ingestion item is parked in the dead-letter queue, immediately (non-retryable) or when the scheduled retry sweep uses up its attempts; without that sweep, retryable failures never raise it.
Recurring data job health changedMGCLatticeRecurringJobHealthAlerts background process (every 15 minutes) and health refreshes on the recurring integration pagesFires once when the health of a recurring data job with alerts on changes (for example Healthy to Failing, or Broken back to Healthy), in the company of the job's processing batch job, with the previous and new health, the reasons and the signal values; a job's first evaluation and unchanged health raise nothing.
Workflow lifecycle actionWorkflowTrackingCommentTable.insert()Fires for each reportable workflow action (assigned, submitted, approved, rejected, delegated, escalated, completed, failed and so on) with workflow, document, step, acting user, new assignee and comment.
Workflow stalled or failedMGCLatticeWorkflowStalledAlertBatch.run()Raised by a scheduled scan once for each faulted or unrecoverable workflow instance and each work item pending past the threshold (default 24 h), and again only when the condition changes or comes back; each condition is raised in its document's company.

Warehouse management​

EventTriggerDescription
Warehouse load shippedWHSShipConfirm.shipConfirm() / WHSShipConfirmationActionTransportLoad.shipConfirm()Fires when load ship confirmation or transport load ship confirmation (including the mobile app's transport loading flow) moves a load to Shipped, once per load.
Warehouse picking completedWHSWorkTable.update()Fires when sales, transfer, production or kanban picking work closes, with the work order type and one entry per completed pick line (item, quantity, unit, location, operator).
Warehouse work completedWHSWorkTable.update() / WHSWorkTable.insert()Fires when warehouse work closes or is created already closed, with the work type, order, load and shipment references, and close time.