Page 104 Account Schedule, source in 29

Source29

src/Layers/W1/BaseApp/Finance/FinancialReports/AccountSchedule.Page.al641 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Finance.FinancialReports;
using System.Environment;
using System.Environment.Configuration;
using System.Integration;
using System.Integration.Excel;
using System.Utilities;

/// <summary>
/// Account schedule line definition page for creating and managing financial report row structures.
/// Provides comprehensive account schedule line configuration with totaling, formulas, and dimensional analysis.
/// </summary>
/// <remarks>
/// Primary interface for defining account schedule lines with calculation logic, dimension filters, and display options.
/// Integrates with column layouts for complete financial reporting matrix. Supports G/L account, cost type, and cash flow totaling.
/// Extensible via page extensions for custom account schedule functionality and additional calculation types.
/// </remarks>
page 104 "Account Schedule"
{
    AboutTitle = 'About (Financial Report) Row Definition';
    AboutText = 'A row definition in financial reports provide a place for calculations that can''t be made directly in the chart of accounts. For example, you can create subtotals for groups of accounts and then include that total in other totals. You can also calculate intermediate steps that aren''t shown in the final report.';
    AutoSplitKey = true;
    AnalysisModeEnabled = false;
    Caption = '(Financial Report) Row Definition';
    DataCaptionFields = "Schedule Name";
    MultipleNewLines = true;
    PageType = Worksheet;
    SourceTable = "Acc. Schedule Line";
    RefreshOnActivate = true;
    UsageCategory = None;

    layout
    {
        area(content)
        {
            group(General)
            {
                ShowCaption = false;
                Visible = not HeaderHidden;
                field(CurrentSchedName; CurrentSchedName)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Name';
                    ToolTip = 'Specifies the unique name (code) of the financial report row definition.';

                    trigger OnValidate()
                    var
                        AccScheduleName: Record "Acc. Schedule Name";
                        ConfirmMgt: Codeunit "Confirm Management";
                        OldName: Code[10];
                        RenameQst: Label 'Your change might update related records, which can take a while. Do you want to continue?';
                    begin
                        Rec.FilterGroup(2);
                        if Rec.GetFilter("Schedule Name") <> '' then
                            OldName := Rec.GetRangeMin("Schedule Name");
                        Rec.FilterGroup(0);
                        if (OldName = CurrentSchedName) or (OldName = '') then
                            Error('');
                        if not AccScheduleName.Get(OldName) then
                            Error('');
                        if not ConfirmMgt.GetResponse(RenameQst) then
                            Error('');
                        CurrPage.SaveRecord();
                        AccScheduleName.Rename(CurrentSchedName);
                        CurrentSchedName := AccScheduleName.Name;
                        AccSchedManagement.SetName(CurrentSchedName, Rec);
                        if Rec.FindFirst() then
                            CurrPage.Update(false)
                        else begin
                            Clear(Rec);
                            Rec.Init();
                        end;
                    end;
                }
                field(CurrentDescription; CurrentDescription)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Description';
                    ToolTip = 'Specifies the description of row definition. The description is not shown on the final report but is used to provide more context when using the definition.';

                    trigger OnValidate()
                    var
                        AccScheduleName: Record "Acc. Schedule Name";
                    begin
                        AccScheduleName.Get(CurrentSchedName);
                        AccScheduleName.Description := CurrentDescription;
                        AccScheduleName.Modify();
                    end;
                }
                field(DefinitionStatus; DefinitionStatus)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Status';
                    TableRelation = "Financial Report Status";
                    ToolTip = 'Specifies the status code for the row definition. The status code helps you organize the lifecycle of your row definitions.';

                    trigger OnValidate()
                    var
                        AccScheduleName: Record "Acc. Schedule Name";
                    begin
                        AccScheduleName.Get(CurrentSchedName);
                        AccScheduleName.Status := DefinitionStatus;
                        AccScheduleName.Modify();
                    end;
                }
                field(InternalDescription; InternalDescription)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Internal Description';
                    MultiLine = true;
                    ToolTip = 'Specifies the internal description of row definition. The internal description is not shown on the final report but is used to provide more context when using the definition.';

                    trigger OnValidate()
                    var
                        AccScheduleName: Record "Acc. Schedule Name";
                    begin
                        AccScheduleName.Get(CurrentSchedName);
                        AccScheduleName."Internal Description" := InternalDescription;
                        AccScheduleName.Modify();
                    end;
                }
            }
            repeater(Control1)
            {
                IndentationColumn = Rec.Indentation;
                IndentationControls = Description;
                ShowCaption = false;
                field("Row No."; Rec."Row No.")
                {
                    ApplicationArea = Basic, Suite;
                }
                field(Description; Rec.Description)
                {
                    ApplicationArea = Basic, Suite;
                    Style = Strong;
                    StyleExpr = Rec.Bold;
                }
                field("Totaling Type"; Rec."Totaling Type")
                {
                    ApplicationArea = Basic, Suite;
                    ToolTip = 'Specifies the totaling type for the financial report line. The type determines which accounts within the totaling interval you specify in the Totaling field will be totaled. ';

                    trigger OnValidate()
                    begin
                        UpdateAccountFactbox();
                    end;
                }
                field(Totaling; TotalingDisplayed)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Totaling';
                    ToolTip = 'Specifies an account interval or a list of account numbers. The entries of the account will be totaled to give a total balance. How entries are totaled depends on the value in the Account Type field.';
                    Lookup = true;

                    trigger OnValidate()
                    begin
                        if Rec."Totaling Type" = Rec."Totaling Type"::"Account Category" then
                            TotalingDisplayed := GetAccountCategoryTotalingToDisplay()
                        else
                            Rec.Validate(Totaling, TotalingDisplayed);

                        UpdateAccountFactbox();
                    end;

                    trigger OnLookup(var Text: Text): Boolean
                    begin
                        Rec.LookupTotaling();
                        if Rec."Totaling Type" = Rec."Totaling Type"::"Account Category" then
                            TotalingDisplayed := GetAccountCategoryTotalingToDisplay()
                        else
                            TotalingDisplayed := Rec.Totaling;

                        UpdateAccountFactbox();
                    end;

                }
                field("Row Type"; Rec."Row Type")
                {
                    ApplicationArea = Basic, Suite;
                }
                field("Amount Type"; Rec."Amount Type")
                {
                    ApplicationArea = Basic, Suite;
                }
                field("Show Opposite Sign"; Rec."Show Opposite Sign")
                {
                    ApplicationArea = Basic, Suite;
                }
                field("Dimension 1 Totaling"; Rec."Dimension 1 Totaling")
                {
                    ApplicationArea = Dimensions;
                    Visible = false;

                    trigger OnLookup(var Text: Text): Boolean
                    begin
                        exit(Rec.LookUpDimFilter(1, Text));
                    end;
                }
                field("Dimension 2 Totaling"; Rec."Dimension 2 Totaling")
                {
                    ApplicationArea = Dimensions;
                    Visible = false;

                    trigger OnLookup(var Text: Text): Boolean
                    begin
                        exit(Rec.LookUpDimFilter(2, Text));
                    end;
                }
                field("Dimension 3 Totaling"; Rec."Dimension 3 Totaling")
                {
                    ApplicationArea = Dimensions;
                    Visible = false;

                    trigger OnLookup(var Text: Text): Boolean
                    begin
                        exit(Rec.LookUpDimFilter(3, Text));
                    end;
                }
                field("Dimension 4 Totaling"; Rec."Dimension 4 Totaling")
                {
                    ApplicationArea = Dimensions;
                    Visible = false;

                    trigger OnLookup(var Text: Text): Boolean
                    begin
                        exit(Rec.LookUpDimFilter(4, Text));
                    end;
                }
                field(Show; Rec.Show)
                {
                    ApplicationArea = Basic, Suite;
                }
                field(Bold; Rec.Bold)
                {
                    ApplicationArea = Basic, Suite;
                }
                field(Italic; Rec.Italic)
                {
                    ApplicationArea = Basic, Suite;
                }
                field(Underline; Rec.Underline)
                {
                    ApplicationArea = Basic, Suite;
                }
                field("Double Underline"; Rec."Double Underline")
                {
                    ApplicationArea = Basic, Suite;
                }
                field("New Page"; Rec."New Page")
                {
                    ApplicationArea = Basic, Suite;
                }
                field(HideCurrencySymbol; Rec."Hide Currency Symbol")
                {
                    ApplicationArea = Basic, Suite;
                    Visible = false;
                }
                field("Internal Description"; Rec."Internal Description")
                {
                    ApplicationArea = Basic, Suite;
                }
            }
        }
        area(factboxes)
        {
            part(TotalingAccountsFactbox; "Totaling Accounts Factbox")
            {
                ApplicationArea = Basic, Suite;
                Caption = 'G/L Accounts';
            }
            systempart(Control1900383207; Links)
            {
                ApplicationArea = RecordLinks;
                Visible = false;
            }
            systempart(Control1905767507; Notes)
            {
                ApplicationArea = Notes;
                Visible = false;
            }
        }
    }

    actions
    {
        area(processing)
        {
            action(Indent)
            {
                ApplicationArea = Basic, Suite;
                Caption = 'Indent';
                Image = Indent;
                Scope = Repeater;
                ToolTip = 'Make this row part of a group of rows. For example, indent rows that itemize a range of accounts, such as types of revenue.';

                trigger OnAction()
                var
                    AccScheduleLine: Record "Acc. Schedule Line";
                begin
                    CurrPage.SetSelectionFilter(AccScheduleLine);
                    if AccScheduleLine.FindSet() then
                        repeat
                            AccScheduleLine.Indent();
                            AccScheduleLine.Modify();
                        until AccScheduleLine.Next() = 0;
                    CurrPage.Update(false);
                end;
            }
            action(Outdent)
            {
                ApplicationArea = Basic, Suite;
                Caption = 'Outdent';
                Image = DecreaseIndent;
                Scope = Repeater;
                ToolTip = 'Move this row out one level.';

                trigger OnAction()
                var
                    AccScheduleLine: Record "Acc. Schedule Line";
                begin
                    CurrPage.SetSelectionFilter(AccScheduleLine);
                    if AccScheduleLine.FindSet() then
                        repeat
                            AccScheduleLine.Outdent();
                            AccScheduleLine.Modify();
                        until AccScheduleLine.Next() = 0;
                    CurrPage.Update(false);
                end;
            }
            action(WhereUsed)
            {
                ApplicationArea = Basic, Suite;
                Caption = 'Where-Used';
                ToolTip = 'View or edit financial reports in which the row definition is used.';
                Image = Track;

                trigger OnAction()
                var
                    FinancialReport: Record "Financial Report";
                begin
                    FinancialReport.SetRange("Financial Report Row Group", CurrentSchedName);
                    Page.Run(0, FinancialReport);
                end;
            }
            action(HideHeader)
            {
                ApplicationArea = Basic, Suite;
                Caption = 'Hide Header';
                Image = ListPage;
                ToolTip = 'Hide the page header.';
                Visible = not HeaderHidden;

                trigger OnAction()
                begin
                    HeaderHidden := true;
                    CurrPage.Update(false);
                end;
            }
            action(ShowHeader)
            {
                ApplicationArea = Basic, Suite;
                Caption = 'Show Header';
                Image = TaskPage;
                ToolTip = 'Show the page header.';
                Visible = HeaderHidden;

                trigger OnAction()
                begin
                    HeaderHidden := false;
                    CurrPage.Update(false);
                end;
            }
            group("F&unctions")
            {
                Caption = 'F&unctions';
                Image = "Action";
                action(InsertGLAccounts)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Insert G/L Accounts';
                    Ellipsis = true;
                    Image = InsertAccount;
                    ToolTip = 'Open the list of general ledger accounts so you can add accounts to the row definition.';

                    trigger OnAction()
                    var
                        AccSchedLine: Record "Acc. Schedule Line";
                    begin
                        CurrPage.Update(true);
                        SetupAccSchedLine(AccSchedLine);
                        AccSchedManagement.InsertGLAccounts(AccSchedLine);
                    end;
                }
                action(InsertCFAccounts)
                {
                    ApplicationArea = Suite;
                    Caption = 'Insert CF Accounts';
                    Ellipsis = true;
                    Image = InsertAccount;
                    ToolTip = 'Mark the cash flow accounts from the chart of cash flow accounts and copy them to row definition lines.';

                    trigger OnAction()
                    var
                        AccSchedLine: Record "Acc. Schedule Line";
                    begin
                        CurrPage.Update(true);
                        SetupAccSchedLine(AccSchedLine);
                        AccSchedManagement.InsertCFAccounts(AccSchedLine);
                    end;
                }
                action(InsertCostTypes)
                {
                    ApplicationArea = CostAccounting;
                    Caption = 'Insert Cost Types';
                    Ellipsis = true;
                    Image = InsertAccount;
                    ToolTip = 'Insert cost types to analyze what the costs are, where the costs come from, and who should bear the costs.';

                    trigger OnAction()
                    var
                        AccSchedLine: Record "Acc. Schedule Line";
                    begin
                        CurrPage.Update(true);
                        SetupAccSchedLine(AccSchedLine);
                        AccSchedManagement.InsertCostTypes(AccSchedLine);
                    end;
                }
            }
            group(Page)
            {
                Caption = 'Page';
                action(EditInExcel)
                {
                    ApplicationArea = Basic, Suite;
                    Caption = 'Edit in Excel';
                    Image = Excel;
                    ToolTip = 'Send the data in the worksheet to an Excel file for analysis or editing.';
                    Visible = IsSaaSExcelAddinEnabled;
                    AccessByPermission = System "Allow Action Export To Excel" = X;

                    trigger OnAction()
                    var
                        EditinExcel: Codeunit "Edit in Excel";
                        EditinExcelFilters: Codeunit "Edit in Excel Filters";
                        ODataUtility: Codeunit "ODataUtility";
                    begin
                        EditinExcelFilters.AddFieldV2(ODataUtility.ExternalizeName(Rec.FieldName(Rec."Schedule Name")), Enum::"Edit in Excel Filter Type"::Equal, CurrentSchedName, Enum::"Edit in Excel Edm Type"::"Edm.String");
                        EditinExcel.EditPageInExcel(Text.CopyStr(CurrPage.Caption, 1, 240), Page::"Account Schedule", EditInExcelFilters, StrSubstNo(ExcelFileNameTxt, CurrentSchedName));
                    end;
                }
            }
        }
        area(Promoted)
        {
            group(Category_Process)
            {
                Caption = 'Process', Comment = 'Generated from the PromotedActionCategories property index 1.';

                actionref(Outdent_Promoted; Outdent) { }
                actionref(Indent_Promoted; Indent) { }
                actionref(WhereUsed_Promoted; WhereUsed) { }
                actionref(HideHeader_Promoted; HideHeader) { }
                actionref(ShowHeader_Promoted; ShowHeader) { }
            }
            group(Category_Category4)
            {
                Caption = 'Insert', Comment = 'Generated from the PromotedActionCategories property index 3.';

                actionref(InsertGLAccounts_Promoted; InsertGLAccounts) { }
                actionref(InsertCostTypes_Promoted; InsertCostTypes) { }
                actionref(InsertCFAccounts_Promoted; InsertCFAccounts) { }
            }
            group(Category_Report)
            {
                Caption = 'Report', Comment = 'Generated from the PromotedActionCategories property index 2.';
            }
        }
    }

    trigger OnAfterGetRecord()
    begin
        FormatLines();
    end;

    trigger OnAfterGetCurrRecord()
    begin
        FormatLines();
        UpdateAccountFactbox();
    end;

    trigger OnOpenPage()
    var
        ClientTypeManagement: Codeunit "Client Type Management";
        FinancialReportMgt: Codeunit "Financial Report Mgt.";
        ServerSetting: Codeunit "Server Setting";
        OriginalSchedName: Code[10];
        CurrentPageCaption: Text;
    begin
        IsSaaSExcelAddinEnabled := ServerSetting.GetIsSaasExcelAddinEnabled();

        if ClientTypeManagement.GetCurrentClientType() = CLIENTTYPE::ODataV4 then
            exit;

        FinancialReportMgt.LaunchEditRowsWarningNotification();
        OriginalSchedName := CurrentSchedName;
        AccSchedManagement.OpenAndCheckSchedule(CurrentSchedName, Rec);
        if CurrentSchedName <> OriginalSchedName then
            CurrentSchedNameOnAfterValidate();

        CurrentPageCaption := AccSchedManagement.GetAccountScheduleCaption(CurrentSchedName);
        if CurrentPageCaption <> '' then
            CurrPage.Caption(CurrentPageCaption);

        GetDescriptions();
    end;

    var
        AccSchedManagement: Codeunit AccSchedManagement;
        CurrentSchedName: Code[10];
        DefinitionStatus: Code[10];
        DimCaptionsInitialized: Boolean;
        IsSaaSExcelAddinEnabled: Boolean;
        CurrentDescription: Text[80];
        InternalDescription: Text[500];
        TotalingDisplayed: Text[250];
        HeaderHidden: Boolean;
        ExcelFileNameTxt: Label 'Row Definition - ScheduleName %1', Comment = '%1 = Schedule Name';

    /// <summary>
    /// Sets the current account schedule name for page context and line filtering.
    /// </summary>
    /// <param name="NewAccSchedName">Account schedule name to set as current context</param>
    procedure SetAccSchedName(NewAccSchedName: Code[10])
    begin
        CurrentSchedName := NewAccSchedName;
    end;

    local procedure CurrentSchedNameOnAfterValidate()
    begin
        CurrPage.SaveRecord();
        AccSchedManagement.SetName(CurrentSchedName, Rec);
        CurrPage.Update(false);
    end;

    local procedure GetDescriptions()
    var
        AccScheduleName: Record "Acc. Schedule Name";
        FinancialReportMgt: Codeunit "Financial Report Mgt.";
    begin
        CurrentDescription := '';
        InternalDescription := '';
        if AccScheduleName.Get(CurrentSchedName) then begin
            DefinitionStatus := AccScheduleName.Status;
            CurrentDescription := AccScheduleName.Description;
            InternalDescription := AccScheduleName."Internal Description";
            FinancialReportMgt.CheckStatus(AccScheduleName.TableCaption(), AccScheduleName.Status);
        end;
    end;

    local procedure FormatLines()
    begin
        if not DimCaptionsInitialized then
            DimCaptionsInitialized := true;
        if Rec."Totaling Type" = Rec."Totaling Type"::"Account Category" then
            TotalingDisplayed := GetAccountCategoryTotalingToDisplay()
        else
            TotalingDisplayed := Rec.Totaling;
    end;

    local procedure UpdateAccountFactbox()
    begin
        if (Rec.Totaling <> '') and (Rec."Totaling Type" in [Rec."Totaling Type"::"Posting Accounts", Rec."Totaling Type"::"Total Accounts"]) then
            CurrPage.TotalingAccountsFactbox.Page.SetTotalingFilter(Rec.Totaling)
        else
            CurrPage.TotalingAccountsFactbox.Page.SetTotalingFilter('=''''');
    end;

    /// <summary>
    /// Configures account schedule line with current page context and handles line number assignment.
    /// Ensures proper line numbering and schedule name association for new and modified lines.
    /// </summary>
    /// <param name="AccSchedLine">Account schedule line to configure with page context</param>
    procedure SetupAccSchedLine(var AccSchedLine: Record "Acc. Schedule Line")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeSetupAccSchedLine(Rec, xRec, AccSchedLine, CurrentSchedName, IsHandled);
        if IsHandled then
            exit;

        AccSchedLine := Rec;
        if Rec."Line No." = 0 then begin
            AccSchedLine := xRec;
            AccSchedLine.SetRange("Schedule Name", CurrentSchedName);
            if AccSchedLine.Next() = 0 then
                AccSchedLine."Line No." := xRec."Line No." + 10000
            else begin
                if AccSchedLine.FindLast() then
                    AccSchedLine."Line No." += 10000;
                AccSchedLine.SetRange("Schedule Name");
            end;
        end;
    end;

    /// <summary>
    /// Retrieves display text for account category totaling when totaling type is account category.
    /// </summary>
    /// <returns>Formatted account category totaling text for display purposes</returns>
    procedure GetAccountCategoryTotalingToDisplay(): Text[250]
    begin
        exit(AccSchedManagement.GLAccCategoryText(Rec));
    end;

    /// <summary>
    /// Returns the current account schedule name set in the page context.
    /// </summary>
    /// <returns>Current account schedule name code</returns>
    procedure GetAccSchedName(): Code[10]
    begin
        exit(CurrentSchedName);
    end;

    /// <summary>
    /// Integration event raised before setting up account schedule line configuration.
    /// </summary>
    /// <param name="RecAccScheduleLine">Current account schedule line record</param>
    /// <param name="xRecAccScheduleLine">Previous version of account schedule line record</param>
    /// <param name="AccScheduleLine">Account schedule line being configured</param>
    /// <param name="CurrentSchedName">Current account schedule name context</param>
    /// <param name="IsHandled">Set to true to override standard setup logic</param>
    [IntegrationEvent(false, false)]
    local procedure OnBeforeSetupAccSchedLine(var RecAccScheduleLine: Record "Acc. Schedule Line"; var xRecAccScheduleLine: Record "Acc. Schedule Line"; var AccScheduleLine: Record "Acc. Schedule Line"; CurrentSchedName: Code[20]; var IsHandled: Boolean)
    begin
    end;
}