Why do you need this change?
We need a new event inside the procedure GetNeededQty of the "Prod. Order Component" table, in order to be able to manage getneedqty calculation according to custom logics in different lines of the procedure.
No sensitive data will be exposed exploiting the new events.
The IsHandled variable, will be set to true only if a partucular condition on Rec is satisfied. It is just a simple condition to verify. So the it won't have a big impact according to the performances.
Describe the request
In procedure GetNeededQty of table 5407 "Prod. Order Component" we need an event:
[IntegrationEvent(false, false)]
local procedure OnGetNeededQtyOnBeforeExitAfterPreviousPosting(var ProdOrderComponent: Record "Prod. Order Component"; var CompQtyBase: Decimal; var Result: Decimal; var IsHandled: Boolean)
begin
end;
Changes between **:
procedure GetNeededQty(CalcBasedOn: Option "Actual Output","Expected Output"; IncludePreviousPosting: Boolean): Decimal
var
ProdOrderLine: Record "Prod. Order Line";
ProdOrderRtngLine: Record "Prod. Order Routing Line";
CapLedgEntry: Record "Capacity Ledger Entry";
MfgCostCalcMgt: Codeunit "Mfg. Cost Calculation Mgt.";
OutputQtyBase: Decimal;
CompQtyBase: Decimal;
NeededQty: Decimal;
RoundingPrecision: Decimal;
IsHandled: Boolean;
begin
Item.Get("Item No.");
RoundingPrecision := Item."Rounding Precision";
if RoundingPrecision = 0 then
RoundingPrecision := UOMMgt.QtyRndPrecision();
OnGetNeededQtyOnBeforeCalcBasedOn(Rec, RoundingPrecision);
if CalcBasedOn = CalcBasedOn::"Actual Output" then begin
ProdOrderLine.Get(Status, "Prod. Order No.", "Prod. Order Line No.");
ProdOrderRtngLine.SetRange(Status, Status);
ProdOrderRtngLine.SetRange("Prod. Order No.", "Prod. Order No.");
ProdOrderRtngLine.SetRange("Routing No.", ProdOrderLine."Routing No.");
ProdOrderRtngLine.SetRange("Routing Reference No.", ProdOrderLine."Routing Reference No.");
ProdOrderRtngLine.SetRange("Routing Link Code", "Routing Link Code");
if not ProdOrderRtngLine.FindFirst() or ("Routing Link Code" = '') then begin
ProdOrderRtngLine.SetRange("Routing Link Code");
ProdOrderRtngLine.SetFilter("Next Operation No.", '%1', '');
if not ProdOrderRtngLine.FindFirst() then
ProdOrderRtngLine."Operation No." := '';
OnGetNeededQtyOnAfterLastOperationFound(Rec, ProdOrderRtngLine);
end;
if Status in [Status::Released, Status::Finished] then begin
CapLedgEntry.SetCurrentKey("Order Type", "Order No.", "Order Line No.");
CapLedgEntry.SetRange("Order Type", CapLedgEntry."Order Type"::Production);
CapLedgEntry.SetRange("Order No.", "Prod. Order No.");
CapLedgEntry.SetRange("Order Line No.", "Prod. Order Line No.");
CapLedgEntry.SetRange("Operation No.", ProdOrderRtngLine."Operation No.");
if CapLedgEntry.Find('-') then
repeat
IsHandled := false;
OnGetNeededQtyOnBeforeAddOutputQtyBase(CapLedgEntry, OutputQtyBase, IsHandled, Rec);
if not IsHandled then
OutputQtyBase := OutputQtyBase + CapLedgEntry."Output Quantity" + CapLedgEntry."Scrap Quantity";
until CapLedgEntry.Next() = 0;
end;
**Clear(Result);
OnGetNeededQtyBeforeCalcCompQtyBase(Ishandled, Rec, OutputQtyBase, Result);
if Ishandled then
exit(Result);**
CompQtyBase := MfgCostCalcMgt.CalcActNeededQtyBase(ProdOrderLine, Rec, OutputQtyBase);
OnGetNeededQtyAfterCalcCompQtyBase(Rec, CompQtyBase, OutputQtyBase);
NeededQty := UOMMgt.RoundToItemRndPrecision(CompQtyBase / "Qty. per Unit of Measure", RoundingPrecision);
if IncludePreviousPosting then begin
if Status in [Status::Released, Status::Finished] then
CalcFields("Act. Consumption (Qty)");
OnGetNeededQtyAfterCalcActConsumptionQty(Rec);
NeededQty :=
NeededQty -
UOMMgt.RoundToItemRndPrecision("Act. Consumption (Qty)" / "Qty. per Unit of Measure", RoundingPrecision);
IsHandled := false;
OnGetNeededQtyOnBeforeExitWithPreviousPosting(Rec, CompQtyBase, NeededQty, IsHandled);
if IsHandled then
exit(NeededQty);
exit(NeededQty);
end;
**IsHandled := false;
OnGetNeededQtyOnBeforeExitAfterPreviousPosting(Rec, CompQtyBase, NeededQty, IsHandled);
if IsHandled then
exit(NeededQty);**
exit(NeededQty);
end;
OnGetNeededQtyOnAfterCalcBasedOn(Rec);
exit(Round("Remaining Quantity", RoundingPrecision));
end;
Provide an implementation (optional)
Alternatives evaluated
We evaluated the existing events exposed by Prod. Order Component.GetNeededQty, including:
OnGetNeededQtyOnBeforeCalcBasedOn
OnGetNeededQtyOnBeforeAddOutputQtyBase
OnGetNeededQtyAfterCalcCompQtyBase
OnGetNeededQtyAfterCalcActConsumptionQty
OnGetNeededQtyOnBeforeExitWithPreviousPosting
OnGetNeededQtyOnAfterCalcBasedOn
These events are useful for modifying individual inputs or intermediate values, but they do not provide a way to completely replace the standard calculation at the required points.
In particular, OnGetNeededQtyAfterCalcCompQtyBase is raised only after the standard call to MfgCostCalcMgt.CalcActNeededQtyBase has already been executed. Therefore, an extension subscribing to that event can modify CompQtyBase, but the standard calculation is still executed first. This is not sufficient for scenarios where the extension must apply a completely different calculation and the standard calculation must be bypassed.
Likewise, OnGetNeededQtyOnBeforeExitWithPreviousPosting only applies to the branch where IncludePreviousPosting is true. It cannot be used to replace the result in the branch where previous postings are not included.
We also considered implementing the customization outside GetNeededQty, for example by duplicating the calculation in the consuming process. This would require reproducing standard Business Central calculation logic outside the base application and would create a maintenance risk whenever the standard implementation changes.
For these reasons, we consider an event at the requested points necessary to provide an extension point without duplicating the standard GetNeededQty implementation.
Justification for IsHandled
The first requested event, OnGetNeededQtyBeforeCalcCompQtyBase, is required to support scenarios where the standard calculation of CompQtyBase must be completely replaced.
The standard implementation currently performs:
CompQtyBase := MfgCostCalcMgt.CalcActNeededQtyBase(ProdOrderLine, Rec, OutputQtyBase);
There are customer-specific production scenarios where the required component quantity cannot be calculated using the standard CalcActNeededQtyBase calculation. For example, a custom extension may determine the required quantity using additional component-specific rules based on fields of the Prod. Order Component record and/or custom production information.
In such a case, subscribing to OnGetNeededQtyAfterCalcCompQtyBase is not equivalent, because the standard calculation would still be executed first. The required behavior is to prevent the standard calculation from being executed and provide the custom result instead.
Therefore, the subscriber needs to be able to set CompQtyBase / Result and signal that the standard implementation must be skipped:
The second requested event, OnGetNeededQtyOnBeforeExitAfterPreviousPosting, is required for the same reason at the end of the procedure. After the standard calculation has been completed, there are scenarios where the final NeededQty must be replaced by a custom result before the procedure exits.
A regular event without IsHandled would allow an extension to inspect or modify the value, but would not provide an explicit mechanism to indicate that the standard exit/result handling has been replaced by the subscriber's calculation.
The IsHandled flag is only set to true when the subscriber's specific business condition is satisfied. In all other cases, the standard Business Central implementation remains unchanged.
Multi-extension interaction
We understand that IsHandled events can create interaction considerations when multiple extensions subscribe to the same event.
The expected behavior is that an extension sets IsHandled := true only when its own specific condition is satisfied. If no subscriber handles the event, IsHandled remains false and the standard Business Central logic is executed.
If multiple extensions subscribe to the event and more than one extension satisfies its handling condition, the first subscriber setting IsHandled := true may prevent the standard logic from being executed, and another subscriber may also attempt to provide a custom result.
We consider this an inherent characteristic of IsHandled events and expect extensions using this event to apply sufficiently specific conditions to avoid handling records outside their own scope.
The requested events do not expose sensitive data and do not introduce additional database operations by themselves. The event invocation consists only of passing the existing procedure variables to subscribers. Subscribers can decide whether to handle the calculation based on the current Prod. Order Component record.
The requested extensibility point therefore allows customer-specific implementations without requiring extensions to copy or replace the entire GetNeededQty procedure.
The existing event OnGetNeededQtyOnBeforeCalcActNeededQtyBase does not cover our scenario.
We specifically need the requested event OnGetNeededQtyOnBeforeExitAfterPreviousPosting because our customization must be able to manage the final exit of GetNeededQty in cases where IncludePreviousPosting = false.
The existing event OnGetNeededQtyOnBeforeCalcActNeededQtyBase is raised earlier in the procedure, before the remaining standard GetNeededQty logic is executed. It therefore does not allow us to control the final result at the exit point.
Furthermore, we also need to handle cases where IncludePreviousPosting = true, but the execution has not already reached an exit through the existing OnGetNeededQtyOnBeforeExitWithPreviousPosting event.
Our requirement is specifically to have an extension point immediately before the final exit(NeededQty), so that custom logic can determine whether the standard result should be replaced in all execution paths that reach this final exit.
In particular, the requested event covers:
IncludePreviousPosting = false, where the existing OnGetNeededQtyOnBeforeExitWithPreviousPosting event is never raised.
IncludePreviousPosting = true, when the execution does not exit through the earlier OnGetNeededQtyOnBeforeExitWithPreviousPosting event and subsequently reaches the final exit(NeededQty).
Therefore, the existing OnGetNeededQtyOnBeforeCalcActNeededQtyBase event cannot provide the required extensibility point, because it is executed at an earlier stage of the procedure and cannot control the final exit/result after the subsequent standard logic has been processed.
For this reason, we still require the proposed OnGetNeededQtyOnBeforeExitAfterPreviousPosting event.
Why do you need this change?
We need a new event inside the procedure GetNeededQty of the "Prod. Order Component" table, in order to be able to manage getneedqty calculation according to custom logics in different lines of the procedure.
No sensitive data will be exposed exploiting the new events.
The IsHandled variable, will be set to true only if a partucular condition on Rec is satisfied. It is just a simple condition to verify. So the it won't have a big impact according to the performances.
Describe the request
In procedure GetNeededQty of table 5407 "Prod. Order Component" we need an event:
Changes between **:
Provide an implementation (optional)
Alternatives evaluated
We evaluated the existing events exposed by
Prod. Order Component.GetNeededQty, including:OnGetNeededQtyOnBeforeCalcBasedOnOnGetNeededQtyOnBeforeAddOutputQtyBaseOnGetNeededQtyAfterCalcCompQtyBaseOnGetNeededQtyAfterCalcActConsumptionQtyOnGetNeededQtyOnBeforeExitWithPreviousPostingOnGetNeededQtyOnAfterCalcBasedOnThese events are useful for modifying individual inputs or intermediate values, but they do not provide a way to completely replace the standard calculation at the required points.
In particular,
OnGetNeededQtyAfterCalcCompQtyBaseis raised only after the standard call toMfgCostCalcMgt.CalcActNeededQtyBasehas already been executed. Therefore, an extension subscribing to that event can modifyCompQtyBase, but the standard calculation is still executed first. This is not sufficient for scenarios where the extension must apply a completely different calculation and the standard calculation must be bypassed.Likewise,
OnGetNeededQtyOnBeforeExitWithPreviousPostingonly applies to the branch whereIncludePreviousPostingis true. It cannot be used to replace the result in the branch where previous postings are not included.We also considered implementing the customization outside
GetNeededQty, for example by duplicating the calculation in the consuming process. This would require reproducing standard Business Central calculation logic outside the base application and would create a maintenance risk whenever the standard implementation changes.For these reasons, we consider an event at the requested points necessary to provide an extension point without duplicating the standard
GetNeededQtyimplementation.Justification for IsHandled
The first requested event,
OnGetNeededQtyBeforeCalcCompQtyBase, is required to support scenarios where the standard calculation ofCompQtyBasemust be completely replaced.The standard implementation currently performs:
There are customer-specific production scenarios where the required component quantity cannot be calculated using the standard
CalcActNeededQtyBasecalculation. For example, a custom extension may determine the required quantity using additional component-specific rules based on fields of theProd. Order Componentrecord and/or custom production information.In such a case, subscribing to
OnGetNeededQtyAfterCalcCompQtyBaseis not equivalent, because the standard calculation would still be executed first. The required behavior is to prevent the standard calculation from being executed and provide the custom result instead.Therefore, the subscriber needs to be able to set
CompQtyBase/Resultand signal that the standard implementation must be skipped:IsHandled := true;The second requested event,
OnGetNeededQtyOnBeforeExitAfterPreviousPosting, is required for the same reason at the end of the procedure. After the standard calculation has been completed, there are scenarios where the finalNeededQtymust be replaced by a custom result before the procedure exits.A regular event without
IsHandledwould allow an extension to inspect or modify the value, but would not provide an explicit mechanism to indicate that the standard exit/result handling has been replaced by the subscriber's calculation.The
IsHandledflag is only set totruewhen the subscriber's specific business condition is satisfied. In all other cases, the standard Business Central implementation remains unchanged.Multi-extension interaction
We understand that
IsHandledevents can create interaction considerations when multiple extensions subscribe to the same event.The expected behavior is that an extension sets
IsHandled := trueonly when its own specific condition is satisfied. If no subscriber handles the event,IsHandledremainsfalseand the standard Business Central logic is executed.If multiple extensions subscribe to the event and more than one extension satisfies its handling condition, the first subscriber setting
IsHandled := truemay prevent the standard logic from being executed, and another subscriber may also attempt to provide a custom result.We consider this an inherent characteristic of
IsHandledevents and expect extensions using this event to apply sufficiently specific conditions to avoid handling records outside their own scope.The requested events do not expose sensitive data and do not introduce additional database operations by themselves. The event invocation consists only of passing the existing procedure variables to subscribers. Subscribers can decide whether to handle the calculation based on the current
Prod. Order Componentrecord.The requested extensibility point therefore allows customer-specific implementations without requiring extensions to copy or replace the entire
GetNeededQtyprocedure.The existing event
OnGetNeededQtyOnBeforeCalcActNeededQtyBasedoes not cover our scenario.We specifically need the requested event
OnGetNeededQtyOnBeforeExitAfterPreviousPostingbecause our customization must be able to manage the finalexitofGetNeededQtyin cases whereIncludePreviousPosting = false.The existing event
OnGetNeededQtyOnBeforeCalcActNeededQtyBaseis raised earlier in the procedure, before the remaining standardGetNeededQtylogic is executed. It therefore does not allow us to control the final result at the exit point.Furthermore, we also need to handle cases where
IncludePreviousPosting = true, but the execution has not already reached anexitthrough the existingOnGetNeededQtyOnBeforeExitWithPreviousPostingevent.Our requirement is specifically to have an extension point immediately before the final
exit(NeededQty), so that custom logic can determine whether the standard result should be replaced in all execution paths that reach this final exit.In particular, the requested event covers:
IncludePreviousPosting = false, where the existingOnGetNeededQtyOnBeforeExitWithPreviousPostingevent is never raised.IncludePreviousPosting = true, when the execution does not exit through the earlierOnGetNeededQtyOnBeforeExitWithPreviousPostingevent and subsequently reaches the finalexit(NeededQty).Therefore, the existing
OnGetNeededQtyOnBeforeCalcActNeededQtyBaseevent cannot provide the required extensibility point, because it is executed at an earlier stage of the procedure and cannot control the final exit/result after the subsequent standard logic has been processed.For this reason, we still require the proposed
OnGetNeededQtyOnBeforeExitAfterPreviousPostingevent.