Skip to content

[Event Requests] - table 36 "Sales Header" #29622

@exnihiloo

Description

@exnihiloo

Why do you need this change?

  1. Field 5700 "Responsibility Center", OnValidate trigger. Our extension requires replacing the standard behavior that updates location, warehouse handling time, ship‑to address, dimensions, and recreates sales lines. Instead, we must run our own logic: To avoid modifying base code, we need an IsHandled pattern or publisher event before the standard update logic executes.

    Alternatives Evaluated:
    For this solution it's possible to reimplement but we will have to use SingleInstance codeunit, OnBeforeValidation trigger and 5 events OnBeforeUpdateLocationCode, OnBeforeUpdateOutboundWhseHandlingTime, OnBeforeUpdateShipToAddress, OnBeforeCreateDimFromDefaultDim, OnBeforeRecreateSalesLinesHandler, In that case it would be better to have one event on the validation trigger to exit the code.

    Justification for IsHandled:
    Our business logic must replace the standard behavior, not extend it.
    Specifically, we must: Prevent automatic updates to location, warehouse handling time, and ship‑to address. Prevent dimension recreation. Prevent sales line recreation. Run our own UpdateSalesLines() logic instead. Without an IsHandled pattern, the standard logic executes and produces incorrect or duplicate updates.

    Performance Considerations:
    The Responsibility Center field is validated infrequently - typically only when users manually change it on a sales document.

    Data Sensitivity Review:
    No sensitive or personal data is exposed. The change affects only internal business logic related to sales document updates.

    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:

    trigger OnValidate()
    begin
       TestStatusOpen();
       if not UserSetupMgt.CheckRespCenter(0, "Responsibility Center") then
           Error(
             Text027,
             RespCenter.TableCaption(), UserSetupMgt.GetSalesFilter());
    
       //Custom code begin <<
    
       //UpdateLocationCode('');
       //UpdateOutboundWhseHandlingTime();
       //UpdateShipToAddress();
    
       //CreateDimFromDefaultDim(Rec.FieldNo("Responsibility Center"));
    
       //if xRec."Responsibility Center" <> "Responsibility Center" then begin
       //    RecreateSalesLines(FieldCaption("Responsibility Center"));
       //    "Assigned User ID" := '';
       //end;
    
      if xRec."Responsibility Center" <> "Responsibility Center" then
           UpdateSalesLines(FieldCaption("Responsibility Center"), true);
    
      //Custom code end<<
    end;
    
  2. Proceure RecreateSalesLines, our extension requires prevent table locking because it conflicts with our custom processing and causes unnecessary blocking in high‑volume environments.

    Alternatives Evaluated:
    There are events OnBeforeRecreateSalesLinesHandler, OnRecreateSalesLinesOnBeforeConfirm which could help us but if we would subscribe to these events we will have to copy lots of standard code to prevent table locking. Another event OnBeforeRecreateSalesLines fires after locking logic, so it cannot prevent the locks.

    Justification for IsHandled:
    Our business logic requires: Avoiding table locks that cause contention in multi‑user environments, running custom line recreation logic that does not require locking, preventing deadlocks and performance degradation in high‑volume scenarios. Without an IsHandled pattern, the standard locking logic always executes and interferes with our custom process.

    Data Sensitivity Review:
    No sensitive or personal data is exposed. The change affects only internal business logic related to sales document updates.

    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 RecreateSalesLines(ChangedFieldName: Text[100])
    var
       ...
       IsHandled: Boolean;
    begin
       if not SalesLinesExist() then
           exit;
    
       ...
    
       if Confirmed then begin
           //SalesLine.LockTable(); Custom commented code
           //ItemChargeAssgntSales.LockTable(); Custom commented code
           //ReservEntry.LockTable(); Custom commented code
           Modify();
           OnBeforeRecreateSalesLines(Rec);
           SalesLine.Reset();
    end;
  3. Proceure RecreateSalesLines, our extensions sets SuspendStatusCheck on SalesLine

    Alternatives Evaluated:
    The event OnRecreateSalesLinesOnBeforeTempSalesLineFindSet would be sufficient for us we are just requesting for one additional parameter in it, var SalesLine: Record "Sales Line".

    Data Sensitivity Review:
    No sensitive or personal data is exposed. The change affects only internal business logic related to sales document updates.

    Example of custom code:

    procedure RecreateSalesLines(ChangedFieldName: Text[100])
    var
       ...
    begin
       ...
               OnRecreateSalesLinesOnBeforeSalesLineDeleteAll(Rec, SalesLine, CurrFieldNo, IsHandled);
               if not IsHandled then
                   SalesLine.DeleteAll(true);
    
               SalesLine.Init();
               SalesLine."Line No." := 0;
               OnRecreateSalesLinesOnBeforeTempSalesLineFindSet(TempSalesLine);
               TempSalesLine.FindSet();
               ExtendedTextAdded := false;
               SalesLine.BlockDynamicTracking(true);
               SalesLine.SuspendStatusCheck(true); // Custom code
               repeat
                   RecreateSalesLinesHandleSupplementTypes(TempSalesLine, ExtendedTextAdded, TempItemChargeAssgntSales, TempInteger);
                   RestoreSalesCommentLine(TempSalesCommentLine, TempSalesLine."Line No.", SalesLine."Line No.");
                   ....
    end;

