Skip to main content

BOM version approved

Fires when the standard approval operation (BomVersionApprove) approves a bill of materials (BOM) version that wasn't approved before. This marks the point at which the version is sanctioned for production planning and costing. The payload carries the item, BOM, approver, validity dates and quantity threshold, so product lifecycle, MES and costing systems can react to an engineering release.

Event classMGCLatticeBOMVersionApprovedBusinessEvent
Contract classMGCLatticeBOMVersionApprovedBusinessEventContract
CategoryProduction control
ModuleModuleAxapta::ProductionControl
Label IDsBOMVersionApprovedBusinessEventName / BOMVersionApprovedBusinessEventDescription
TriggerBomVersionApprove.run() -> an approval (not a removal of approval) changes the version's Approved flag from No to Yes

Trigger / Hook​

  • Extension class: MGCLatticeBomVersionApprove_Class_Extension, decorated with [ExtensionOf(classStr(BomVersionApprove))].
  • CoC method signature: void run() (no parameters). This is the approval process method, not the BOMVersion.update() table write.
  • Firing condition: before next run(), the version's Approved flag is read with BOMVersion::findRecId(this.parmRecId()). After next run(), if the operation was not a removal of approval (this.parmRemove() is No), the version is re-read, and the event is sent when that record exists and its Approved flag changed from NoYes::No to NoYes::Yes (MGCLatticeBOMVersionApprovedBusinessEvent::isApprovalTransition()).
  • Re-approval: the standard operation doesn't stop you from approving a version that is already approved; it saves the approval again with the approver from that run. That doesn't raise the event again. If the approval is removed and the version is approved again later, that new approval raises the event.
  • Coverage: every caller of BomVersionApprove.run() raises the event when it approves a version that wasn't approved. That includes the Approve action on a BOM version, the approval step when an engineering change case is applied (EngChgCaseBOMRouteApplyAction), and the approval action on the BOM version OData entities (BOMBillOfMaterialsVersionODataEntity, BOMBillOfMaterialsVersionODataV2Entity). A version that becomes approved without this operation (for example, when code or an import sets BOMVersion.Approved directly) doesn't raise it. When the same run also approves the parent BOM (Approve BOM), no separate event is sent for the BOM.
  • Transaction: run() saves the approval inside its own ttsbegin/ttscommit, and the event is sent after run() returns. BusinessEventsBase.send() only writes to the commit log inside the current transaction and delivery is asynchronous post-commit, so if the approval runs inside a larger transaction that rolls back, the event is never delivered.
  • Enablement gate: guarded by BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeBOMVersionApprovedBusinessEvent)), so the event only sends when activated in the business events catalog.
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(MGCLatticeBOMVersionApprovedBusinessEvent));
RecId versionRecId = this.parmRecId();
NoYes approvedBefore;

if (eventEnabled)
{
approvedBefore = BOMVersion::findRecId(versionRecId).Approved;
}

next run();

if (eventEnabled && !this.parmRemove())
{
BOMVersion bomVersionLocal = BOMVersion::findRecId(versionRecId);

if (bomVersionLocal.RecId
&& MGCLatticeBOMVersionApprovedBusinessEvent::isApprovalTransition(approvedBefore, bomVersionLocal.Approved))
{
MGCLatticeBOMVersionApprovedBusinessEvent::newFromBOMVersion(bomVersionLocal).send();
}
}
}

Payload Contract​

One row per [DataMember], in declaration order. All sources are fields on the re-read BOMVersion record, mapped in initialize().

JSON fieldDisplay labelType / EDTSourceNotes
legalEntityLegal EntityDataAreaIdBOMVersion.DataAreaIdCompany the BOM version belongs to.
itemIdItem IDItemIdBOMVersion.ItemIdItem the BOM version produces.
bomIdBOM IDBOMIdBOMVersion.BOMIdThe BOM.
bomNameBOM NameNameBOMVersion.NameName of the BOM version.
approverPersonnelNumberApprover Personnel NumberHcmPersonnelNumberIdHcmWorker::find(BOMVersion.Approver).PersonnelNumberPersonnel number of the approving worker; empty when Approver is 0.
approverNameApprover NameNameHcmWorker::find(BOMVersion.Approver).name()Name of the approving worker; empty when Approver is 0.
isActiveIs ActivebooleanBOMVersion.Active == NoYes::YesApproving doesn't activate a version, so this is false unless the version was already active.
fromDateFrom DateTransDateBOMVersion.FromDateStart of the version's validity.
toDateTo DateTransDateBOMVersion.ToDateEnd of the version's validity.
fromQuantityFrom QuantityProductFromQuantityBOMVersion.FromQtyQuantity from which this version applies.
crossReferencesCross referencesList of MGCLatticeCrossReferenceEventContractMGCLatticeCrossReferenceEventHelper::listFor(BOMVersion)Keys external systems hold for the BOM version: 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": "MGCLatticeBOMVersionApprovedBusinessEvent",
"ControlNumber": 5637151793,
"EventId": "B099D667-09AE-4B31-8C7F-5FE3F2DAC5BC",
"EventTime": "\/Date(1790169044000)\/",
"EventTimeIso8601": "2026-09-23T13:10:44.8066739Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{EE6EAF96-160E-F345-DC88-6AFED5E73676}",
"ParentContextRecordSubjects": [],
"eventSequence": 48175,
"correlationId": "Event:35dc55bd-8efa-4b0e-8f02-6785ed703b64",
"schemaVersion": 1,
"legalEntity": "usmf",
"itemId": "D0001",
"bomId": "D0001BOM",
"bomName": "Mid-Range Speaker",
"approverPersonnelNumber": "000234",
"approverName": "Julia Funderburk",
"isActive": false,
"fromDate": "\/Date(1790812800000)\/",
"toDate": "\/Date(1822262400000)\/",
"fromQuantity": 1.00,
"crossReferences": [
{
"externalSystem": "PLM",
"externalKey": "BOMV-4410-B"
}
]
}

Activation​

In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("BOM version approved") or by filtering the Category column to Production control. 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).