Purchase agreement confirmed
Fires when a purchase agreement is confirmed. Each confirmation takes a snapshot of the agreement header in agreement history (PurchAgreementHeaderHistory), which records the negotiated terms, such as the vendor and the default effective and expiration dates, that release orders draw against. Procurement and supplier-management systems can use this event to react as soon as a purchase commitment is confirmed or reconfirmed.
| Event class | MGCLatticePurchAgreementConfirmedBusinessEvent |
| Contract class | MGCLatticePurchAgreementConfirmedBusinessEventContract |
| Category | Purchase orders |
| Module | ModuleAxapta::PurchaseOrder |
| Label IDs | PurchAgreementConfirmedBusinessEventName / PurchAgreementConfirmedBusinessEventDescription |
| Trigger | AgreementConfirm_Purch.createHeaderHistory() -> after the purchase agreement header history snapshot is created (RecId guard) |
Trigger / Hook
- Extension class:
MGCLatticeAgreementConfirm_Purch_Class_Extension, decorated with[ExtensionOf(classStr(AgreementConfirm_Purch))]. - CoC method signature:
protected recId createHeaderHistory(). This is the purchase agreement confirmation step that writes the header snapshot, not theAgreementHeaderHistory.insert()table write. Because the hook is on the purchase confirmation class, sales agreements never raise this event. - Firing condition: after
next createHeaderHistory(), when the event is activated (checked first, a cached lookup), the returned record ID is resolved withAgreementHeaderHistory::find(headerHistoryRecId), and the event is sent when that history record exists (agreementHeaderHistory.RecId). - When it fires: every confirmation of a purchase agreement creates a new header history snapshot with the next confirmation number, so the event is raised on each confirmation, including reconfirming an agreement that was confirmed before. A pro forma confirmation doesn't create history and doesn't raise the event. If the approved vendor list check in
AgreementConfirm_Purch.startConfirm()fails, the confirmation stops before the snapshot is created and nothing is sent. - Transaction:
createHeaderHistory()runs inside thettsbegin/ttscommitofAgreementConfirm.createHistory(), before the line history is written.BusinessEventsBase.send()only writes to the commit log inside that transaction and delivery is asynchronous post-commit, so a confirmation that rolls back never delivers. - Enablement gate: guarded by
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticePurchAgreementConfirmedBusinessEvent)), so the event only sends when activated in the business events catalog.
protected recId createHeaderHistory()
{
recId headerHistoryRecId = next createHeaderHistory();
if (headerHistoryRecId
&& BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticePurchAgreementConfirmedBusinessEvent)))
{
AgreementHeaderHistory agreementHeaderHistory = AgreementHeaderHistory::find(headerHistoryRecId);
if (agreementHeaderHistory.RecId)
{
MGCLatticePurchAgreementConfirmedBusinessEvent::newFromAgreementHeaderHistory(agreementHeaderHistory).send();
}
}
return headerHistoryRecId;
}
Payload Contract
One row per [DataMember], in declaration order. The contract reads the new AgreementHeaderHistory record, and reads the purchase-specific fields through it as a PurchAgreementHeaderHistory record, in initialize().
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | PurchAgreementHeaderHistory.BuyingLegalEntity (the agreement's buying legal entity, copied from the agreement header into the snapshot); if that is empty or doesn't resolve, PurchAgreementHeaderHistory.VendorDataAreaId | Company id in lowercase. Agreement history is a shared table with no company column, so the company comes from the agreement's buying legal entity, not from DataAreaId. BusinessEventLegalEntity is the company in which the confirmation ran, which can differ. |
purchAgreementId | Purchase Agreement ID | str | PurchAgreementHeaderHistory.PurchNumberSequence | The purchase agreement ID (EDT PurchAgreementId on the history table). The confirmation number isn't included. |
vendorAccount | Vendor Account | VendAccount | PurchAgreementHeaderHistory.VendAccount | Vendor the agreement is with. |
effectiveDate | Effective Date | TransDate | AgreementHeaderHistory.DefaultAgreementLineEffectiveDate | The agreement's default effective date for its lines, as of this confirmation. |
expirationDate | Expiration Date | TransDate | AgreementHeaderHistory.DefaultAgreementLineExpirationDate | The agreement's default expiration date for its lines, as of this confirmation. |
crossReferences | Cross references | List of MGCLatticeCrossReferenceEventContract | MGCLatticeCrossReferenceEventHelper::listForAgreement(AgreementHeaderHistory.AgreementHeader, legalEntity) | Keys external systems hold for the purchase agreement: 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 buying legal entity. |
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": "MGCLatticePurchAgreementConfirmedBusinessEvent",
"ControlNumber": 5637151811,
"EventId": "0926016E-8B48-4402-AD40-7F0E5524FB76",
"EventTime": "\/Date(1790243726000)\/",
"EventTimeIso8601": "2026-09-24T09:55:26.2191169Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{33B3465A-E581-F63E-41AD-1414808E6B3A}",
"ParentContextRecordSubjects": [],
"eventSequence": 48211,
"correlationId": "Event:62f992b7-6068-4edd-aef0-d0fceec5d683",
"schemaVersion": 1,
"legalEntity": "usmf",
"purchAgreementId": "USMF-000012",
"vendorAccount": "US-104",
"effectiveDate": "\/Date(1790812800000)\/",
"expirationDate": "\/Date(1822262400000)\/",
"crossReferences": [
{
"externalSystem": "SRM",
"externalKey": "PA-2026-031"
}
]
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Purchase agreement confirmed") 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).