Describe the request

  1. OnValidate trigger field 5700 "Responsibility Center"

    trigger OnValidate()
    var
       IsHandled: Boolean;
    begin
        TestStatusOpen();
        IsHandled := false;
        OnBeforeResponsibilityCenterValidate(Rec, xRec, IsHandled);
        if IsHandled then
           exit;
        if not UserSetupMgt.CheckRespCenter(0, "Responsibility Center") then
            Error(
              Text027,
              RespCenter.TableCaption(), UserSetupMgt.GetSalesFilter());
    
        UpdateLocationCode('');
        UpdateOutboundWhseHandlingTime();
        UpdateShipToAddress();
    
        CreateDimFromDefaultDim(Rec.FieldNo("Responsibility Center"));
    
        if xRec."Responsibility Center" <> "Responsibility Center" then begin
            RecreateSalesLines(FieldCaption("Responsibility Center"));
            "Assigned User ID" := '';
        end;
    end;
    
    [IntegrationEvent(false, false)]
    local procedure OnBeforeResponsibilityCenterValidate(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;
  2. Procedure RecreateSalesLines

    procedure RecreateSalesLines(ChangedFieldName: Text[100])
    var
        ...
        IsHandled: Boolean;
    begin
        if not SalesLinesExist() then
            exit;
    
        ...
    
        if Confirmed then begin
            OnBeforeRecreateSalesLinesLocking(Rec, IsHandled);
            if not IsHandled then begin
              SalesLine.LockTable(); 
              ItemChargeAssgntSales.LockTable(); 
              ReservEntry.LockTable();
            end;
            Modify();
            OnBeforeRecreateSalesLines(Rec);
            SalesLine.Reset();
     end;
    
    [IntegrationEvent(false, false)]
    local procedure OnBeforeRecreateSalesLinesLocking(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    begin
    end;
  3. Procedure RecreateSalesLines

    procedure RecreateSalesLines(ChangedFieldName: Text[100])
    var
       ...
    begin
       ...
               OnRecreateSalesLinesOnBeforeSalesLineDeleteAll(Rec, SalesLine, CurrFieldNo, IsHandled);
               if not IsHandled then
                   SalesLine.DeleteAll(true);
    
               SalesLine.Init();
               SalesLine."Line No." := 0;
               OnRecreateSalesLinesOnBeforeTempSalesLineFindSet(TempSalesLine, SalesLine); //New parameter
               TempSalesLine.FindSet();
               ExtendedTextAdded := false;
               SalesLine.BlockDynamicTracking(true);
               repeat
                   RecreateSalesLinesHandleSupplementTypes(TempSalesLine, ExtendedTextAdded, TempItemChargeAssgntSales, TempInteger);
                   RestoreSalesCommentLine(TempSalesCommentLine, TempSalesLine."Line No.", SalesLine."Line No.");
                   ....
    end;
    
    [IntegrationEvent(false, false)]
    local procedure OnRecreateSalesLinesOnBeforeTempSalesLineFindSet(var TempSalesLine: Record "Sales Line" temporary; var SalesLine: Record "Sales Line")
    begin
    end;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions