Why do you need this change?
We want to be able to skip the checks for blocked service items and blocked/deleted items when invoicing service contracts, so that active contracts for items that were later blocked or deleted can still be invoiced.
Alternative events or patterns considered
We checked OnCreateAllServLinesOnBeforeServContractLineLoop in codeunit 5940, which fires right before these checks are called from CreateAllServLines, but it has no Skip/IsHandled parameter and cannot prevent CheckServiceItemBlockedForAll / CheckItemServiceBlocked from running. A Skip-parameter design at the call site was considered as well, but placing the events inside the two procedures themselves keeps each check independently skippable and mirrors the same pattern already approved in issue #28616 (codeunit 5900 ServOrderManagement, OnBeforeCheckItemServiceBlocked) for the equivalent scenario.
Why IsHandled is required
Both procedures perform hard-coded TestField/Get validations with no existing extensibility point to bypass them. Customers need to continue invoicing active service contracts for items/service items that were later blocked or deleted, without duplicating or forking codeunit 5940. Since the checks must be skipped entirely rather than supplemented, a regular OnBefore/OnAfter event is not sufficient — only an IsHandled bypass lets the calling process continue instead of raising the error.
Performance considerations
Each event is raised once per service contract line during contract invoicing — the same frequency as the existing OnCreateAllServLinesOnBeforeServContractLineLoop event in the same loop. No additional loops, database reads, or locking beyond what a subscriber may add on its own (e.g., one Get on a setup table).
Data sensitivity review
The events expose Service Contract Line (var), which is already fully accessible in the calling procedures and their existing events (e.g., OnCreateAllServLinesOnBeforeServContractLineLoop). No new or additional sensitive data is exposed.
Multi-extension interaction/conflict risk
Both parameters follow the IsHandled pattern (initialized to false). If multiple extensions subscribe, each subscriber must check whether IsHandled is already true before evaluating its own condition, and should never reset it back to false. This is the same convention used in the accepted precedent (#28616) and avoids conflicting behavior between subscribers.
Describe the request
We need two separate IsHandled event publishers in codeunit 5940 ServContractManagement, one in CheckServiceItemBlockedForAll and one in CheckItemServiceBlocked.
1: Add an event publisher OnBeforeCheckServiceItemBlockedForAll() to codeunit 5940 ServContractManagement with the following signature:
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckServiceItemBlockedForAll(var ServiceContractLine: Record "Service Contract Line"; var IsHandled: Boolean)
begin
end;
which would be called as follows:
internal procedure CheckServiceItemBlockedForAll(var ServiceContractLine: Record "Service Contract Line")
var
ServiceItem: Record "Service Item";
IsHandled: Boolean; // << isHandled pattern
begin
IsHandled := false; // << isHandled pattern
OnBeforeCheckServiceItemBlockedForAll(ServiceContractLine, IsHandled); // << Call event
if IsHandled then // << isHandled pattern
exit; // << isHandled pattern
if ServiceContractLine."Service Item No." = '' then
exit;
ServiceItem.SetLoadFields(Blocked);
ServiceItem.Get(ServiceContractLine."Service Item No.");
ServiceItem.ErrorIfBlockedForAll();
end;
2: Add an event publisher OnBeforeCheckItemServiceBlocked() to codeunit 5940 ServContractManagement with the following signature:
[IntegrationEvent(false, false)]
local procedure OnBeforeCheckItemServiceBlocked(var ServiceContractLine: Record "Service Contract Line"; var IsHandled: Boolean)
begin
end;
which would be called as follows:
internal procedure CheckItemServiceBlocked(var ServiceContractLine: Record "Service Contract Line")
var
Item: Record Item;
ItemVariant: Record "Item Variant";
IsHandled: Boolean; // << isHandled pattern
begin
IsHandled := false; // << isHandled pattern
OnBeforeCheckItemServiceBlocked(ServiceContractLine, IsHandled); // << Call event
if IsHandled then // << isHandled pattern
exit; // << isHandled pattern
if ServiceContractLine."Item No." = '' then
exit;
Item.SetLoadFields(Blocked, "Service Blocked");
Item.Get(ServiceContractLine."Item No.");
Item.TestField(Blocked, false);
Item.TestField("Service Blocked", false);
if ServiceContractLine."Variant Code" <> '' then begin
ItemVariant.SetLoadFields(Blocked, "Service Blocked");
ItemVariant.Get(ServiceContractLine."Item No.", ServiceContractLine."Variant Code");
ItemVariant.TestField(Blocked, false);
ItemVariant.TestField("Service Blocked", false);
end;
end;
Why do you need this change?
We want to be able to skip the checks for blocked service items and blocked/deleted items when invoicing service contracts, so that active contracts for items that were later blocked or deleted can still be invoiced.
Alternative events or patterns considered
We checked
OnCreateAllServLinesOnBeforeServContractLineLoopin codeunit 5940, which fires right before these checks are called fromCreateAllServLines, but it has no Skip/IsHandled parameter and cannot preventCheckServiceItemBlockedForAll/CheckItemServiceBlockedfrom running. A Skip-parameter design at the call site was considered as well, but placing the events inside the two procedures themselves keeps each check independently skippable and mirrors the same pattern already approved in issue #28616 (codeunit 5900 ServOrderManagement, OnBeforeCheckItemServiceBlocked) for the equivalent scenario.Why IsHandled is required
Both procedures perform hard-coded
TestField/Getvalidations with no existing extensibility point to bypass them. Customers need to continue invoicing active service contracts for items/service items that were later blocked or deleted, without duplicating or forking codeunit 5940. Since the checks must be skipped entirely rather than supplemented, a regular OnBefore/OnAfter event is not sufficient — only an IsHandled bypass lets the calling process continue instead of raising the error.Performance considerations
Each event is raised once per service contract line during contract invoicing — the same frequency as the existing
OnCreateAllServLinesOnBeforeServContractLineLoopevent in the same loop. No additional loops, database reads, or locking beyond what a subscriber may add on its own (e.g., one Get on a setup table).Data sensitivity review
The events expose
Service Contract Line(var), which is already fully accessible in the calling procedures and their existing events (e.g.,OnCreateAllServLinesOnBeforeServContractLineLoop). No new or additional sensitive data is exposed.Multi-extension interaction/conflict risk
Both parameters follow the IsHandled pattern (initialized to false). If multiple extensions subscribe, each subscriber must check whether
IsHandledis already true before evaluating its own condition, and should never reset it back to false. This is the same convention used in the accepted precedent (#28616) and avoids conflicting behavior between subscribers.Describe the request
We need two separate IsHandled event publishers in codeunit 5940 ServContractManagement, one in CheckServiceItemBlockedForAll and one in CheckItemServiceBlocked.
1: Add an event publisher
OnBeforeCheckServiceItemBlockedForAll()to codeunit 5940 ServContractManagement with the following signature:which would be called as follows:
2: Add an event publisher
OnBeforeCheckItemServiceBlocked()to codeunit 5940 ServContractManagement with the following signature:which would be called as follows: