MRP run completed
Fires once when a master planning run of the built-in planning engine finishes calculating a plan. It publishes the plan identifier and the company so downstream systems can react to freshly recalculated planned orders, requirement messages, and pegging - for example to kick off a planned-order release review or refresh an external planning dashboard. Helper threads, forecast scheduling, firming and order explosions don't raise it. A canceled run (canceled by the user or because its batch job was canceled) doesn't raise it. Master planning with Planning Optimization doesn't raise it either: those runs are executed by the planning service.
| Event class | MGCLatticeMRPRunCompletedBusinessEvent |
| Contract class | MGCLatticeMRPRunCompletedBusinessEventContract |
| Category | Master planning |
| Module | ModuleAxapta::MasterPlanning |
| Label IDs | MRPRunCompletedBusinessEventName / MRPRunCompletedBusinessEventDescription |
| Trigger | ReqCalc.run() -> after next run() returns, for the main thread of a ReqCalcScheduleItemTable run that was not canceled (built-in master planning engine only) |
Trigger / Hook
- Extension class:
MGCLatticeReqCalc_Class_Extension, declared[ExtensionOf(classStr(ReqCalc))]. - CoC method signature:
void run(). - Firing condition: after the base
next run()returns, the event is sent only whenMGCLatticeMRPRunCompletedBusinessEvent::mustRaiseForRun(classIdGet(this), this.parmThisIsChildThread(), wasCanceled)is true - the run was not canceled andisPlanCalculationRunholds: the run is aReqCalcScheduleItemTable(the class behind Master planning > Run > Master planning) and not a helper thread. That gives one emission per completed plan calculation run:- Canceled runs:
ReqCalc.run()returns normally after a cancellation and logs it on the plan's master planning log (ReqLog.Cancelled). The hook reads the run'scanceledflag and the log buffer just written (parmReqPlanData().reqLog()) and sends nothing when either shows the run was canceled. - Helper threads: a run with helpers starts helper batch tasks (
ReqProcessExternThread) that each run their ownReqCalcScheduleItemTableflagged as a child thread; those don't fire. The main thread'srun()returns only after the whole plan is calculated, so the event marks the end of the run. - Other calculations that share
ReqCalc.run()don't fire: forecast scheduling (ReqCalcForecastItemTable), parallel firming (ReqCalcParallelFirming), item-level planning (ReqCalcScheduleItem,ReqCalcForecastItem) - for example Master planning from the net requirements page - order explosions (ReqCalcExplodeand its subclasses) and continuity scheduling. - Intercompany master planning runs a master planning run in each company of the planning group, per iteration, so it raises one event per company and iteration, each in that company.
- Canceled runs:
- If
run()throws, nothing is sent.ReqCalc.run()starts withReqParameters::checkPlanningProcessesAreEnabled(), so when master planning is disabled in the master planning parameters the run stops with an error and no event is raised. - Planning Optimization: when the planning service is enabled for the company, master planning is executed by
MpsMasterPlanningRunnerRegen(aRunBaseBatchclass, not aReqCalc). Those runs never pass throughReqCalc.run()and don't raise this event. - Enablement gate:
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeMRPRunCompletedBusinessEvent)). - The plan identifier is sourced from the running
ReqCalcinstance viathis.parmReqPlanId(). - Correlation:
buildContract()callscontract.correlateTo(MGCLatticeBusinessEventRunCorrelation::currentRunCorrelation('MRPRun', planId)). When the run executes in batch,correlationIdisBatchTask:<RecId of the current batch task>- the main task, since only the main thread raises the event; when it runs interactively, it'sMRPRun:<planId>.
void run()
{
next run();
// The activation check is a cached lookup and comes first, so an environment that has not activated the
// event does not read the plan log.
if (!BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeMRPRunCompletedBusinessEvent)))
{
return;
}
ReqPlanData reqPlanDataLocal = this.parmReqPlanData();
boolean wasCanceled = canceled
|| (reqPlanDataLocal != null && reqPlanDataLocal.reqLog().Cancelled == NoYes::Yes);
if (MGCLatticeMRPRunCompletedBusinessEvent::mustRaiseForRun(classIdGet(this), this.parmThisIsChildThread(), wasCanceled))
{
MGCLatticeMRPRunCompletedBusinessEvent::construct(this.parmReqPlanId()).send();
}
}
Payload Contract
One row per [DataMember], in declaration order. Both values are set in MGCLatticeMRPRunCompletedBusinessEventContract::construct().
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | strLwr(curExt()) | Company the run calculated, in lower case |
planId | Plan ID | str | ReqCalc.parmReqPlanId() | Master plan the run calculated, passed through MGCLatticeMRPRunCompletedBusinessEvent::construct(); carried as a plain string |
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
A master planning run executed in batch:
{
"BusinessEventId": "MGCLatticeMRPRunCompletedBusinessEvent",
"ControlNumber": 5637151102,
"EventId": "A3F9C2E1-4B6D-4A21-9F0E-7C1D2E8B4A55",
"EventTime": "\/Date(1790291742000)\/",
"EventTimeIso8601": "2026-09-24T23:15:42.9940434Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{15F76DFA-DB53-0023-F1D9-6AA3EED297D6}",
"ParentContextRecordSubjects": [],
"eventSequence": 48213,
"correlationId": "BatchTask:5637148576",
"schemaVersion": 1,
"legalEntity": "usmf",
"planId": "StaticPlan"
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("MRP run completed") or by filtering the Category column to Master planning. 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). No other setup is needed, but the event is raised only by the built-in master planning engine: companies that run master planning with Planning Optimization don't receive it.