-
Notifications
You must be signed in to change notification settings - Fork 687
Description
Why do you need this change?
-
Procedure UpdateSalesLinesByFieldNo, our extension must skip the SalesLine.LockTable() call, because the locking behavior causes contention and deadlocks in highΓÇævolume environments.
Alternatives Evaluated:
At the beggining of proceure there is an event OnBeforeUpdateSalesLinesByFieldNo with IsHandled parameter and it could exit the procedure, but then we would have to copy lots of standard code to that event just to avoid one line of the code.Justification for IsHandled:
Avoiding table locks that cause blocking and deadlocks in multiΓÇæuser environments. Running custom update logic that does not require locking. Ensuring smoother concurrency for large sales order volumes. Without an IsHandled pattern, the standard lock always executes and interferes with our custom process.Performance Considerations:
This procedure is triggered when certain header fields change, not continuously.Removing unnecessary locks improves concurrency and reduces blocking.Data Sensitivity Review:
The event exposes only current Sales Header and IsHandled. These records do not contain sensitive data.Multi Extension Interaction:
Extensions that rely on this event must coordinate via dependency declarations. Partners can use EventSubscriberInstance = Manual to control execution order. The pattern is consistent with other core IsHandled events, so developers are familiar with the implications.Example of custom code:
procedure UpdateSalesLinesByFieldNo(ChangedFieldNo: Integer; AskQuestion: Boolean) var "Field": Record "Field"; JobTransferLine: Codeunit "Job Transfer Line"; JobPostLine: Codeunit "Job Post-Line"; Question: Text[250]; IsHandled: Boolean; ShouldConfirmReservationDateConflict: Boolean; begin ... if AskQuestion then begin Question := StrSubstNo(Text031, Field."Field Caption"); if GuiAllowed and not GetHideValidationDialog() then if DIALOG.Confirm(Question, true) then begin ShouldConfirmReservationDateConflict := ChangedFieldNo in [ FieldNo("Shipment Date"), FieldNo("Shipping Agent Code"), FieldNo("Shipping Agent Service Code"), FieldNo("Shipping Time"), FieldNo("Requested Delivery Date"), FieldNo("Promised Delivery Date"), FieldNo("Outbound Whse. Handling Time") ]; OnUpdateSalesLinesByFieldNoOnAfterCalcShouldConfirmReservationDateConflict(Rec, ChangedFieldNo, ShouldConfirmReservationDateConflict); if ShouldConfirmReservationDateConflict then ConfirmReservationDateConflict(); end else exit end; //SalesLine.LockTable(); Custom code if not Rec.Modify() then begin Session.LogMessage('0000G97', SalesHeaderCannotModifyLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinesCategoryLbl); exit; end; SalesLine.Reset(); ... end;
-
Procedure ConfirmCloseUnposted
Standard procedure:
procedure ConfirmCloseUnposted() Result: Boolean var InstructionMgt: Codeunit "Instruction Mgt."; IsHandled: Boolean; begin if SalesLinesExist() then begin IsHandled := false; OnConfirmCloseUnpostedOnSalesLinesExist(Rec, Result, IsHandled); if IsHandled then exit(Result); if InstructionMgt.IsUnpostedEnabledForRecord(Rec) then exit(InstructionMgt.ShowConfirm(DocumentNotPostedClosePageQst, InstructionMgt.QueryPostOnCloseCode())); end; exit(true) end;
Customized procedure:
procedure ConfirmCloseUnposted() Result: Boolean var InstructionMgt: Codeunit "Instruction Mgt."; IsHandled: Boolean; begin //Custom removed code exit(true) end;
Alternatives Evaluated:
We can not use OnConfirmCloseUnpostedOnSalesLinesExist because procedure SalesLinesExist would be already executed. The procedure it self has event OnBeforeSalesLinesExist where we could exit it, but this procedure is global and used in several places. We need new event publisher at the beginning of ConfirmCloseUnposted before checking SalesLinesExist. The publisher should contain these parameters Rec, Result, IsHandled or publisher with only Rec parameter would be sufficient for us, we could reimplement the rest using Single Instance codeunit.Justification for IsHandled:
Avoid triggering procedure SalesLinesExist and setting filters to globalvariable.Performance Considerations:
This procedure is triggered on few pages when they are closed.Data Sensitivity Review:
The event exposes only current Sales Header, Result, IsHandled. These records do not contain sensitive data.Multi Extension Interaction:
Extensions that rely on this event must coordinate via dependency declarations. Partners can use EventSubscriberInstance = Manual to control execution order. The pattern is consistent with other core IsHandled events, so developers are familiar with the implications.
Describe the request
-
Procedure UpdateSalesLinesByFieldNo
procedure UpdateSalesLinesByFieldNo(ChangedFieldNo: Integer; AskQuestion: Boolean) var "Field": Record "Field"; JobTransferLine: Codeunit "Job Transfer Line"; JobPostLine: Codeunit "Job Post-Line"; Question: Text[250]; IsHandled: Boolean; ShouldConfirmReservationDateConflict: Boolean; begin ... if AskQuestion then begin Question := StrSubstNo(Text031, Field."Field Caption"); if GuiAllowed and not GetHideValidationDialog() then if DIALOG.Confirm(Question, true) then begin ShouldConfirmReservationDateConflict := ChangedFieldNo in [ FieldNo("Shipment Date"), FieldNo("Shipping Agent Code"), FieldNo("Shipping Agent Service Code"), FieldNo("Shipping Time"), FieldNo("Requested Delivery Date"), FieldNo("Promised Delivery Date"), FieldNo("Outbound Whse. Handling Time") ]; OnUpdateSalesLinesByFieldNoOnAfterCalcShouldConfirmReservationDateConflict(Rec, ChangedFieldNo, ShouldConfirmReservationDateConflict); if ShouldConfirmReservationDateConflict then ConfirmReservationDateConflict(); end else exit end; OnBeforeSalesLineByFieldNoLock(Rec, Ishandled); //New Event if not Ishandled then SalesLine.LockTable(); if not Rec.Modify() then begin Session.LogMessage('0000G97', SalesHeaderCannotModifyLbl, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', SalesLinesCategoryLbl); exit; end; SalesLine.Reset(); ... end; [IntegrationEvent(false, false)] local procedure OnBeforeSalesLineByFieldNoLock(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean) begin end;
-
Procedure ConfirmCloseUnposted
procedure ConfirmCloseUnposted() Result: Boolean var InstructionMgt: Codeunit "Instruction Mgt."; IsHandled: Boolean; begin IsHandled := false; OnBeforeConfirmCloseUnposted(Rec, Result, IsHandled); //New Event if IsHandled then exit(Result); if SalesLinesExist() then begin IsHandled := false; OnConfirmCloseUnpostedOnSalesLinesExist(Rec, Result, IsHandled); if IsHandled then exit(Result); if InstructionMgt.IsUnpostedEnabledForRecord(Rec) then exit(InstructionMgt.ShowConfirm(DocumentNotPostedClosePageQst, InstructionMgt.QueryPostOnCloseCode())); end; exit(true) end; [IntegrationEvent(false, false)] local procedure OnBeforeConfirmCloseUnposted(var SalesHeader: Record "Sales Header"; var Result: Boolean; var IsHandled: Boolean) begin end; OR procedure ConfirmCloseUnposted() Result: Boolean var InstructionMgt: Codeunit "Instruction Mgt."; IsHandled: Boolean; begin OnBeforeConfirmCloseUnposted(Rec); //New Event if SalesLinesExist() then begin IsHandled := false; OnConfirmCloseUnpostedOnSalesLinesExist(Rec, Result, IsHandled); if IsHandled then exit(Result); if InstructionMgt.IsUnpostedEnabledForRecord(Rec) then exit(InstructionMgt.ShowConfirm(DocumentNotPostedClosePageQst, InstructionMgt.QueryPostOnCloseCode())); end; exit(true) end; [IntegrationEvent(false, false)] local procedure OnBeforeConfirmCloseUnposted(var SalesHeader: Record "Sales Header") begin end;
Internal work item: AB#619099