Skip to main content

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 classMGCLatticePurchAgreementConfirmedBusinessEvent
Contract classMGCLatticePurchAgreementConfirmedBusinessEventContract
CategoryPurchase orders
ModuleModuleAxapta::PurchaseOrder
Label IDsPurchAgreementConfirmedBusinessEventName / PurchAgreementConfirmedBusinessEventDescription
TriggerAgreementConfirm_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 the AgreementHeaderHistory.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 with AgreementHeaderHistory::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 the ttsbegin/ttscommit of AgreementConfirm.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 fieldDisplay labelType / EDTSourceNotes
legalEntityLegal EntityDataAreaIdPurchAgreementHeaderHistory.BuyingLegalEntity (the agreement's buying legal entity, copied from the agreement header into the snapshot); if that is empty or doesn't resolve, PurchAgreementHeaderHistory.VendorDataAreaIdCompany 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.
purchAgreementIdPurchase Agreement IDstrPurchAgreementHeaderHistory.PurchNumberSequenceThe purchase agreement ID (EDT PurchAgreementId on the history table). The confirmation number isn't included.
vendorAccountVendor AccountVendAccountPurchAgreementHeaderHistory.VendAccountVendor the agreement is with.
effectiveDateEffective DateTransDateAgreementHeaderHistory.DefaultAgreementLineEffectiveDateThe agreement's default effective date for its lines, as of this confirmation.
expirationDateExpiration DateTransDateAgreementHeaderHistory.DefaultAgreementLineExpirationDateThe agreement's default expiration date for its lines, as of this confirmation.
crossReferencesCross referencesList of MGCLatticeCrossReferenceEventContractMGCLatticeCrossReferenceEventHelper::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).