Purchase requisition approved
Fires when a purchase requisition completes its approval workflow and its status is set to Approved. This is the signal that a request for goods or services has cleared review and can be released to purchase orders. Downstream systems can use it to start sourcing, budgeting, or notification flows.
| Event class | MGCLatticePurchReqApprovedBusinessEvent |
| Contract class | MGCLatticePurchReqApprovedBusinessEventContract |
| Category | Purchase orders |
| Module | ModuleAxapta::PurchaseOrder |
| Label IDs | PurchReqApprovedBusinessEventName / PurchReqApprovedBusinessEventDescription |
| Trigger | PurchReqWFStatusTransitionHelper::setPurchReqTable2Approved() -> requisition set to Approved by workflow completion (!_isReset2Approved) |
Trigger / Hook
- Extension class:
MGCLatticePurchReqWFStatusTransitionHelper_Class_Extension, decorated with[ExtensionOf(classStr(PurchReqWFStatusTransitionHelper))]. - CoC method signature:
static void setPurchReqTable2Approved(RecId _purchReqTableRecId, boolean _isReset2Approved). This is the workflow status-transition method that sets a requisition to Approved, not thePurchReqTable.update()table write. - Firing condition: after
next setPurchReqTable2Approved(...), the event is sent when_isReset2Approvedis false. The requisition is re-read withPurchReqTable::find(_purchReqTableRecId), so the payload reflects the saved record. - Where the call comes from: the purchase requisition workflow's completed event handler (
PurchReqWFTypeEventHandler.completed()) calls the method with_isReset2Approvedfalse when the workflow completes, unless the requisition is Closed. The same method is also called with_isReset2Approvedtrue to reset a requisition back to Approved (fromPurchReqLineand from budget reservation lines,BudgetReservationLine_PSN); those calls don't raise the event. So the event is raised once per completed approval workflow, and only through the workflow. - Transaction:
setPurchReqTable2Approved()updates the requisition and its lines inside its ownttsbegin/ttscommit, and the event is sent after it returns.BusinessEventsBase.send()only writes to the commit log inside the current transaction and delivery is asynchronous post-commit, so an event raised inside a larger transaction that rolls back is never delivered. - Enablement gate: guarded by
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticePurchReqApprovedBusinessEvent)), so the event only sends when activated in the business events catalog.
static void setPurchReqTable2Approved(RecId _purchReqTableRecId, boolean _isReset2Approved)
{
next setPurchReqTable2Approved(_purchReqTableRecId, _isReset2Approved);
if (!_isReset2Approved
&& BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticePurchReqApprovedBusinessEvent)))
{
MGCLatticePurchReqApprovedBusinessEvent::newFromPurchReqTable(PurchReqTable::find(_purchReqTableRecId)).send();
}
}
Payload Contract
One row per [DataMember], in declaration order. The sources are the re-read PurchReqTable record and its lines (PurchReqLine), mapped in initialize(). Purchase requisitions are shared across legal entities (the tables have no company column), and one requisition can buy for several legal entities: each line carries its own buying legal entity.
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | Buying legal entity of the first requisition line (PurchReqLine.BuyingLegalEntity, by line number); if no line has one, the requisition's default buying legal entity (PurchReqTable.CompanyInfoDefault) | Company id in lowercase. When the lines buy for more than one legal entity, all of them are in buyingLegalEntities. BusinessEventLegalEntity is the company in which the approval was processed, which can differ. |
buyingLegalEntities | Buying Legal Entities | List of str | Distinct PurchReqLine.BuyingLegalEntity values of the requisition's lines | Company ids in lowercase, each listed once, in the order of the first line that uses it. Empty when no line has a buying legal entity. |
purchReqId | Requisition ID | PurchReqId | PurchReqTable.PurchReqId | Purchase requisition number. |
requisitionName | Requisition Name | PurchReqName | PurchReqTable.PurchReqName | Name of the requisition. |
requesterPersonnelNumber | Requester Personnel Number | HcmPersonnelNumberId | HcmWorker.PersonnelNumber of PurchReqTable.Originator | Personnel number of the worker who prepared the requisition, labeled Preparer in the client. Line-level requesters aren't included. |
crossReferences | Cross references | List of MGCLatticeCrossReferenceEventContract | MGCLatticeCrossReferenceEventHelper::listFor(PurchReqTable) | Keys external systems hold for the purchase requisition: one { externalSystem, externalKey } object per external system, ordered by external system, historical keys included; [] when it has none. See Cross-reference keys. Read in the legal entity of the requisition's default buying legal entity, where its keys are set. |
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.
Example Payload
{
"BusinessEventId": "MGCLatticePurchReqApprovedBusinessEvent",
"ControlNumber": 5637151819,
"EventId": "184EF5D1-E9E0-4552-8283-210F2758DDAE",
"EventTime": "\/Date(1790249822000)\/",
"EventTimeIso8601": "2026-09-24T11:37:02.2782934Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{0028E98B-AD1D-B341-ECAF-5423B427D2D2}",
"ParentContextRecordSubjects": [],
"eventSequence": 48219,
"correlationId": "Event:ab1b426e-b511-4b6c-8c4f-f4a5f227fcc5",
"schemaVersion": 1,
"legalEntity": "usmf",
"buyingLegalEntities": ["usmf"],
"purchReqId": "000912",
"requisitionName": "Office furniture for new hires",
"requesterPersonnelNumber": "000020",
"crossReferences": [
{
"externalSystem": "PROCURE",
"externalKey": "REQ-88120"
}
]
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Purchase requisition approved") or by filtering the Category column to Purchase 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). The event is only raised when a purchase requisition approval workflow completes, so requisitions must be submitted to an active purchase requisition workflow.