web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Small and medium business | Business Central, N...
Suggested answer

FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes

(7) ShareShare
ReportReport
Posted on by 27

I have an AL project where I am calculating a customer's sales credit limit. On the Customer Card, there is a field called Sales Credit Limit, which calculates the total amount including VAT for Released and Open orders for that customer, based on a boolean flag in Sales & Receivables Setup. This calculation works correctly. On the Sales Header, I created a FlowField that looks up the Sales Credit Limit from the corresponding customer. The issue is that when I update the Sales Lines (insert, modify, or delete), the Sales Credit Limit on the Customer Card updates correctly, but the FlowField on the Sales Header does not update in real-time. It only reflects the correct value after performing UI actions like refreshing the page. I have tried approaches such as CurrPage.Update(), Rec.CalculateFields(), and other common FlowField refresh techniques, but none of them work. How can I ensure that the FlowField on the Sales Header updates dynamically at runtime when Sales Lines are modified, without requiring a page refresh or other manual actions?

I have the same question (0)
  • Suggested answer
    Gregory Mavrogeorgis Profile Picture
    600 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    You’re doing the right thing with the FlowField on the Sales Header, but BC only recalculates FlowFields when the record is redrawn. Updating Sales Lines doesn’t automatically tell the Header to refresh—so you see the right number on the Customer Card, but the Header hangs onto an old, cached value until you poke the UI.
    The quick fix 
    1. Let the lines notify the header.
      On the parent page, set the Lines part to:

     
    1. Ask the lines page to refresh after important edits.
      In the Sales Lines subpage (extension), call CurrPage.Update(false); in the triggers that change totals (Quantity, Unit Price, Line Discount %, VAT, etc.):
    1. Make sure the header actually recalculates the FlowField when drawn.
      If you’re just showing it on the page, set the control’s SourceExpr to the FlowField and BC will auto-calc on redraw.
      If you use the value in code, also do:


    Why the usual tricks didn’t help
    • Calling CurrPage.Update() on the header doesn’t run when you edit lines—the header doesn’t know anything changed. The missing link is UpdatePropagation = Both plus CurrPage.Update(false) from the subpage.
    • Rec.CalcFields() works only at the moment you call it. If you call it once and then change lines later, the cached value won’t change until the header redraws or you call it again.
    if you find helpful please mark it as verified answer
  • Suggested answer
    Aman Kakkar Profile Picture
    1,115 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    Hi,
     
    It looks like you’ve already tried most common approaches. The reason the FlowField on the header doesn’t update automatically is that the header isn’t aware of changes happening at the line level.
     
    There are three main ways to achieve real-time updates:
    • The approach mentioned by  works just fine, I just tried it. The missing part is to use the "UpdatePropagation = Both;" property in your subform.

      Other ways:
    • Use a dedicated field on the Sales Header: 

      Maintain a standard (normal) field on the header and update it through triggers on the Sales Lines (Insert/Modify/Delete). This is the most reliable method for UI-level real-time updates.
       
    • Keep using a FlowField: 

      If you prefer to stick with a FlowField, consider adding the total field in a “card-like part” of the lines subpage, similar to how standard Sales Lines display totals. You can then update it on OnAfterGetRecord and OnValidate triggers to reflect changes for all lines dynamically. 

     

    Do mark it as Verified if it helps, thanks.

    Aman K

  • Suggested answer
    Suresh Kulla Profile Picture
    50,237 Super User 2025 Season 2 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    The standard sales order subform already has UpdatePropagation set to Both, so you don't need to modify it, as mentioned in other posts. One thing to note is where did you add the CurrPage.Update: What field values reflect the flowfield values when you move from one line to another? Does it update?
  • Sahan Hasitha Profile Picture
    2,674 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    hi
    The reason the FlowField on the Sales Header does not update in real time is that FlowFields in Business Central are virtual and only recalculate when explicitly refreshed or when the record is reread from the database. Although the Customer’s Sales Credit Limit recalculates correctly when Sales Lines are modified, the FlowField on the Sales Header does not automatically refresh because it depends on the Customer’s FlowField value, which is not event-driven. To resolve this, you can replace the FlowField with a calculated variable on the Sales Header page that recalculates each time the record is retrieved using the OnAfterGetRecord() trigger. This ensures the value updates dynamically as the user works. Alternatively, if the value is required for business logic or reporting, you can create a physical field in the Sales Header table and update it via event subscribers that trigger on Sales Line insert, modify, or delete events. This approach guarantees that the Sales Credit Limit value remains synchronized in real time without requiring the user to manually refresh the page.
  • Pallavi Phade Profile Picture
    2,658 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
     
    I agree with Below posts , Kindly use below property , it updates the header totals . 
     
     
    Attaching , MS Document Link for Reference 
     
     
    Regards
    Pallavi Phade
  • Suggested answer
    YUN ZHU Profile Picture
    93,874 Super User 2025 Season 2 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    I remember this problem always exists. You need to reopen the page or press F5 to solve it. You can submit this idea to Microsoft.
    Missing a feature? Post or vote for ideas on: aka.ms/BCIdeas
     
    Thanks.
    ZHU
  • Suggested answer
    Rishabh Kanaskar Profile Picture
    5,474 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    Hi,
     
    FlowFields don’t update in real time, they recalc only when read. That’s why the Customer updates but your Sales Header FlowField doesn’t.
    Options:
    > Use events on Sales Line (insert/modify/delete) to force recalc or update the Sales Header.
    > Replace the FlowField with a normal field and update it through events.
    > Use SetAutoCalcFields when fetching the record, but it still requires a new read.
     
    You can’t make a FlowField auto-refresh on screen; you need event-driven updates or a stored field.
     
    Thanks
    Rishabh
     
  • Suggested answer
    RockwithNav Profile Picture
    8,419 Super User 2025 Season 2 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    I didn't remember exactly but I was in the same situation few years back, see if updatepropagation property helps you or else get rid of the flowfield and code the value you want.
  • TM-02091452-0 Profile Picture
    27 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes

    @RockwithNav @Rishabh Kanaskar @YUN ZHU @Pallavi Phade @Sahan Hasitha @Suresh Kulla @Aman Kakkar @Gregory Mavrogeorgis

    Thank you all for taking the time to respond to my question — I really appreciate your input. Unfortunately, the issue couldn’t be resolved purely through an AL-based approach. I tried several methods, including adding code in the OnAfterValidate triggers of fields like Quantity, Unit Price, and Line Discount, but none provided the desired outcome.

    Since using a normal field would require modifying the Sales Header frequently, I decided to implement a Control Add-in instead. The add-in refreshes the Sales Order Subform page based on specific conditions at defined time intervals. There’s a slight visible delay, but overall, it gets the job done.

    However, my senior wasn’t fully confident in this approach since he hasn’t used a control add-in for such a purpose before. For now, the client has been advised to proceed with manual refresh.

    Below are the Control Add-in code files — I believe this approach should work fine even in production, but I’d love to hear any suggestions or feedback you might have.

     
     
     
    var isReady = false;
    var isPolling = false;
    var pollIntervalMs = 1000;
    var consecutiveErrors = 0;
    var maxErrors = 5;
     
    try {
        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('OnControlAddinReady', []);
        isReady = true;
        console.log('AutoRefresh control add-in ready');
    } catch (error) {
        console.error('Control add-in initialization error:', error);
    }
     
    function StartSmartPolling(intervalMs) {
        if (isPolling) {
            console.log('Polling already running');
            return;
        }
       
        pollIntervalMs = intervalMs;
        isPolling = true;
        consecutiveErrors = 0;
       
        console.log('Smart polling started with interval: ' + intervalMs + 'ms');
       
       
        scheduleNextPoll();
    }
     
    function scheduleNextPoll() {
        if (!isPolling || !isReady) {
            return;
        }
       
       
        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod(
            'OnCheckForChanges',
            [],
            false,
            function() {
               
                consecutiveErrors = 0;
               
                if (isPolling) {
                   
                    setTimeout(function() {
                        scheduleNextPoll();
                    }, pollIntervalMs);
                }
            },
            function(error) {
               
                console.error('Polling error:', error);
                consecutiveErrors++;
               
               
                if (consecutiveErrors >= maxErrors) {
                    console.error('Max consecutive errors reached (' + maxErrors + '), stopping polling');
                    StopSmartPolling();
                    return;
                }
               
               
                if (isPolling) {
                    var backoffDelay = pollIntervalMs * Math.pow(2, Math.min(consecutiveErrors, 3));
                    console.log('Retrying in ' + backoffDelay + 'ms (attempt ' + consecutiveErrors + ')');
                    setTimeout(function() {
                        scheduleNextPoll();
                    }, backoffDelay);
                }
            }
        );
    }
     
    function StopSmartPolling() {
        isPolling = false;
        consecutiveErrors = 0;
        console.log('Smart polling stopped');
    }
     
    window.addEventListener('beforeunload', function() {
        StopSmartPolling();
    });
     
     
    controladdin AutoRefreshAddin
    {
        RequestedHeight = 0;
        RequestedWidth = 0;
        MinimumHeight = 0;
        MinimumWidth = 0;
        VerticalStretch = false;
        VerticalShrink = false;
        HorizontalStretch = false;
        HorizontalShrink = false;
     
        Scripts = 'src/Controladdin/AutoRefresh.js';
     
        event OnControlAddinReady();
        //event OnRefreshRequired();
        event OnCheckForChanges();
        procedure StartSmartPolling(intervalMs: Integer);
        procedure StopSmartPolling();
        //procedure TriggerRefresh();
    }
     
     
    pageextension 50211 "Sales Order Subform Ext" extends "Sales Order Subform"
    {
        layout
        {
           
            addafter(Control1)  
            {
     
                usercontrol(RefreshControl; AutoRefreshAddin)
                {
                    ApplicationArea = All;
     
                    // trigger OnRefreshRequired()
                    // begin
                    //     CurrPage.Update(false);                  
                    // end;
                    trigger OnControlAddinReady()
                    var
                        Customer: Record Customer;
                        SalesHeader: Record "Sales Header";
                    begin
                        if SalesHeader.Get(Rec."Document Type", Rec."Document No.") then begin
                            Customer.SetLoadFields("Credit Limit Check");
                            if Customer.Get(SalesHeader."Sell-to Customer No.") then
                                LastCreditLimitValue := Customer."Credit Limit Check";
                        end;
     
                        CurrPage.RefreshControl.StartSmartPolling(1000);
                    end;
     
                    trigger OnCheckForChanges()
                    var
     
                   
                        Customer: Record Customer;
                        SalesHeader: Record "Sales Header";
                        CurrentValueOnCustomer: Decimal;
                    begin
                       
                        SalesHeader.Get(Rec."Document Type"::Order, Rec."Document No.");                    
                        if Customer.Get(SalesHeader."Sell-to Customer No.") then
                        begin
                            Customer.SetLoadFields("Credit Limit Check");
                            CurrentValueOnCustomer := Customer."Credit Limit Check"
                        end                        
                        else
                            CurrentValueOnCustomer := 0;
                       
                       
                        if CurrentValueOnCustomer <> LastCreditLimitValue then begin
                            CurrPage.Update(false);
                            LastCreditLimitValue := CurrentValueOnCustomer;
                        end;
                    end;                
                }
            }
           
        }
     
        trigger OnClosePage()
        begin
            CurrPage.RefreshControl.StopSmartPolling();
        end;
     
        var
            LastCreditLimitValue: Decimal;
    }
     
  • Suggested answer
    Nimsara Jayathilaka. Profile Picture
    4,826 on at
    FlowField on Sales Header Not Updating in Real-Time After Sales Line Changes
    // 1. Sales Header Table Extension
    tableextension 50100 "Sales Header Ext" extends "Sales Header"
    {
        fields
        {
            field(50100; "Customer Credit Limit"; Decimal)
            {
                FieldClass = FlowField;
                CalcFormula = lookup(Customer."Credit Limit (LCY)" where("No." = field("Sell-to Customer No.")));
                Editable = false;
            }
        }
    
        // Method to refresh the FlowField
        procedure RefreshCustomerCreditLimit()
        begin
            Rec.CalcFields("Customer Credit Limit");
        end;
    }
    
    // 2. Sales Line Table Extension - Add triggers
    tableextension 50101 "Sales Line Ext" extends "Sales Line"
    {
        trigger OnAfterInsert()
        begin
            RefreshSalesHeaderCreditLimit();
        end;
    
        trigger OnAfterModify()
        begin
            RefreshSalesHeaderCreditLimit();
        end;
    
        trigger OnAfterDelete()
        begin
            RefreshSalesHeaderCreditLimit();
        end;
    
        local procedure RefreshSalesHeaderCreditLimit()
        var
            SalesHeader: Record "Sales Header";
        begin
            if SalesHeader.Get(Rec."Document Type", Rec."Document No.") then begin
                SalesHeader.CalcFields("Customer Credit Limit");
                SalesHeader.Modify(); // This triggers the OnAfterModify event
            end;
        end;
    }
    
    // 3. Sales Order Subform Page Extension
    pageextension 50100 "Sales Order Subform Ext" extends "Sales Order Subform"
    {
        trigger OnAfterGetCurrRecord()
        begin
            UpdateSalesHeaderCreditLimit();
        end;
    
        trigger OnInsertRecord(BelowxRec: Boolean): Boolean
        begin
            UpdateSalesHeaderCreditLimit();
        end;
    
        trigger OnModifyRecord(): Boolean
        begin
            UpdateSalesHeaderCreditLimit();
        end;
    
        trigger OnDeleteRecord(): Boolean
        begin
            UpdateSalesHeaderCreditLimit();
        end;
    
        local procedure UpdateSalesHeaderCreditLimit()
        var
            SalesHeader: Record "Sales Header";
        begin
            if SalesHeader.Get(Rec."Document Type", Rec."Document No.") then begin
                SalesHeader.CalcFields("Customer Credit Limit");
                CurrPage.Update(false); // Update without validation
            end;
        end;
    }
    
    // 4. Sales Order Page Extension
    pageextension 50101 "Sales Order Ext" extends "Sales Order"
    {
        layout
        {
            addafter("Sell-to Customer No.")
            {
                field("Customer Credit Limit"; Rec."Customer Credit Limit")
                {
                    ApplicationArea = All;
                    Caption = 'Customer Credit Limit';
                    Editable = false;
                    ToolTip = 'Shows the current credit limit for the customer including VAT.';
                }
            }
        }
    
        // Subscribe to Customer changes
        trigger OnAfterGetCurrRecord()
        begin
            Rec.CalcFields("Customer Credit Limit");
        end;
    }
    
    // 5. ALTERNATIVE APPROACH: Using Events (More robust)
    codeunit 50100 "Sales Credit Limit Handler"
    {
        [EventSubscriber(ObjectType::Table, Database::"Sales Line", 'OnAfterInsertEvent', '', false, false)]
        local procedure OnAfterInsertSalesLine(var Rec: Record "Sales Line")
        begin
            UpdateSalesHeaderCreditLimit(Rec);
        end;
    
        [EventSubscriber(ObjectType::Table, Database::"Sales Line", 'OnAfterModifyEvent', '', false, false)]
        local procedure OnAfterModifySalesLine(var Rec: Record "Sales Line")
        begin
            UpdateSalesHeaderCreditLimit(Rec);
        end;
    
        [EventSubscriber(ObjectType::Table, Database::"Sales Line", 'OnAfterDeleteEvent', '', false, false)]
        local procedure OnAfterDeleteSalesLine(var Rec: Record "Sales Line")
        begin
            UpdateSalesHeaderCreditLimit(Rec);
        end;
    
        local procedure UpdateSalesHeaderCreditLimit(var SalesLine: Record "Sales Line")
        var
            SalesHeader: Record "Sales Header";
            Customer: Record Customer;
        begin
            // First, ensure the customer's credit limit is recalculated
            if Customer.Get(SalesLine."Sell-to Customer No.") then begin
                Customer.CalcFields("Credit Limit (LCY)"); // Assuming this is your FlowField
            end;
    
            // Then update the sales header
            if SalesHeader.Get(SalesLine."Document Type", SalesLine."Document No.") then begin
                SalesHeader.CalcFields("Customer Credit Limit");
                // Optionally trigger a page update through SystemId
                SalesHeader.Modify(false);
            end;
        end;
    
        // Optional: Subscribe to Customer changes
        [EventSubscriber(ObjectType::Page, Page::"Sales Order", 'OnAfterGetCurrRecordEvent', '', false, false)]
        local procedure OnAfterGetCurrRecordSalesOrder(var Rec: Record "Sales Header")
        begin
            Rec.CalcFields("Customer Credit Limit");
        end;
    }
     

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Pallavi Phade – Community Spotlight

We are honored to recognize Pallavi Phade as our Community Spotlight honoree for…

Leaderboard > Small and medium business | Business Central, NAV, RMS

#1
OussamaSabbouh Profile Picture

OussamaSabbouh 2,225

#2
Sumit Singh Profile Picture

Sumit Singh 2,123

#3
YUN ZHU Profile Picture

YUN ZHU 1,813 Super User 2025 Season 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans