Skip to main content

Advanced bank reconciliation completed

Fires when an Advanced bank reconciliation worksheet is marked as reconciled - the moment D365 sets the reconciliation's Reconciled flag. It carries the reconciliation ID, bank account, cut-off and reconciled dates, the bank statements whose lines the reconciliation matched, the bank currency, the number of matched statement lines and bank transactions with their totals in bank currency, and the user who reconciled, giving treasury and cash-management systems a push signal that a reconciliation has been closed. The classic bank account reconciliation raises Bank reconciliation completed instead.

Event classMGCLatticeAdvancedBankReconciliationCompletedBusinessEvent
Contract classMGCLatticeAdvancedBankReconciliationCompletedBusinessEventContract
CategoryBank management
ModuleModuleAxapta::Bank
Label IDsAdvancedBankReconciliationCompletedBusinessEventName / AdvancedBankReconciliationCompletedBusinessEventDescription
TriggerBankReconciliationHeader::reconcile() / reconcileInBatch() -> IsReconciled goes from No to Yes

Trigger / Hook​

  • Extension class: MGCLatticeBankReconciliationHeader_Table_Extension, [ExtensionOf(tableStr(BankReconciliationHeader))] - a process hook on the two public reconcile entry points, not on the table's update().
  • CoC method signatures: public static void reconcile(RecId _reconciliationRecId) and public static void reconcileInBatch(RecId _reconciliationRecId, UserConnection _connection).
  • Firing condition: when the event is activated, each wrapper reads the worksheet's IsReconciled before next; afterwards MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent::raiseIfReconciliationCompleted() reads the worksheet again and sends the event when the flag changed from No to Yes (isReconciliationCompleted). A run that fails validation, does not get the bank account lock, or rolls back leaves the flag at No and raises nothing; reconciling a worksheet that is already reconciled does not raise it again.
  • Process: the reconciliation worksheet's Mark as reconciled action, run interactively (reconcile) or in batch (reconcileInBatch). Both run the private BankReconciliationHeader::reconcileInner, which inside its own transaction writes the reconciliation history, marks every matched statement line and bank document reconciled, and then sets IsReconciled to Yes and ReconciledDate to today (in the user's time zone). No other standard code sets IsReconciled to Yes.
  • Other writers: worksheets written by data entities, imports or code outside these two methods do not raise the event.
  • Matched data: when the event is built, the worksheet's matching items (BankReconciliationMatchingItemView for the reconciliation) are read - the same rows the Reconcile step has just walked.
  • Unreconcile sets IsReconciled back to No and raises nothing. A worksheet that is unreconciled and then marked as reconciled again raises the event again, with the matches it has then.
  • The classic bank account reconciliation is not covered. It reconciles one BankAccountStatement with the Reconcile account action and raises Bank reconciliation completed; it never touches BankReconciliationHeader.
  • Timing: the event is sent after next returns, when reconcileInner's transaction has committed (unless the caller holds an outer transaction, in which case send() writes to the business events commit log inside it and delivery waits for its commit). A reconciliation that fails and rolls back never delivers. Building the payload only reads data, and a bank document that cannot be valued counts with amount 0 rather than failing.
  • Enablement gate: BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent)), checked before the worksheet is read at all; while the event is not activated the wrappers read nothing and build nothing.
public static void reconcile(RecId _reconciliationRecId)
{
// Read the worksheet only when the event is active (cached check); Yes makes the raise below a no-op.
NoYes previousIsReconciled = BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent))
? BankReconciliationHeader::find(_reconciliationRecId).IsReconciled
: NoYes::Yes;

next reconcile(_reconciliationRecId);

MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent::raiseIfReconciliationCompleted(_reconciliationRecId, previousIsReconciled);
}

// reconcileInBatch(RecId, UserConnection) is wrapped the same way.

Payload Contract​

One row per [DataMember], in declaration order. initialize() reads the reconciled BankReconciliationHeader row and its bank account, then counts and totals the statement lines and bank documents matched on the worksheet and collects the statements those lines belong to.

JSON fieldDisplay labelType / EDTSourceNotes
legalEntityLegal EntityDataAreaIdBankReconciliationHeader.DataAreaIdCompany of the bank account, in lower case (for example usmf).
reconciliationIdReconciliation IDBankReconciliationIdBankReconciliationHeader.ReconciliationIdThe reconciliation worksheet.
bankAccountIdBank Account IDCompanyBankAccountIdBankReconciliationHeader.AccountIdBank account.
cutOffDateCut-off DateBankReconciliationCutOffDateBankReconciliationHeader.CutOffDateThe worksheet's cut-off date (date, \/Date(milliseconds)\/ form).
statementIdsStatement IDsList of BankStatementIdBankStmtISOAccountStatement.Identification of each statement with at least one matched line, ordered by FromDateTimeThe bank statements the reconciliation covers, as a JSON array of strings; a worksheet can span several. [] when no statement line was matched.
statementsFromDateTimeStatements FromBankStmtISODateTime (utcdatetime)Earliest BankStmtISOAccountStatement.FromDateTime of those statementsStart of the period the covered statements span; the empty date-time ("\/Date(-2208988800000)\/") when statementIds is empty.
statementsToDateTimeStatements ToBankStmtISODateTime (utcdatetime)Latest BankStmtISOAccountStatement.ToDateTime of those statementsEnd of that period; empty like statementsFromDateTime.
reconciledDateReconciled DateBankReconciliationReconciledDateBankReconciliationHeader.ReconciledDateDate the worksheet was marked as reconciled.
currencyCodeCurrency CodeCurrencyCodeBankAccountTable.CurrencyCode of the bank accountThe bank currency; every amount in the payload is in this currency.
matchedStatementLineCountMatched Statement Line Countintcount(RecId) of BankStmtISOReportEntry rows matched on the worksheetNumber of bank statement lines reconciled.
matchedStatementAmountMatched Statement AmountAmountCurBankReconciliationHeader.getMatchedStatementTotal()Net total of those lines in bank currency, as the worksheet computes it: debit lines add, credit lines subtract.
matchedBankTransactionCountMatched Bank Transaction CountintNumber of distinct BankDocumentTable rows matched on the worksheetNumber of bank transactions reconciled - the rows of the worksheet's bank transactions grid (bank transactions, checks, deposit slips and so on).
matchedBankTransactionAmountMatched Bank Transaction AmountAmountCurSum of BankDocument.getBankCurrencyAmount() over those documentsNet total of those bank transactions in bank currency, including any correction amount, as the worksheet values them.
reconciledByReconciled ByUserIdcurUserId() when the event is raisedThe user who marked the worksheet as reconciled; when it ran in batch, the user the batch job runs as.

The two totals are equal for one-to-one matches. Compare them rather than assume they are equal: a statement line can be reconciled without a bank transaction of the same amount, for example a line matched to a new voucher generated from the worksheet, or a match with a correction amount.

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, not 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; an event that joins no run carries Event: followed by a lower-case 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 does not join a run: correlationId is unique to each emission.

Example Payload​

A worksheet with an August cut-off that reconciled lines from two imported bank statements.

{
"BusinessEventId": "MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent",
"ControlNumber": 5637148912,
"EventId": "3E8A61D2-94B7-4C05-A1F3-6B2D7E90C4A8",
"EventTime": "\/Date(1788358328000)\/",
"EventTimeIso8601": "2026-09-02T14:12:08.4107391Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{9E0E481C-DDF2-461E-F503-CA809B9A682C}",
"ParentContextRecordSubjects": [],
"eventSequence": 48241,
"correlationId": "Event:b51d7f20-6c3e-4a98-8e17-3f0a9c2d6b84",
"schemaVersion": 1,
"legalEntity": "usmf",
"reconciliationId": "BR-000042",
"bankAccountId": "USMF OPER",
"cutOffDate": "\/Date(1788134400000)\/",
"statementIds": ["STMT-2026-08A", "STMT-2026-08B"],
"statementsFromDateTime": "\/Date(1785542400000)\/",
"statementsToDateTime": "\/Date(1788220799000)\/",
"reconciledDate": "\/Date(1788307200000)\/",
"currencyCode": "USD",
"matchedStatementLineCount": 57,
"matchedStatementAmount": 48210.75,
"matchedBankTransactionCount": 55,
"matchedBankTransactionAmount": 48210.75,
"reconciledBy": "Admin"
}

Activation​

In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Advanced bank reconciliation completed") or by filtering the Category column to Bank management. 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 only covers bank accounts reconciled with Advanced bank reconciliation; to cover bank accounts that still use the classic bank account reconciliation, also activate Bank reconciliation completed.