Skip to main content

Aggregate measurement refresh completed

Fires when a full-reset refresh of an entity store aggregate measurement finishes, successfully or not. The platform's measurement processor records each completed full refresh on the measurement's BIMeasurementProcessingStatisticsFull row; this event publishes that outcome - the measurement name, status, start and completion times, and duration - so a BI or data pipeline can pick up fresh entity store data, or alert on a failed refresh, instead of polling the processing statistics.

Event classMGCLatticeAggregateMeasurementRefreshedBusinessEvent
Contract classMGCLatticeAggregateMeasurementRefreshedBusinessEventContract
CategorySystem administration
ModuleModuleAxapta::SystemAdministration
Label IDsAggregateMeasurementRefreshedBusinessEventName / AggregateMeasurementRefreshedBusinessEventDescription
TriggerBIMeasurementProcessingStatisticsFull.update() -> terminal LastExecutionStatus with a new LastProcessed start time

Trigger / Hook​

  • Extension class: MGCLatticeBIMeasurementProcessingStatisticsFull_Table_Extension, decorated with [ExtensionOf(tableStr(BIMeasurementProcessingStatisticsFull))].
  • CoC method signature: public void update().
  • Why a table hook: the platform processor (BIMeasurementProcessor) records a finished full refresh by calling BIMeasurementProcessingStatisticsFull::updateStatistics(), which writes the start time (LastProcessed), duration (LastDuration) and terminal status onto the measurement's statistics row with a record-based update(). There's no separate process method to hook.
  • Firing condition: after next update(), the event sends when the new LastExecutionStatus is Succeeded or Failed and LastProcessed differs from its orig() value. At the start of processing the platform stamps the row InProgress without touching LastProcessed, so that write is ignored; the completion write carries the new start time, so the event fires once per measurement per full refresh - including a repeated Succeeded -> Succeeded run.
  • Scope: full-reset refreshes only. Incremental updates record their results in BIMeasurementProcessingStatisticsIncremental, which has no execution status and isn't hooked, so they don't raise this event.
  • Timing: updateStatistics() performs the update inside its own ttsbegin/ttscommit, so send() writes to the business events commit log inside that transaction and the event is delivered only after it commits.
  • The statistics table is shared across companies (SaveDataPerCompany = No), so the payload carries no legal entity; an entity store refresh isn't company specific.
  • Company: the statistics row belongs to no company, so activation is checked in the company of the session that writes it (for a scheduled entity store refresh, the batch job's company), and BusinessEventLegalEntity is that company. Activate the event for all legal entities, or in the company that runs the refresh jobs.
  • Enablement gate: BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAggregateMeasurementRefreshedBusinessEvent)), in the writing session's company.
public void update()
{
utcdatetime origProcessed = this.orig().LastProcessed;

next update();

if (MGCLatticeAggregateMeasurementRefreshedBusinessEvent::isTerminalStatus(this.LastExecutionStatus)
&& this.LastProcessed != origProcessed)
{
if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAggregateMeasurementRefreshedBusinessEvent)))
{
MGCLatticeAggregateMeasurementRefreshedBusinessEvent::newFromStatistics(this).send();
}
}
}

Payload Contract​

One row per [DataMember], in declaration order. Sources are the completed BIMeasurementProcessingStatisticsFull row, mapped in initialize().

JSON fieldDisplay labelType / EDTSourceNotes
measurementNameMeasurement NameBIAggregateMeasurementNameBIMeasurement.Name, looked up by BIMeasurementProcessingStatisticsFull.BIMeasurementThe aggregate measurement (entity store) that was refreshed
refreshStatusRefresh StatusintBIMeasurementProcessingStatisticsFull.LastExecutionStatus (as integer)BIMeasurementExecutionStatus: 2 = Succeeded, 3 = Failed
refreshStatusNameRefresh Status NamestrLastExecutionStatus (enum symbol)"Succeeded" or "Failed"
isSuccessfulIs SuccessfulbooleanLastExecutionStatus == Succeededtrue / false
startedDateTimeStarted Date TimeutcdatetimeBIMeasurementProcessingStatisticsFull.LastProcessedUTC time the processing started; serialized in the \/Date(ms)\/ form
completedDateTimeCompleted Date TimeutcdatetimeDerived: LastProcessed plus durationSecondsThe row stores no end time, so this is calculated; \/Date(ms)\/ form
durationSecondsDuration SecondsintDerived: real2int(LastDuration * 60)Whole seconds; the platform stores a full refresh's elapsed time in minutes (LastDuration)

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; it orders the events of one record, gaps are normal and permanent, see the README), correlationId (String - always Scope:Key; groups emissions that belong to one logical run and defaults to Event: plus a GUID unique to this emission) 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.

This event doesn't call correlateTo, so correlationId is unique to each emission.

Example Payload​

{
"BusinessEventId": "MGCLatticeAggregateMeasurementRefreshedBusinessEvent",
"ControlNumber": 5637150421,
"EventId": "5C0E7B2A-91D4-4F6E-A3B8-2D6F0C9E1A74",
"EventTime": "\/Date(1790215955000)\/",
"EventTimeIso8601": "2026-09-24T02:12:35.0084868Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{2CAEE5B5-EABB-CA80-0364-1B68C0AAC081}",
"ParentContextRecordSubjects": [],
"eventSequence": 47102,
"correlationId": "Event:d41b6f20-7c3a-4e95-8b1d-0f2a6c9e3b57",
"schemaVersion": 1,
"measurementName": "CustCollectionsBIMeasurements",
"refreshStatus": 2,
"refreshStatusName": "Succeeded",
"isSuccessful": true,
"startedDateTime": "\/Date(1790215205000)\/",
"completedDateTime": "\/Date(1790215955000)\/",
"durationSeconds": 750
}

Activation​

In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Aggregate measurement refresh completed") or by filtering the Category column to System administration. 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), for all legal entities or in the company that runs the refresh jobs. No Lattice setup is needed; the event follows whatever full refreshes you run or schedule for your entity store measurements (System administration > Setup > Entity store).