Codeunit 8 AccSchedManagement, source in 29
Source29
src/Layers/W1/BaseApp/Finance/FinancialReports/AccSchedManagement.Codeunit.al3488 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 Microsoft.CashFlow.Account;
using Microsoft.CashFlow.Forecast;
using Microsoft.CostAccounting.Account;
using Microsoft.CostAccounting.Budget;
using Microsoft.CostAccounting.Ledger;
using Microsoft.CostAccounting.Setup;
using Microsoft.Finance.Analysis;
using Microsoft.Finance.Currency;
using Microsoft.Finance.Dimension;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Budget;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Foundation.Enums;
using Microsoft.Foundation.Period;
using System.Utilities;
/// <summary>
/// Central engine for account schedule management, calculation, and financial report generation.
/// Handles complex financial calculations including G/L accounts, cash flow forecasts, cost accounting, and budget analysis.
/// </summary>
/// <remarks>
/// Core calculation engine for financial reporting with support for formulas, operators, and multi-dimensional analysis.
/// Integrates with Analysis Views, G/L entries, budget entries, and cash flow forecasts for comprehensive financial analysis.
/// Extensibility: Multiple integration events for custom calculation logic and filter processing.
/// </remarks>
codeunit 8 AccSchedManagement
{
TableNo = "Acc. Schedule Line";
trigger OnRun()
begin
end;
var
#pragma warning disable AA0074
Text000: Label 'DEFAULT';
Text001: Label 'Default Schedule';
Text002: Label 'Default Columns';
Text012: Label 'You have entered an illegal value or a nonexistent row number.';
Text013: Label 'You have entered an illegal value or a nonexistent column number.';
#pragma warning restore AA0074
Text016Err: Label '%1\\ %2 %3 %4.', Locked = true;
Text017Txt: Label 'The error occurred when the program tried to calculate:\';
Text018Txt: Label 'Acc. Sched. Line: Row No. = %1, Line No. = %2, Totaling = %3\', Comment = '%1 = Row No., %2= Line No., %3 = Totaling';
Text019Txt: Label 'Acc. Sched. Column: Column No. = %1, Line No. = %2, Formula = %3', Comment = '%1 = Column No., %2= Line No., %3 = Formula';
AccSchedName: Record "Acc. Schedule Name";
AccountScheduleLine: Record "Acc. Schedule Line";
ColumnLayoutName: Record "Column Layout Name";
TempAccSchedCellValue: Record "Acc. Sched. Cell Value" temporary;
CurrExchRate: Record "Currency Exchange Rate";
GLSetup: Record "General Ledger Setup";
AddRepCurrency: Record Currency;
AnalysisView: Record "Analysis View";
MatrixMgt: Codeunit "Matrix Management";
AccountingPeriodMgt: Codeunit "Accounting Period Mgt.";
AnalysisViewRead: Boolean;
DimPerspectiveRead: Boolean;
StartDate: Date;
EndDate: Date;
FiscalStartDate: Date;
DivisionError: Boolean;
PeriodError: Boolean;
CallingAccSchedLineID: Integer;
CallingColumnLayoutID: Integer;
OldAccSchedLineFilters: Text;
OldColumnLayoutFilters: Text;
OldAccSchedLineName: Code[10];
OldColumnLayoutName: Code[10];
OldCalcAddCurr: Boolean;
GLSetupRead: Boolean;
#pragma warning disable AA0074
#pragma warning disable AA0470
Text021: Label 'Conversion of dimension totaling filter %1 results in a filter that becomes too long.';
#pragma warning restore AA0470
#pragma warning restore AA0074
BasePercentLine: array[50] of Integer;
#pragma warning disable AA0074
#pragma warning disable AA0470
Text022: Label 'You cannot have more than %1 lines with %2 of %3.';
Text023: Label 'Formulas ending with a percent sign require %2 %1 on a line before it.';
Text024: Label 'The %1 %3 on the %2 must equal the %4 %6 on the %5 when any Dimension Totaling is used in any %7.';
#pragma warning restore AA0470
#pragma warning restore AA0074
#pragma warning disable AA0470
ColumnFormulaMsg: Label 'Column formula: %1.';
RowFormulaMsg: Label 'Row formula: %1.';
ColumnFormulaErrorMsg: Label 'Column formula: %1. \Error: %2.';
#pragma warning restore AA0470
ColumnHeaderTxt: Label '%1 (%2)', Comment = '%1 = Column Header, %2 = Date';
QuarterTxt: Label 'Q%1', Comment = '%1 = Quarter number';
WeekTxt: Label 'W%1', Comment = '%1 = Week number';
Recalculate: Boolean;
SystemGeneratedAccSchedQst: Label 'This report definition may be automatically updated by the system, so any changes you make may be lost. Do you want to make a copy?';
PerspectiveDimensionMismatchErr: Label 'The %1 on %2 must be one of the dimension codes specified on the %3 %4.', Comment = '%1 = Perspective Type, %2 = Dimension Perspective Name, %3 = Analysis View, %4 = Analysis View Name';
/// <summary>
/// Opens and initializes account schedule lines for the specified schedule name with proper template validation.
/// Ensures the schedule exists and applies appropriate filters for schedule line processing.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to open and validate</param>
/// <param name="AccSchedLine">Account schedule line record to configure with filters and settings</param>
procedure OpenSchedule(var CurrentSchedName: Code[10]; var AccSchedLine: Record "Acc. Schedule Line")
begin
CheckTemplateAndSetFilter(CurrentSchedName, AccSchedLine);
end;
/// <summary>
/// Opens account schedule with validation and system-generated schedule protection logic.
/// Prompts user to copy system-generated schedules before modification to preserve integrity.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to open and validate</param>
/// <param name="AccSchedLine">Account schedule line record to configure with filters and settings</param>
procedure OpenAndCheckSchedule(var CurrentSchedName: Code[10]; var AccSchedLine: Record "Acc. Schedule Line")
var
AccScheduleName: Record "Acc. Schedule Name";
GeneralLedgerSetup: Record "General Ledger Setup";
CopyAccountSchedule: Report "Copy Account Schedule";
ConfirmManagement: Codeunit "Confirm Management";
begin
CheckTemplateAndSetFilter(CurrentSchedName, AccSchedLine);
if AccSchedLine.IsEmpty() then
exit;
GeneralLedgerSetup.Get();
if CurrentScheduleAlreadyDefinedInGLSetup(CurrentSchedName) then
if ConfirmManagement.GetResponseOrDefault(SystemGeneratedAccSchedQst, true) then begin
AccScheduleName.SetRange(Name, CurrentSchedName);
CopyAccountSchedule.SetTableView(AccScheduleName);
CopyAccountSchedule.RunModal();
CurrentSchedName := CopyAccountSchedule.GetNewAccountScheduleName();
end;
end;
procedure GetAccountScheduleCaption(CurrentSchedName: Code[10]): Text
var
AccScheduleName: Record "Acc. Schedule Name";
begin
if CurrentSchedName <> '' then
if AccScheduleName.Get(CurrentSchedName) and (AccScheduleName.Description <> '') then
exit(StrSubstNo('%1 (%2)', AccScheduleName.Description, AccScheduleName.Name));
exit(CurrentSchedName);
end;
local procedure CurrentScheduleAlreadyDefinedInGLSetup(ScheduleName: Code[10]): Boolean
var
FinancialReport: Record "Financial Report";
GeneralLedgerSetup: Record "General Ledger Setup";
begin
if not GeneralLedgerSetup.Get() then
exit(false);
if GeneralLedgerSetup."Fin. Rep. for Balance Sheet" <> '' then
if FinancialReport.Get(GeneralLedgerSetup."Fin. Rep. for Balance Sheet") then
if (FinancialReport."Financial Report Row Group" = ScheduleName) then
exit(true);
if GeneralLedgerSetup."Fin. Rep. for Cash Flow Stmt" <> '' then
if FinancialReport.Get(GeneralLedgerSetup."Fin. Rep. for Cash Flow Stmt") then
if (FinancialReport."Financial Report Row Group" = ScheduleName) then
exit(true);
if GeneralLedgerSetup."Fin. Rep. for Income Stmt." <> '' then
if FinancialReport.Get(GeneralLedgerSetup."Fin. Rep. for Income Stmt.") then
if (FinancialReport."Financial Report Row Group" = ScheduleName) then
exit(true);
if GeneralLedgerSetup."Fin. Rep. for Retained Earn." <> '' then
if FinancialReport.Get(GeneralLedgerSetup."Fin. Rep. for Retained Earn.") then
if (FinancialReport."Financial Report Row Group" = ScheduleName) then
exit(true);
exit(false);
end;
local procedure CheckTemplateAndSetFilter(var CurrentSchedName: Code[10]; var AccSchedLine: Record "Acc. Schedule Line")
begin
CheckTemplateName(CurrentSchedName);
AccSchedLine.FilterGroup(2);
AccSchedLine.SetRange("Schedule Name", CurrentSchedName);
AccSchedLine.FilterGroup(0);
OnAfterCheckTemplateAndSetFilter(CurrentSchedName, AccSchedLine);
end;
local procedure CheckTemplateName(var CurrentSchedName: Code[10])
var
AccSchedName: Record "Acc. Schedule Name";
begin
if not AccSchedName.Get(CurrentSchedName) then begin
if not AccSchedName.FindFirst() then begin
AccSchedName.Init();
AccSchedName.Name := Text000;
AccSchedName.Description := Text001;
AccSchedName.Insert();
Commit();
end;
CurrentSchedName := AccSchedName.Name;
end;
OnAfterCheckTemplateName(CurrentSchedName);
end;
/// <summary>
/// Validates that the specified account schedule name exists in the database.
/// Raises error if account schedule name is not found.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to validate existence for</param>
procedure CheckName(CurrentSchedName: Code[10])
var
AccSchedName: Record "Acc. Schedule Name";
begin
AccSchedName.Get(CurrentSchedName);
OnAfterCheckName(CurrentSchedName);
end;
/// <summary>
/// Sets the account schedule name filter on account schedule lines for data filtering and processing.
/// Configures account schedule line record to work with the specified schedule.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to set as filter</param>
/// <param name="AccSchedLine">Account schedule line record to configure with the schedule name filter</param>
procedure SetName(CurrentSchedName: Code[10]; var AccSchedLine: Record "Acc. Schedule Line")
begin
AccSchedLine.FilterGroup(2);
AccSchedLine.SetRange("Schedule Name", CurrentSchedName);
AccSchedLine.FilterGroup(0);
if AccSchedLine.Find('-') then;
end;
/// <summary>
/// Opens account schedule name lookup dialog and returns the selected schedule name.
/// Enables interactive selection of account schedules for financial reporting.
/// </summary>
/// <param name="CurrentSchedName">Currently selected account schedule name for initial positioning</param>
/// <param name="EntrdSchedName">Selected account schedule name returned from lookup</param>
/// <returns>True if user selected a schedule name, false if cancelled</returns>
/// <summary>
/// Opens a lookup dialog for account schedule names and returns the selected schedule name.
/// Provides user interface for selecting from available account schedule templates.
/// </summary>
/// <param name="CurrentSchedName">Current account schedule name to initialize lookup selection</param>
/// <param name="EntrdSchedName">Variable to receive the selected account schedule name</param>
/// <returns>True if user selected a schedule name, false if canceled</returns>
procedure LookupName(CurrentSchedName: Code[10]; var EntrdSchedName: Text[10]): Boolean
var
AccSchedName: Record "Acc. Schedule Name";
begin
AccSchedName.Name := CurrentSchedName;
if PAGE.RunModal(0, AccSchedName) <> ACTION::LookupOK then
exit(false);
EntrdSchedName := AccSchedName.Name;
exit(true);
end;
/// <summary>
/// Opens and initializes column layout lines for the specified column layout name with proper template validation.
/// Ensures the column layout exists and applies appropriate filters for column layout processing.
/// </summary>
/// <param name="CurrentColumnName">Column layout name to open and validate</param>
/// <param name="ColumnLayout">Column layout record to configure with filters and settings</param>
procedure OpenColumns(var CurrentColumnName: Code[10]; var ColumnLayout: Record "Column Layout")
begin
CheckColumnTemplateName(CurrentColumnName);
ColumnLayout.FilterGroup(2);
ColumnLayout.SetRange("Column Layout Name", CurrentColumnName);
ColumnLayout.FilterGroup(0);
OnAfterOpenColumns(CurrentColumnName, ColumnLayout);
end;
procedure GetColumnLayoutCaption(CurrentColumnName: Code[10]): Text;
var
ColLayoutName: Record "Column Layout Name";
begin
if CurrentColumnName <> '' then
if ColLayoutName.Get(CurrentColumnName) and (ColLayoutName.Description <> '') then
exit(StrSubstNo('%1 (%2)', ColLayoutName.Description, ColLayoutName.Name));
exit(CurrentColumnName);
end;
local procedure CheckColumnTemplateName(var CurrentColumnName: Code[10])
var
ColumnLayoutName: Record "Column Layout Name";
begin
if not ColumnLayoutName.Get(CurrentColumnName) then begin
if not ColumnLayoutName.FindFirst() then begin
ColumnLayoutName.Init();
ColumnLayoutName.Name := Text000;
ColumnLayoutName.Description := Text002;
ColumnLayoutName.Insert();
Commit();
end;
CurrentColumnName := ColumnLayoutName.Name;
end;
end;
/// <summary>
/// Validates that the specified column layout name exists in the database.
/// Raises error if column layout name is not found.
/// </summary>
/// <param name="CurrentColumnName">Column layout name to validate existence for</param>
procedure CheckColumnName(CurrentColumnName: Code[10])
var
ColumnLayoutName: Record "Column Layout Name";
begin
ColumnLayoutName.Get(CurrentColumnName);
OnAfterCheckColumnName(CurrentColumnName);
end;
/// <summary>
/// Sets the column layout name filter on column layout lines for data filtering and processing.
/// Configures column layout record to work with the specified column layout name.
/// </summary>
/// <param name="CurrentColumnName">Column layout name to set as filter</param>
/// <param name="ColumnLayout">Column layout record to configure with the column layout name filter</param>
procedure SetColumnName(CurrentColumnName: Code[10]; var ColumnLayout: Record "Column Layout")
begin
ColumnLayout.Reset();
ColumnLayout.FilterGroup(2);
ColumnLayout.SetRange("Column Layout Name", CurrentColumnName);
ColumnLayout.FilterGroup(0);
end;
/// <summary>
/// Copies column layout lines to temporary table for processing and manipulation.
/// Enables temporary column layout processing without affecting the original data.
/// </summary>
/// <param name="NewColumnName">Column layout name to copy from</param>
/// <param name="TempColumnLayout">Temporary column layout record to copy data to</param>
procedure CopyColumnsToTemp(NewColumnName: Code[10]; var TempColumnLayout: Record "Column Layout")
var
ColumnLayout: Record "Column Layout";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCopyColumnsToTemp(NewColumnName, TempColumnLayout, IsHandled);
if IsHandled then
exit;
TempColumnLayout.DeleteAll();
ColumnLayout.SetRange("Column Layout Name", NewColumnName);
if ColumnLayout.Find('-') then
repeat
TempColumnLayout := ColumnLayout;
TempColumnLayout.Insert();
OnCopyColumnsToTempOnAfterColumnLayoutInsert(AccSchedName, NewColumnName, ColumnLayout, TempColumnLayout);
until ColumnLayout.Next() = 0;
OnCopyColumnsToTempOnBeforeFind(AccSchedName, NewColumnName, TempColumnLayout);
if TempColumnLayout.Find('-') then;
end;
/// <summary>
/// Opens column layout name lookup window and returns selected column name.
/// </summary>
/// <param name="CurrentColumnName">Current column layout name to use as default selection</param>
/// <param name="EntrdColumnName">Selected column layout name returned from lookup</param>
/// <returns>True if column layout was selected, false if lookup was cancelled</returns>
procedure LookupColumnName(CurrentColumnName: Code[10]; var EntrdColumnName: Text[10]) Result: Boolean
var
ColumnLayoutName: Record "Column Layout Name";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeLookupColumnName(CurrentColumnName, EntrdColumnName, Result, IsHandled);
if IsHandled then
exit(Result);
ColumnLayoutName.Name := CurrentColumnName;
if PAGE.RunModal(0, ColumnLayoutName) <> ACTION::LookupOK then
exit(false);
EntrdColumnName := ColumnLayoutName.Name;
exit(true);
end;
/// <summary>
/// Sets the analysis view read status flag.
/// </summary>
/// <param name="Value">Analysis view read status - true if analysis view data has been read</param>
procedure SetAnalysisViewRead(Value: Boolean)
begin
AnalysisViewRead := Value;
end;
/// <summary>
/// Validates analysis view consistency across account schedule and column layout configuration.
/// Ensures analysis view setup is compatible with financial reporting requirements.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to validate analysis view for</param>
/// <param name="CurrentColumnName">Column layout name to validate analysis view for</param>
/// <param name="TestColumnName">Whether to validate column layout analysis view settings</param>
/// <summary>
/// Validates and configures analysis view settings for account schedule and column layout compatibility.
/// Ensures proper dimension setup and analysis view consistency across schedule and columns.
/// </summary>
/// <param name="CurrentSchedName">Account schedule name to validate against analysis view</param>
/// <param name="CurrentColumnName">Column layout name for analysis view configuration</param>
/// <param name="TestColumnName">Whether to validate column layout name consistency</param>
procedure CheckAnalysisView(CurrentSchedName: Code[10]; CurrentColumnName: Code[10]; TestColumnName: Boolean)
var
ColumnLayout2: Record "Column Layout";
AnyColumnDimensions: Boolean;
begin
if not AnalysisViewRead then begin
AnalysisViewRead := true;
if CurrentSchedName <> AccSchedName.Name then begin
CheckTemplateName(CurrentSchedName);
AccSchedName.Get(CurrentSchedName);
end;
if TestColumnName then
if CurrentColumnName <> ColumnLayoutName.Name then begin
CheckColumnTemplateName(CurrentColumnName);
ColumnLayoutName.Get(CurrentColumnName);
end;
if AccSchedName."Analysis View Name" = '' then begin
GetGLSetup();
AnalysisView.Init();
AnalysisView."Dimension 1 Code" := GLSetup."Global Dimension 1 Code";
AnalysisView."Dimension 2 Code" := GLSetup."Global Dimension 2 Code";
end else
AnalysisView.Get(AccSchedName."Analysis View Name");
if AccSchedName."Analysis View Name" <> ColumnLayoutName."Analysis View Name" then begin
AnyColumnDimensions := false;
ColumnLayout2.SetRange("Column Layout Name", ColumnLayoutName.Name);
if ColumnLayout2.Find('-') then
repeat
AnyColumnDimensions :=
(ColumnLayout2."Dimension 1 Totaling" <> '') or
(ColumnLayout2."Dimension 2 Totaling" <> '') or
(ColumnLayout2."Dimension 3 Totaling" <> '') or
(ColumnLayout2."Dimension 4 Totaling" <> '');
until AnyColumnDimensions or (ColumnLayout2.Next() = 0);
if AnyColumnDimensions then
Error(
Text024,
AccSchedName.FieldCaption("Analysis View Name"),
AccSchedName.TableCaption(),
AccSchedName."Analysis View Name",
ColumnLayoutName.FieldCaption("Analysis View Name"),
ColumnLayoutName.TableCaption(),
ColumnLayoutName."Analysis View Name",
ColumnLayout2.TableCaption());
end;
end;
OnAfterCheckAnalysisView(AccSchedName, ColumnLayoutName, AnalysisView);
end;
procedure CheckPerspectiveAnalysisView(CurrentSchedName: Code[10]; CurrentPerspectiveName: Code[10])
var
DimPerspectiveName: Record "Dimension Perspective Name";
DimPerspectiveLine: Record "Dimension Perspective Line";
AnyPerspectiveDimensions: Boolean;
begin
if not DimPerspectiveRead then begin
DimPerspectiveRead := true;
if CurrentSchedName <> AccSchedName.Name then begin
CheckTemplateName(CurrentSchedName);
AccSchedName.Get(CurrentSchedName);
end;
DimPerspectiveName.Get(CurrentPerspectiveName);
if AccSchedName."Analysis View Name" = '' then begin
GetGLSetup();
AnalysisView.Init();
AnalysisView."Dimension 1 Code" := GLSetup."Global Dimension 1 Code";
AnalysisView."Dimension 2 Code" := GLSetup."Global Dimension 2 Code";
end else
AnalysisView.Get(AccSchedName."Analysis View Name");
if AccSchedName."Analysis View Name" <> DimPerspectiveName."Analysis View Name" then begin
DimPerspectiveLine.SetRange(Name, CurrentPerspectiveName);
if DimPerspectiveLine.FindSet() then
repeat
AnyPerspectiveDimensions :=
(DimPerspectiveLine."Dimension 1 Totaling" <> '') or
(DimPerspectiveLine."Dimension 2 Totaling" <> '') or
(DimPerspectiveLine."Dimension 3 Totaling" <> '') or
(DimPerspectiveLine."Dimension 4 Totaling" <> '');
until AnyPerspectiveDimensions or (DimPerspectiveLine.Next() = 0);
if AnyPerspectiveDimensions then
Error(
Text024,
AccSchedName.FieldCaption("Analysis View Name"),
AccSchedName.TableCaption(),
AccSchedName."Analysis View Name",
DimPerspectiveName.FieldCaption("Analysis View Name"),
DimPerspectiveName.TableCaption(),
DimPerspectiveName."Analysis View Name",
DimPerspectiveLine.TableCaption());
end;
if (DimPerspectiveName."Perspective Type" <> DimPerspectiveName."Perspective Type"::Custom) and
(DimPerspectiveName."Analysis View Name" <> '')
then
case DimPerspectiveName."Perspective Type" of
"Dimension Perspective Type"::Dimension5,
"Dimension Perspective Type"::Dimension6,
"Dimension Perspective Type"::Dimension7,
"Dimension Perspective Type"::Dimension8,
"Dimension Perspective Type"::BusinessUnit:
Error(
PerspectiveDimensionMismatchErr,
DimPerspectiveName.FieldCaption("Perspective Type"),
DimPerspectiveName.TableCaption(),
DimPerspectiveName.FieldCaption("Analysis View Name"),
DimPerspectiveName."Analysis View Name");
end;
end;
end;
/// <summary>
/// Calculates accounting period start and end dates based on column layout comparison period formula.
/// Handles period formulas for historical, current, and future period comparisons.
/// </summary>
/// <param name="ColumnLayout">Column layout containing comparison period formula configuration</param>
/// <param name="Date">Base date to calculate period range from</param>
/// <param name="StartDate">Calculated period start date returned</param>
/// <param name="EndDate">Calculated period end date returned</param>
procedure AccPeriodStartEnd(ColumnLayout: Record "Column Layout"; Date: Date; var StartDate: Date; var EndDate: Date)
var
PeriodFormulaParser: Codeunit "Period Formula Parser";
Steps: Integer;
Type: Enum "Period Type";
RangeFromType: Enum "Period Formula Range";
RangeToType: Enum "Period Formula Range";
RangeFromInt: Integer;
RangeToInt: Integer;
begin
if ColumnLayout."Comparison Period Formula" = '' then
exit;
PeriodFormulaParser.ParsePeriodFormula(
ColumnLayout."Comparison Period Formula", Steps, Type, RangeFromType, RangeToType, RangeFromInt, RangeToInt, ColumnLayout."Comparison Period Formula LCID");
AccountingPeriodMgt.AccPeriodStartEnd(
Date, StartDate, EndDate, PeriodError, Steps, Type, RangeFromType, RangeToType, RangeFromInt, RangeToInt);
end;
local procedure InitBasePercents(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout")
var
BaseIdx: Integer;
begin
Clear(BasePercentLine);
BaseIdx := 0;
AccSchedLine.SetRange("Schedule Name", AccSchedLine."Schedule Name");
if AccSchedLine.Find('-') then
repeat
if AccSchedLine."Totaling Type" = AccSchedLine."Totaling Type"::"Set Base For Percent" then begin
BaseIdx := BaseIdx + 1;
if BaseIdx > ArrayLen(BasePercentLine) then
ShowError(
StrSubstNo(Text022, ArrayLen(BasePercentLine), AccSchedLine.FieldCaption("Totaling Type"), AccSchedLine."Totaling Type"),
AccSchedLine, ColumnLayout);
BasePercentLine[BaseIdx] := AccSchedLine."Line No.";
end;
until AccSchedLine.Next() = 0;
if BaseIdx = 0 then begin
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Set Base For Percent";
ShowError(
StrSubstNo(Text023, AccSchedLine.FieldCaption("Totaling Type"), AccSchedLine."Totaling Type"),
AccSchedLine, ColumnLayout);
end;
end;
local procedure GetBasePercentLine(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"): Integer
var
BaseIdx: Integer;
begin
if BasePercentLine[1] = 0 then
InitBasePercents(AccSchedLine, ColumnLayout);
BaseIdx := ArrayLen(BasePercentLine);
repeat
if BasePercentLine[BaseIdx] <> 0 then
if BasePercentLine[BaseIdx] < AccSchedLine."Line No." then
exit(BasePercentLine[BaseIdx]);
BaseIdx := BaseIdx - 1;
until BaseIdx = 0;
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Set Base For Percent";
ShowError(
StrSubstNo(Text023, AccSchedLine.FieldCaption("Totaling Type"), AccSchedLine."Totaling Type"),
AccSchedLine, ColumnLayout);
end;
local procedure GetGLSetup() Result: Boolean
begin
if not GLSetupRead then
Result := GLSetup.Get();
GLSetupRead := true;
end;
/// <summary>
/// Calculates the cell for the specified Acc. Schedule Line and Column Layout combination.
/// An additional currency can be calculated using the CalcAddCurr parameter, but this parameter may be ignored if the Column Layout's Show in ACY field is set to true.
/// Core calculation engine handling formulas, totaling, and various source systems.
/// </summary>
/// <param name="AccSchedLine">Account schedule line defining row calculation logic</param>
/// <param name="ColumnLayout">Column layout defining period and calculation parameters</param>
/// <param name="CalcAddCurr">Whether to calculate in additional reporting currency</param>
/// <returns>Calculated financial value for the line/column intersection</returns>
procedure CalcCell(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean) Result: Decimal
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCalcCell(AccSchedLine, ColumnLayout, CalcAddCurr, Result, IsHandled, Recalculate);
if not IsHandled then begin
if ColumnLayout."Show in ACY" then
CalcAddCurr := true;
AccountScheduleLine."Dimension 1 Totaling" := AccSchedLine."Dimension 1 Totaling";
AccountScheduleLine."Dimension 2 Totaling" := AccSchedLine."Dimension 2 Totaling";
AccountScheduleLine.CopyFilters(AccSchedLine);
OnCalcCellOnAfterAccountScheduleLineCopyFilters(ColumnLayout, AccountScheduleLine);
StartDate := AccountScheduleLine.GetRangeMin("Date Filter");
if EndDate <> AccountScheduleLine.GetRangeMax("Date Filter") then begin
EndDate := AccountScheduleLine.GetRangeMax("Date Filter");
FiscalStartDate := AccountingPeriodMgt.FindFiscalYear(EndDate);
end;
DivisionError := false;
PeriodError := false;
CallingAccSchedLineID := AccSchedLine."Line No.";
CallingColumnLayoutID := ColumnLayout."Line No.";
if (OldAccSchedLineFilters <> AccSchedLine.GetFilters) or
(OldColumnLayoutFilters <> ColumnLayout.GetFilters) or
(OldAccSchedLineName <> AccSchedLine."Schedule Name") or
(OldColumnLayoutName <> ColumnLayout."Column Layout Name") or
(OldCalcAddCurr <> CalcAddCurr) or
Recalculate
then begin
TempAccSchedCellValue.Reset();
TempAccSchedCellValue.DeleteAll();
Clear(BasePercentLine);
OldAccSchedLineFilters := AccSchedLine.GetFilters();
OldColumnLayoutFilters := ColumnLayout.GetFilters();
OldAccSchedLineName := AccSchedLine."Schedule Name";
OldColumnLayoutName := ColumnLayout."Column Layout Name";
OldCalcAddCurr := CalcAddCurr;
end;
Result := CalcCellValue(AccSchedLine, ColumnLayout, CalcAddCurr);
FormatCellResult(AccSchedLine, ColumnLayout, CalcAddCurr, Result);
end;
OnBeforeCalcCellExit(AccSchedLine, ColumnLayout, CalcAddCurr, Result);
end;
/// <summary>
/// Applies display formatting rules to calculated financial values.
/// Handles positive/negative value display options and rounding specifications.
/// </summary>
/// <param name="AccSchedLine">Account schedule line containing formatting preferences</param>
/// <param name="ColumnLayout">Column layout containing show and rounding options</param>
/// <param name="CalcAddCurr">Whether calculation uses additional reporting currency</param>
/// <param name="Result">Financial value to format, modified according to display rules</param>
procedure FormatCellResult(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var Result: Decimal)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeFormatCellResult(AccSchedLine, ColumnLayout, CalcAddCurr, Result, IsHandled);
if IsHandled then
exit;
case ColumnLayout.Show of
ColumnLayout.Show::"When Positive":
if Result < 0 then
Result := 0;
ColumnLayout.Show::"When Negative":
if Result > 0 then
Result := 0;
end;
if ColumnLayout."Show Opposite Sign" then
Result := -Result;
case ColumnLayout."Show Indented Lines" of
ColumnLayout."Show Indented Lines"::"Indented Only":
if AccSchedLine.Indentation = 0 then
Result := 0;
ColumnLayout."Show Indented Lines"::"Non-Indented Only":
if AccSchedLine.Indentation > 0 then
Result := 0;
end;
if AccSchedLine."Show Opposite Sign" then
Result := -Result;
end;
/// <summary>
/// Evaluates financial value for specific account schedule line and column layout combination.
/// Handles various source systems including G/L accounts, cost accounting, cash flow, and budgets.
/// </summary>
/// <param name="AccSchedLine">Account schedule line containing totaling and calculation rules</param>
/// <param name="ColumnLayout">Column layout defining period, formula, and display parameters</param>
/// <param name="CalcAddCurr">Whether to calculate amounts in additional reporting currency</param>
/// <returns>Calculated financial value from specified sources and formulas</returns>
procedure CalcCellValue(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean) Result: Decimal
var
GLAcc: Record "G/L Account";
GLAccountCategory: Record "G/L Account Category";
CostType: Record "Cost Type";
CFAccount: Record "Cash Flow Account";
GLAccCategoriesToVisit: Record "G/L Acc. Cat. Buffer";
GLAccCategoriesVisited: Record "G/L Acc. Cat. Buffer";
GLAccCatCode: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCalcCellValue(AccSchedLine, ColumnLayout, CalcAddCurr, Result, IsHandled, AccountScheduleLine, TempAccSchedCellValue);
if not IsHandled then begin
if AccSchedLine.Totaling = '' then
exit(Result);
if TempAccSchedCellValue.Get(AccSchedLine."Line No.", ColumnLayout."Line No.") then begin
Result := TempAccSchedCellValue.Value;
DivisionError := DivisionError or TempAccSchedCellValue."Has Error";
PeriodError := PeriodError or TempAccSchedCellValue."Period Error";
end else begin
if ColumnLayout."Column Type" = ColumnLayout."Column Type"::Formula then
Result :=
EvaluateExpression(
false, ColumnLayout.Formula, AccSchedLine, ColumnLayout, CalcAddCurr)
else
if AccSchedLine."Totaling Type" in
[AccSchedLine."Totaling Type"::Formula, AccSchedLine."Totaling Type"::"Set Base For Percent"]
then
Result :=
EvaluateExpression(
true, AccSchedLine.Totaling, AccSchedLine, ColumnLayout, CalcAddCurr)
else
if (StartDate = 0D) or (EndDate = 0D) or (EndDate = DMY2Date(31, 12, 9999)) then begin
Result := 0;
PeriodError := true;
end else
case AccSchedLine."Totaling Type" of
AccSchedLine."Totaling Type"::"Posting Accounts",
AccSchedLine."Totaling Type"::"Total Accounts":
begin
AccSchedLine.CopyFilters(AccountScheduleLine);
SetGLAccRowFilters(GLAcc, AccSchedLine);
SetGLAccColumnFilters(GLAcc, AccSchedLine, ColumnLayout);
if (AccSchedLine."Totaling Type" = AccSchedLine."Totaling Type"::"Posting Accounts") and
(StrLen(AccSchedLine.Totaling) <= MaxStrLen(GLAcc.Totaling)) and (StrPos(AccSchedLine.Totaling, '*') = 0)
then begin
GLAcc."Account Type" := GLAcc."Account Type"::Total;
GLAcc.Totaling := AccSchedLine.Totaling;
Result := Result + CalcGLAcc(GLAcc, AccSchedLine, ColumnLayout, CalcAddCurr);
end else
if GLAcc.Find('-') then
repeat
Result := Result + CalcGLAcc(GLAcc, AccSchedLine, ColumnLayout, CalcAddCurr);
until GLAcc.Next() = 0;
end;
AccSchedLine."Totaling Type"::"Cost Type",
AccSchedLine."Totaling Type"::"Cost Type Total":
begin
AccSchedLine.CopyFilters(AccountScheduleLine);
SetCostTypeRowFilters(CostType, AccSchedLine, ColumnLayout);
SetCostTypeColumnFilters(CostType, AccSchedLine, ColumnLayout);
if (AccSchedLine."Totaling Type" = AccSchedLine."Totaling Type"::"Cost Type") and
(StrLen(AccSchedLine.Totaling) <= MaxStrLen(GLAcc.Totaling)) and (StrPos(AccSchedLine.Totaling, '*') = 0)
then begin
CostType.Type := CostType.Type::Total;
CostType.Totaling := AccSchedLine.Totaling;
Result := Result + CalcCostType(CostType, AccSchedLine, ColumnLayout, CalcAddCurr);
end else
if CostType.Find('-') then
repeat
Result := Result + CalcCostType(CostType, AccSchedLine, ColumnLayout, CalcAddCurr);
until CostType.Next() = 0;
end;
AccSchedLine."Totaling Type"::"Cash Flow Entry Accounts",
AccSchedLine."Totaling Type"::"Cash Flow Total Accounts":
begin
AccSchedLine.CopyFilters(AccountScheduleLine);
SetCFAccRowFilter(CFAccount, AccSchedLine);
SetCFAccColumnFilter(CFAccount, AccSchedLine, ColumnLayout);
if (AccSchedLine."Totaling Type" = AccSchedLine."Totaling Type"::"Cash Flow Entry Accounts") and
(StrLen(AccSchedLine.Totaling) <= 30)
then begin
CFAccount."Account Type" := CFAccount."Account Type"::Total;
CFAccount.Totaling := AccSchedLine.Totaling;
Result := Result + CalcCFAccount(CFAccount, AccSchedLine, ColumnLayout);
end else
if CFAccount.Find('-') then
repeat
Result := Result + CalcCFAccount(CFAccount, AccSchedLine, ColumnLayout);
until CFAccount.Next() = 0;
end;
AccSchedLine."Totaling Type"::"Account Category":
begin
AccSchedLine.CopyFilters(AccountScheduleLine);
GLAccountCategory.Reset();
GLAccountCategory.SetFilter("Entry No.", AccSchedLine.Totaling);
if GLAccountCategory.FindSet() then
repeat
GLAccCategoriesToVisit."Entry No." := GLAccountCategory."Entry No.";
GLAccCategoriesToVisit.Insert();
until GLAccountCategory.Next() = 0;
while GLAccCategoriesToVisit.Count() > 0 do begin
GLAccCategoriesToVisit.FindFirst();
GLAccCatCode := GLAccCategoriesToVisit."Entry No.";
GLAcc.Reset();
GlAcc.SetRange("Account Type", GlAcc."Account Type"::Posting);
GlAcc.SetRange("Account Subcategory Entry No.", GLAccCatCode);
SetGLAccColumnFilters(GLAcc, AccSchedLine, ColumnLayout);
if GLAcc.FindSet() then
repeat
GLAcc.CalcFields(Balance);
Result := Result + CalcGLAcc(GLAcc, AccSchedLine, ColumnLayout, CalcAddCurr);
until GLAcc.Next() = 0;
GLAccCategoriesVisited."Entry No." := GLAccCatCode;
GLAccCategoriesVisited.Insert();
GLAccountCategory.Reset();
GLAccountCategory.SetRange("Parent Entry No.", GLAccCatCode);
if GLAccountCategory.FindSet() then
repeat
if (not GLAccCategoriesVisited.Get(GLAccountCategory."Entry No.")) and (not GLAccCategoriesToVisit.Get(GLAccountCategory."Entry No.")) then begin
GLAccCategoriesToVisit."Entry No." := GLAccountCategory."Entry No.";
GLAccCategoriesToVisit.Insert();
end;
until GLAccountCategory.Next() = 0;
GLAccCategoriesToVisit."Entry No." := GLAccCatCode;
GLAccCategoriesToVisit.Delete();
end;
end
else
OnCalcCellValueOnElseTotalingType(AccSchedLine, AccountScheduleLine, ColumnLayout, Result);
end;
OnAfterCalcCellValue(AccSchedLine, ColumnLayout, Result, AccountScheduleLine, GLAcc);
TempAccSchedCellValue."Row No." := AccSchedLine."Line No.";
TempAccSchedCellValue."Column No." := ColumnLayout."Line No.";
TempAccSchedCellValue.Value := Result;
TempAccSchedCellValue."Has Error" := DivisionError;
TempAccSchedCellValue."Period Error" := PeriodError;
TempAccSchedCellValue.Insert();
end;
end;
OnCalcCellValueOnBeforeExit(AccSchedLine, ColumnLayout, CalcAddCurr, StartDate, EndDate, Result);
end;
/// <summary>
/// Calculates G/L account values for account schedule line and column intersection.
/// Handles various amount types, entry types, and currency calculations with filter support.
/// </summary>
/// <param name="GLAcc">G/L Account record for calculation with applied filters</param>
/// <param name="AccSchedLine">Account schedule line containing totaling configuration and filters</param>
/// <param name="ColumnLayout">Column layout defining calculation parameters and date ranges</param>
/// <param name="CalcAddCurr">Whether to calculate using additional currency amounts</param>
/// <returns>Calculated decimal amount for the account schedule cell</returns>
procedure CalcGLAcc(var GLAcc: Record "G/L Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean) ColValue: Decimal
var
[SecurityFiltering(SecurityFilter::Filtered)]
GLEntry: Record "G/L Entry";
[SecurityFiltering(SecurityFilter::Filtered)]
GLBudgEntry: Record "G/L Budget Entry";
[SecurityFiltering(SecurityFilter::Filtered)]
AnalysisViewEntry: Record "Analysis View Entry";
[SecurityFiltering(SecurityFilter::Filtered)]
AnalysisViewBudgetEntry: Record "Analysis View Budget Entry";
AmountType: Enum "Account Schedule Amount Type";
TestBalance: Boolean;
Balance: Decimal;
UseBusUnitFilter: Boolean;
UseDimFilter: Boolean;
IsHandled: Boolean;
begin
ColValue := 0;
IsHandled := false;
OnBeforeCalcGLAcc(GLAcc, AccSchedLine, ColumnLayout, CalcAddCurr, ColValue, IsHandled);
if IsHandled then
exit(ColValue);
UseDimFilter := false;
if AccSchedName.Name <> AccSchedLine."Schedule Name" then
AccSchedName.Get(AccSchedLine."Schedule Name");
if ConflictAmountType(AccSchedLine, ColumnLayout."Amount Type", AmountType) then
exit(0);
TestBalance :=
AccSchedLine.Show in [AccSchedLine.Show::"When Positive Balance", AccSchedLine.Show::"When Negative Balance"];
if ColumnLayout."Column Type" <> ColumnLayout."Column Type"::Formula then begin
UseBusUnitFilter := (AccSchedLine.GetFilter("Business Unit Filter") <> '') or (ColumnLayout."Business Unit Totaling" <> '');
UseDimFilter := HasDimFilter(AccSchedLine, ColumnLayout);
case ColumnLayout."Ledger Entry Type" of
ColumnLayout."Ledger Entry Type"::Entries:
if AccSchedName."Analysis View Name" = '' then begin
SetGLAccGLEntryFilters(GLAcc, GLEntry, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter);
case AmountType of
AmountType::"Net Amount":
begin
if CalcAddCurr then begin
GLEntry.CalcSums("Additional-Currency Amount");
ColValue := GLEntry."Additional-Currency Amount";
end else begin
GLEntry.CalcSums(Amount);
ColValue := GLEntry.Amount;
end;
Balance := ColValue;
end;
AmountType::"Debit Amount":
if CalcAddCurr then begin
if TestBalance then begin
GLEntry.CalcSums("Add.-Currency Debit Amount", "Additional-Currency Amount");
Balance := GLEntry."Additional-Currency Amount";
end else
GLEntry.CalcSums("Add.-Currency Debit Amount");
ColValue := GLEntry."Add.-Currency Debit Amount";
end else begin
if TestBalance then begin
GLEntry.CalcSums("Debit Amount", Amount);
Balance := GLEntry.Amount;
end else
GLEntry.CalcSums("Debit Amount");
ColValue := GLEntry."Debit Amount";
end;
AmountType::"Credit Amount":
if CalcAddCurr then begin
if TestBalance then begin
GLEntry.CalcSums("Add.-Currency Credit Amount", "Additional-Currency Amount");
Balance := GLEntry."Additional-Currency Amount";
end else
GLEntry.CalcSums("Add.-Currency Credit Amount");
ColValue := GLEntry."Add.-Currency Credit Amount";
end else begin
if TestBalance then begin
GLEntry.CalcSums("Credit Amount", Amount);
Balance := GLEntry.Amount;
end else
GLEntry.CalcSums("Credit Amount");
ColValue := GLEntry."Credit Amount";
end;
end;
end
else begin
SetGLAccAnalysisViewEntryFilters(GLAcc, AnalysisViewEntry, AccSchedLine, ColumnLayout);
case AmountType of
AmountType::"Net Amount":
begin
if CalcAddCurr then begin
AnalysisViewEntry.CalcSums("Add.-Curr. Amount");
ColValue := AnalysisViewEntry."Add.-Curr. Amount";
end else begin
AnalysisViewEntry.CalcSums(Amount);
ColValue := AnalysisViewEntry.Amount;
end;
Balance := ColValue;
end;
AmountType::"Debit Amount":
if CalcAddCurr then begin
if TestBalance then begin
AnalysisViewEntry.CalcSums("Add.-Curr. Debit Amount", "Add.-Curr. Amount");
Balance := AnalysisViewEntry."Add.-Curr. Amount";
end else
AnalysisViewEntry.CalcSums("Add.-Curr. Debit Amount");
ColValue := AnalysisViewEntry."Add.-Curr. Debit Amount";
end else begin
if TestBalance then begin
AnalysisViewEntry.CalcSums("Debit Amount", Amount);
Balance := AnalysisViewEntry.Amount;
end else
AnalysisViewEntry.CalcSums("Debit Amount");
ColValue := AnalysisViewEntry."Debit Amount";
end;
AmountType::"Credit Amount":
if CalcAddCurr then begin
if TestBalance then begin
AnalysisViewEntry.CalcSums("Add.-Curr. Credit Amount", "Add.-Curr. Amount");
Balance := AnalysisViewEntry."Add.-Curr. Amount";
end else
AnalysisViewEntry.CalcSums("Add.-Curr. Credit Amount");
ColValue := AnalysisViewEntry."Add.-Curr. Credit Amount";
end else begin
if TestBalance then begin
AnalysisViewEntry.CalcSums("Credit Amount", Amount);
Balance := AnalysisViewEntry.Amount;
end else
AnalysisViewEntry.CalcSums("Credit Amount");
ColValue := AnalysisViewEntry."Credit Amount";
end;
end;
end;
ColumnLayout."Ledger Entry Type"::"Budget Entries":
begin
if AccSchedName."Analysis View Name" = '' then begin
SetGLAccGLBudgetEntryFilters(GLAcc, GLBudgEntry, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter);
case AmountType of
AmountType::"Net Amount":
begin
GLBudgEntry.CalcSums(Amount);
ColValue := GLBudgEntry.Amount;
end;
AmountType::"Debit Amount":
begin
GLBudgEntry.CalcSums(Amount);
ColValue := GLBudgEntry.Amount;
if ColValue < 0 then
ColValue := 0;
end;
AmountType::"Credit Amount":
begin
GLBudgEntry.CalcSums(Amount);
ColValue := -GLBudgEntry.Amount;
if ColValue < 0 then
ColValue := 0;
end;
end;
Balance := GLBudgEntry.Amount;
end
else begin
SetGLAccAnalysisViewBudgetEntries(GLAcc, AnalysisViewBudgetEntry, AccSchedLine, ColumnLayout);
case AmountType of
AmountType::"Net Amount":
begin
AnalysisViewBudgetEntry.CalcSums(Amount);
ColValue := AnalysisViewBudgetEntry.Amount;
end;
AmountType::"Debit Amount":
begin
AnalysisViewBudgetEntry.CalcSums(Amount);
ColValue := AnalysisViewBudgetEntry.Amount;
if ColValue < 0 then
ColValue := 0;
end;
AmountType::"Credit Amount":
begin
AnalysisViewBudgetEntry.CalcSums(Amount);
ColValue := -AnalysisViewBudgetEntry.Amount;
if ColValue < 0 then
ColValue := 0;
end;
end;
Balance := AnalysisViewBudgetEntry.Amount;
end;
if CalcAddCurr then
ColValue := CalcLCYToACY(ColValue);
end;
end;
OnBeforeTestBalance(
GLAcc, AccSchedName, AccSchedLine, ColumnLayout, AmountType.AsInteger(), ColValue, CalcAddCurr, TestBalance, GLEntry, GLBudgEntry, Balance);
if TestBalance then begin
if AccSchedLine.Show = AccSchedLine.Show::"When Positive Balance" then
if Balance < 0 then
exit(0);
if AccSchedLine.Show = AccSchedLine.Show::"When Negative Balance" then
if Balance > 0 then
exit(0);
end;
end;
exit(ColValue);
end;
/// <summary>
/// Calculates cash flow account values for account schedule line and column intersection.
/// Processes cash flow forecast entries with support for various amount types and filtering.
/// </summary>
/// <param name="CFAccount">Cash Flow Account record for calculation with applied filters</param>
/// <param name="AccSchedLine">Account schedule line containing cash flow totaling configuration</param>
/// <param name="ColumnLayout">Column layout defining calculation parameters and date ranges</param>
/// <returns>Calculated decimal amount for the cash flow account schedule cell</returns>
procedure CalcCFAccount(var CFAccount: Record "Cash Flow Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout") ColValue: Decimal
var
CFForecastEntry: Record "Cash Flow Forecast Entry";
AnalysisViewEntry: Record "Analysis View Entry";
AmountType: Enum "Account Schedule Amount Type";
IsHandled: Boolean;
begin
ColValue := 0;
IsHandled := false;
OnBeforeCalcCFAcc(CFAccount, AccSchedLine, ColumnLayout, ColValue, IsHandled);
if IsHandled then
exit(ColValue);
if AccSchedName.Name <> AccSchedLine."Schedule Name" then
AccSchedName.Get(AccSchedLine."Schedule Name");
if ConflictAmountType(AccSchedLine, ColumnLayout."Amount Type", AmountType) then
exit(0);
if ColumnLayout."Column Type" <> ColumnLayout."Column Type"::Formula then
case ColumnLayout."Ledger Entry Type" of
ColumnLayout."Ledger Entry Type"::Entries:
if AccSchedName."Analysis View Name" = '' then begin
SetCFEntryFilters(CFAccount, CFForecastEntry, AccSchedLine, ColumnLayout);
case ColumnLayout."Amount Type" of
ColumnLayout."Amount Type"::"Net Amount":
begin
CFForecastEntry.CalcSums("Amount (LCY)");
ColValue := CFForecastEntry."Amount (LCY)";
end;
end;
end
else begin
SetCFAnalysisViewEntryFilters(CFAccount, AnalysisViewEntry, AccSchedLine, ColumnLayout);
case ColumnLayout."Amount Type" of
ColumnLayout."Amount Type"::"Net Amount":
begin
AnalysisViewEntry.CalcSums(Amount);
ColValue := AnalysisViewEntry.Amount;
end;
end;
end;
end;
OnCalcCFAccountOnAfterSetEntryFilters(CFAccount, AccSchedLine, ColumnLayout, ColValue);
exit(ColValue);
end;
local procedure CalcCellValueInAccSchedLines(SourceAccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; Expression: Text; CalcAddCurr: Boolean; IsFilter: Boolean) Result: Decimal
var
AccSchedLine: Record "Acc. Schedule Line";
IsHandled: Boolean;
CellValue: Decimal;
begin
AccSchedLine.SetRange("Schedule Name", SourceAccSchedLine."Schedule Name");
AccSchedLine.SetFilter("Row No.", Expression);
if AccSchedLine.Find('-') then
repeat
if AccSchedLine."Line No." <> SourceAccSchedLine."Line No." then begin
IsHandled := false;
OnEvaluateExpressionOnBeforeCalcAccSchedLineCellValue(
SourceAccSchedLine, AccSchedLine, ColumnLayout, CalcAddCurr, IsHandled, CellValue);
if IsHandled then
Result += CellValue
else
Result := Result + CalcCellValue(AccSchedLine, ColumnLayout, CalcAddCurr);
end;
until AccSchedLine.Next() = 0
else begin
IsHandled := false;
OnCalcCellValueInAccSchedLinesOnBeforeShowError(
SourceAccSchedLine, AccSchedLine, ColumnLayout, CalcAddCurr, CellValue,
StartDate, EndDate, Result, IsHandled, Expression, DivisionError, PeriodError);
if not IsHandled then
if IsFilter or (not Evaluate(Result, Expression)) then
ShowError(Text012, SourceAccSchedLine, ColumnLayout);
end;
end;
local procedure CalcCellValueInColumnLayouts(SourceColumnLayout: Record "Column Layout"; AccSchedLine: Record "Acc. Schedule Line"; Expression: Text; CalcAddCurr: Boolean; IsFilter: Boolean) Result: Decimal
var
ColumnLayout: Record "Column Layout";
IsHandled: Boolean;
CellValue: Decimal;
begin
ColumnLayout.SetRange("Column Layout Name", SourceColumnLayout."Column Layout Name");
ColumnLayout.SetFilter("Column No.", Expression);
if ColumnLayout.Find('-') then
repeat
if ColumnLayout."Line No." <> SourceColumnLayout."Line No." then begin
IsHandled := false;
OnEvaluateExpressionOnBeforeCalcColumnLayoutCellValue(
SourceColumnLayout, AccSchedLine, ColumnLayout, CalcAddCurr, IsHandled, CellValue);
if IsHandled then
Result += CellValue
else
Result := Result + CalcCellValue(AccSchedLine, ColumnLayout, CalcAddCurr);
end;
until ColumnLayout.Next() = 0
else
if IsFilter or (not Evaluate(Result, Expression)) then
ShowError(Text013, AccSchedLine, SourceColumnLayout);
end;
/// <summary>
/// Applies row-level filters to G/L Account based on account schedule line totaling configuration.
/// Sets appropriate account number and account type filters for posting or total accounts.
/// </summary>
/// <param name="GLAcc">G/L Account record to apply filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing totaling type and range specification</param>
procedure SetGLAccRowFilters(var GLAcc: Record "G/L Account"; var AccSchedLine2: Record "Acc. Schedule Line")
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetGLAccRowFilters(GLAcc, AccSchedLine2, IsHandled);
if IsHandled then
exit;
case AccSchedLine2."Totaling Type" of
AccSchedLine2."Totaling Type"::"Posting Accounts":
begin
GLAcc.SetFilter("No.", AccSchedLine2.Totaling);
GLAcc.SetRange("Account Type", GLAcc."Account Type"::Posting);
end;
AccSchedLine2."Totaling Type"::"Total Accounts":
begin
GLAcc.SetFilter("No.", AccSchedLine2.Totaling);
GLAcc.SetFilter("Account Type", '<>%1', GLAcc."Account Type"::Posting);
end;
end;
OnAfterSetGLAccRowFilters(GLAcc, AccSchedLine2);
end;
/// <summary>
/// Applies comprehensive filters to G/L Entry records for account schedule calculations.
/// Handles account filters, date ranges, business unit filters, and dimension filters.
/// </summary>
/// <param name="GLAcc">G/L Account record with applied account filters</param>
/// <param name="GLEntry">G/L Entry record to apply calculation filters to</param>
/// <param name="AccSchedLine">Account schedule line containing filter specifications</param>
/// <param name="ColumnLayout">Column layout containing date and dimension filter criteria</param>
/// <param name="UseBusUnitFilter">Whether to apply business unit filtering</param>
/// <param name="UseDimFilter">Whether to apply dimension filtering</param>
procedure SetGLAccGLEntryFilters(var GLAcc: Record "G/L Account"; var GLEntry: Record "G/L Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetGLAccGLEntryFilters(GLAcc, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter, IsHandled, GLEntry);
if IsHandled then
exit;
if UseBusUnitFilter then
if UseDimFilter then
GLEntry.SetCurrentKey(
"G/L Account No.", "Business Unit Code", "Global Dimension 1 Code", "Global Dimension 2 Code")
else
GLEntry.SetCurrentKey(
"G/L Account No.", "Business Unit Code", "Posting Date")
else
if UseDimFilter then
GLEntry.SetCurrentKey("G/L Account No.", "Global Dimension 1 Code", "Global Dimension 2 Code")
else
GLEntry.SetCurrentKey("G/L Account No.", "Posting Date");
if GLAcc.Totaling = '' then
GLEntry.SetRange("G/L Account No.", GLAcc."No.")
else
GLEntry.SetFilter("G/L Account No.", GLAcc.Totaling);
GLAcc.CopyFilter("Date Filter", GLEntry."Posting Date");
AccSchedLine.CopyFilter("Business Unit Filter", GLEntry."Business Unit Code");
AccSchedLine.CopyFilter("Dimension 1 Filter", GLEntry."Global Dimension 1 Code");
AccSchedLine.CopyFilter("Dimension 2 Filter", GLEntry."Global Dimension 2 Code");
GLEntry.FilterGroup(2);
GLEntry.SetFilter("Global Dimension 1 Code", GetDimTotalingFilter(1, AccSchedLine."Dimension 1 Totaling"));
GLEntry.SetFilter("Global Dimension 2 Code", GetDimTotalingFilter(2, AccSchedLine."Dimension 2 Totaling"));
GLEntry.FilterGroup(8);
GLEntry.SetFilter("Global Dimension 1 Code", GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"));
GLEntry.SetFilter("Global Dimension 2 Code", GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"));
GLEntry.SetFilter("Business Unit Code", ColumnLayout."Business Unit Totaling");
GLEntry.SetFilter("G/L Account No.", ColumnLayout."G/L Account Totaling");
GLEntry.FilterGroup(0);
OnAfterSetGLAccGLEntryFilters(GLAcc, GLEntry, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter);
end;
/// <summary>
/// Applies comprehensive filters to G/L Budget Entry records for account schedule budget calculations.
/// Configures account filters, date ranges, business unit filters, and dimension filters for budget analysis.
/// </summary>
/// <param name="GLAcc">G/L Account record with applied account filters</param>
/// <param name="GLBudgetEntry">G/L Budget Entry record to apply calculation filters to</param>
/// <param name="AccSchedLine">Account schedule line containing filter specifications</param>
/// <param name="ColumnLayout">Column layout containing date and dimension filter criteria</param>
/// <param name="UseBusUnitFilter">Whether to apply business unit filtering</param>
/// <param name="UseDimFilter">Whether to apply dimension filtering</param>
procedure SetGLAccGLBudgetEntryFilters(var GLAcc: Record "G/L Account"; var GLBudgetEntry: Record "G/L Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetGLAccGLBudgetEntryFilters(GLAcc, GLBudgetEntry, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter, IsHandled);
if IsHandled then
exit;
if UseBusUnitFilter or UseDimFilter then
GLBudgetEntry.SetCurrentKey(
"Budget Name", "G/L Account No.", "Business Unit Code",
"Global Dimension 1 Code", "Global Dimension 2 Code",
"Budget Dimension 1 Code", "Budget Dimension 2 Code",
"Budget Dimension 3 Code", "Budget Dimension 4 Code", Date)
else
GLBudgetEntry.SetCurrentKey("Budget Name", "G/L Account No.", Date);
if GLAcc.Totaling = '' then
GLBudgetEntry.SetRange("G/L Account No.", GLAcc."No.")
else
GLBudgetEntry.SetFilter("G/L Account No.", GLAcc.Totaling);
GLAcc.CopyFilter("Date Filter", GLBudgetEntry.Date);
if ColumnLayout."Budget Name" <> '' then
GLBudgetEntry.SetRange("Budget Name", ColumnLayout."Budget Name")
else
AccSchedLine.CopyFilter("G/L Budget Filter", GLBudgetEntry."Budget Name");
AccSchedLine.CopyFilter("Business Unit Filter", GLBudgetEntry."Business Unit Code");
AccSchedLine.CopyFilter("Dimension 1 Filter", GLBudgetEntry."Global Dimension 1 Code");
AccSchedLine.CopyFilter("Dimension 2 Filter", GLBudgetEntry."Global Dimension 2 Code");
GLBudgetEntry.FilterGroup(2);
GLBudgetEntry.SetFilter("Global Dimension 1 Code", GetDimTotalingFilter(1, AccSchedLine."Dimension 1 Totaling"));
GLBudgetEntry.SetFilter("Global Dimension 2 Code", GetDimTotalingFilter(2, AccSchedLine."Dimension 2 Totaling"));
GLBudgetEntry.FilterGroup(8);
GLBudgetEntry.SetFilter("Global Dimension 1 Code", GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"));
GLBudgetEntry.SetFilter("Global Dimension 2 Code", GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"));
GLBudgetEntry.SetFilter("Business Unit Code", ColumnLayout."Business Unit Totaling");
GLBudgetEntry.SetFilter("G/L Account No.", ColumnLayout."G/L Account Totaling");
GLBudgetEntry.FilterGroup(0);
OnAfterSetGLAccGLBudgetEntryFilters(GLAcc, GLBudgetEntry, AccSchedLine, ColumnLayout, UseBusUnitFilter, UseDimFilter);
end;
/// <summary>
/// Configures Analysis View Budget Entry filters for multi-dimensional budget analysis calculations.
/// Applies account filters, analysis view settings, budget name filters, and comprehensive dimension filtering.
/// </summary>
/// <param name="GLAcc">G/L Account record with applied account filters and totaling configuration</param>
/// <param name="AnalysisViewBudgetEntry">Analysis View Budget Entry record to apply calculation filters to</param>
/// <param name="AccSchedLine">Account schedule line containing dimension totaling and filter specifications</param>
/// <param name="ColumnLayout">Column layout containing budget name and additional filter criteria</param>
procedure SetGLAccAnalysisViewBudgetEntries(var GLAcc: Record "G/L Account"; var AnalysisViewBudgetEntry: Record "Analysis View Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
if GLAcc.Totaling = '' then
AnalysisViewBudgetEntry.SetRange("G/L Account No.", GLAcc."No.")
else
AnalysisViewBudgetEntry.SetFilter("G/L Account No.", GLAcc.Totaling);
AnalysisViewBudgetEntry.SetRange("Analysis View Code", AccSchedName."Analysis View Name");
GLAcc.CopyFilter("Date Filter", AnalysisViewBudgetEntry."Posting Date");
if ColumnLayout."Budget Name" <> '' then
AnalysisViewBudgetEntry.SetRange("Budget Name", ColumnLayout."Budget Name")
else
AccSchedLine.CopyFilter("G/L Budget Filter", AnalysisViewBudgetEntry."Budget Name");
AccSchedLine.CopyFilter("Business Unit Filter", AnalysisViewBudgetEntry."Business Unit Code");
AnalysisViewBudgetEntry.CopyDimFilters(AccSchedLine);
AnalysisViewBudgetEntry.FilterGroup(2);
AnalysisViewBudgetEntry.SetDimFilters(
GetDimTotalingFilter(1, AccSchedLine."Dimension 1 Totaling"),
GetDimTotalingFilter(2, AccSchedLine."Dimension 2 Totaling"),
GetDimTotalingFilter(3, AccSchedLine."Dimension 3 Totaling"),
GetDimTotalingFilter(4, AccSchedLine."Dimension 4 Totaling"));
AnalysisViewBudgetEntry.FilterGroup(8);
AnalysisViewBudgetEntry.SetDimFilters(
GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"),
GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"),
GetDimTotalingFilter(3, ColumnLayout."Dimension 3 Totaling"),
GetDimTotalingFilter(4, ColumnLayout."Dimension 4 Totaling"));
AnalysisViewBudgetEntry.SetFilter("Business Unit Code", ColumnLayout."Business Unit Totaling");
AnalysisViewBudgetEntry.SetFilter("G/L Account No.", ColumnLayout."G/L Account Totaling");
AnalysisViewBudgetEntry.FilterGroup(0);
OnAfterSetGLAccAnalysisViewBudgetEntries(GLAcc, AnalysisViewBudgetEntry, AccSchedLine, ColumnLayout);
end;
/// <summary>
/// Configures Analysis View Entry filters for multi-dimensional G/L analysis calculations.
/// Applies account source settings, account filters, analysis view configuration, and dimension filtering.
/// </summary>
/// <param name="GLAcc">G/L Account record with applied account filters and totaling configuration</param>
/// <param name="AnalysisViewEntry">Analysis View Entry record to apply calculation filters to</param>
/// <param name="AccSchedLine">Account schedule line containing dimension totaling and filter specifications</param>
/// <param name="ColumnLayout">Column layout containing additional filter criteria for analysis view processing</param>
procedure SetGLAccAnalysisViewEntryFilters(var GLAcc: Record "G/L Account"; var AnalysisViewEntry: Record "Analysis View Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
AnalysisViewEntry.SetRange("Analysis View Code", AccSchedName."Analysis View Name");
AnalysisViewEntry.SetRange("Account Source", AnalysisViewEntry."Account Source"::"G/L Account");
if GLAcc.Totaling = '' then
AnalysisViewEntry.SetRange("Account No.", GLAcc."No.")
else
AnalysisViewEntry.SetFilter("Account No.", GLAcc.Totaling);
GLAcc.CopyFilter("Date Filter", AnalysisViewEntry."Posting Date");
OnSetGLAccAnalysisViewEntryFiltersOnBeforeAccSchedLineCopyFilter(AccSchedLine, AnalysisViewEntry);
AccSchedLine.CopyFilter("Business Unit Filter", AnalysisViewEntry."Business Unit Code");
AnalysisViewEntry.CopyDimFilters(AccSchedLine);
AnalysisViewEntry.FilterGroup(2);
AnalysisViewEntry.SetDimFilters(
GetDimTotalingFilter(1, AccSchedLine."Dimension 1 Totaling"),
GetDimTotalingFilter(2, AccSchedLine."Dimension 2 Totaling"),
GetDimTotalingFilter(3, AccSchedLine."Dimension 3 Totaling"),
GetDimTotalingFilter(4, AccSchedLine."Dimension 4 Totaling"));
AnalysisViewEntry.FilterGroup(8);
AnalysisViewEntry.SetDimFilters(
GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"),
GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"),
GetDimTotalingFilter(3, ColumnLayout."Dimension 3 Totaling"),
GetDimTotalingFilter(4, ColumnLayout."Dimension 4 Totaling"));
AnalysisViewEntry.SetFilter("Business Unit Code", ColumnLayout."Business Unit Totaling");
AnalysisViewEntry.SetFilter("Account No.", ColumnLayout."G/L Account Totaling");
AnalysisViewEntry.FilterGroup(0);
OnAfterSetGLAccAnalysisViewEntryFilters(GLAcc, AnalysisViewEntry, AccSchedLine, ColumnLayout);
end;
/// <summary>
/// Applies row-level filters to Cash Flow Account based on account schedule line configuration.
/// Sets cash flow forecast filters and account number filters for cash flow entry account calculations.
/// </summary>
/// <param name="CFAccount">Cash Flow Account record to apply filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing cash flow totaling and filter specifications</param>
procedure SetCFAccRowFilter(var CFAccount: Record "Cash Flow Account"; var AccSchedLine2: Record "Acc. Schedule Line")
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetCFAccRowFilter(CFAccount, AccSchedLine2, IsHandled);
if IsHandled then
exit;
AccSchedLine2.CopyFilter("Cash Flow Forecast Filter", CFAccount."Cash Flow Forecast Filter");
case AccSchedLine2."Totaling Type" of
AccSchedLine2."Totaling Type"::"Cash Flow Entry Accounts":
begin
CFAccount.SetFilter("No.", AccSchedLine2.Totaling);
CFAccount.SetRange("Account Type", CFAccount."Account Type"::Entry);
end;
AccSchedLine2."Totaling Type"::"Cash Flow Total Accounts":
begin
CFAccount.SetFilter("No.", AccSchedLine2.Totaling);
CFAccount.SetFilter("Account Type", '<>%1', CFAccount."Account Type"::Entry);
end;
end;
OnAfterSetCFAccRowFilter(CFAccount, AccSchedLine2);
end;
/// <summary>
/// Applies column-level date filters to G/L Account based on column layout and row type configuration.
/// Handles net change, beginning balance, and balance at date calculations with proper date range filtering.
/// </summary>
/// <param name="GLAcc">G/L Account record to apply column-based date filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing row type specification for date filter logic</param>
/// <param name="ColumnLayout">Column layout containing column type and date calculation parameters</param>
procedure SetGLAccColumnFilters(var GLAcc: Record "G/L Account"; AccSchedLine2: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
var
FromDate: Date;
ToDate: Date;
FiscalStartDate2: Date;
begin
CalcColumnDates(ColumnLayout, FromDate, ToDate, FiscalStartDate2);
case ColumnLayout."Column Type" of
ColumnLayout."Column Type"::"Net Change":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
GLAcc.SetRange("Date Filter", FromDate, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
GLAcc.SetFilter("Date Filter", '..%1', ClosingDate(FromDate - 1));
// always includes closing date
AccSchedLine2."Row Type"::"Balance at Date":
GLAcc.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout."Column Type"::"Balance at Date":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Beginning Balance" then
GLAcc.SetRange("Date Filter", 0D)
// Force a zero return
else
GLAcc.SetRange("Date Filter", 0D, ToDate);
ColumnLayout."Column Type"::"Beginning Balance":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Balance at Date" then
GLAcc.SetRange("Date Filter", 0D)
// Force a zero return
else
GLAcc.SetRange(
"Date Filter", 0D, ClosingDate(FromDate - 1));
ColumnLayout."Column Type"::"Year to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
GLAcc.SetRange("Date Filter", FiscalStartDate2, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
GLAcc.SetFilter("Date Filter", '..%1', ClosingDate(FiscalStartDate2 - 1));
// always includes closing date
AccSchedLine2."Row Type"::"Balance at Date":
GLAcc.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout."Column Type"::"Rest of Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
GLAcc.SetRange(
"Date Filter", CalcDate('<+1D>', ToDate), AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
GLAcc.SetRange("Date Filter", 0D, ToDate);
AccSchedLine2."Row Type"::"Balance at Date":
GLAcc.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout."Column Type"::"Entire Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
GLAcc.SetRange(
"Date Filter",
FiscalStartDate2,
AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
GLAcc.SetFilter("Date Filter", '..%1', ClosingDate(FiscalStartDate2 - 1));
// always includes closing date
AccSchedLine2."Row Type"::"Balance at Date":
GLAcc.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout."Column Type"::"Month to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
GLAcc.SetRange("Date Filter", CalcDate('<-CM>', ToDate), ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
GLAcc.SetFilter("Date Filter", '..%1', ClosingDate(CalcDate('<-CM>', ToDate) - 1));
AccSchedLine2."Row Type"::"Balance at Date":
GLAcc.SetRange("Date Filter", 0D, ToDate);
end;
end;
OnAfterSetGLAccColumnFilters(GLAcc, AccSchedLine2, ColumnLayout, StartDate, EndDate);
end;
/// <summary>
/// Applies column-level date filters to Cash Flow Account based on column layout and row type configuration.
/// Handles cash flow forecast date range filtering for different row types and column calculations.
/// </summary>
/// <param name="CFAccount">Cash Flow Account record to apply column-based date filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing row type specification for date filter logic</param>
/// <param name="ColumnLayout2">Column layout containing column type and date calculation parameters</param>
procedure SetCFAccColumnFilter(var CFAccount: Record "Cash Flow Account"; AccSchedLine2: Record "Acc. Schedule Line"; var ColumnLayout2: Record "Column Layout")
var
FromDate: Date;
ToDate: Date;
FiscalStartDate2: Date;
begin
CalcColumnDates(ColumnLayout2, FromDate, ToDate, FiscalStartDate2);
case ColumnLayout2."Column Type" of
ColumnLayout2."Column Type"::"Net Change":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CFAccount.SetRange("Date Filter", FromDate, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CFAccount.SetFilter("Date Filter", '..%1', ClosingDate(FromDate - 1));
AccSchedLine2."Row Type"::"Balance at Date":
CFAccount.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout2."Column Type"::"Balance at Date":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Beginning Balance" then
CFAccount.SetRange("Date Filter", 0D)
// Force a zero return
else
CFAccount.SetRange("Date Filter", 0D, ToDate);
ColumnLayout2."Column Type"::"Beginning Balance":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Balance at Date" then
CFAccount.SetRange("Date Filter", 0D)
// Force a zero return
else
CFAccount.SetRange(
"Date Filter", 0D, CalcDate('<-1D>', FromDate));
ColumnLayout2."Column Type"::"Year to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CFAccount.SetRange("Date Filter", FiscalStartDate2, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CFAccount.SetFilter("Date Filter", '..%1', FiscalStartDate2 - 1);
AccSchedLine2."Row Type"::"Balance at Date":
CFAccount.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout2."Column Type"::"Rest of Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CFAccount.SetRange(
"Date Filter",
CalcDate('<+1D>', ToDate), AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
CFAccount.SetRange("Date Filter", 0D, ToDate);
AccSchedLine2."Row Type"::"Balance at Date":
CFAccount.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout2."Column Type"::"Entire Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CFAccount.SetRange(
"Date Filter",
FiscalStartDate2, AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
CFAccount.SetFilter("Date Filter", '..%1', ClosingDate(FiscalStartDate2 - 1));
AccSchedLine2."Row Type"::"Balance at Date":
CFAccount.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout2."Column Type"::"Month to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CFAccount.SetRange("Date Filter", CalcDate('<-CM>', ToDate), ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CFAccount.SetFilter("Date Filter", '..%1', ClosingDate(CalcDate('<-CM>', ToDate) - 1));
AccSchedLine2."Row Type"::"Balance at Date":
CFAccount.SetRange("Date Filter", 0D, ToDate);
end;
end;
OnAfterSetCFAccColumnFilter(CFAccount, AccSchedLine2, ColumnLayout2, StartDate, EndDate);
end;
local procedure SetCFEntryFilters(var CFAccount: Record "Cash Flow Account"; var CFForecastEntry: Record "Cash Flow Forecast Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
CFForecastEntry.SetCurrentKey(
"Cash Flow Account No.", "Cash Flow Forecast No.", "Global Dimension 1 Code",
"Global Dimension 2 Code", "Cash Flow Date");
if CFAccount.Totaling = '' then
CFForecastEntry.SetRange("Cash Flow Account No.", CFAccount."No.")
else
CFForecastEntry.SetFilter("Cash Flow Account No.", CFAccount.Totaling);
CFAccount.CopyFilter("Date Filter", CFForecastEntry."Cash Flow Date");
AccSchedLine.CopyFilter("Cash Flow Forecast Filter", CFForecastEntry."Cash Flow Forecast No.");
AccSchedLine.CopyFilter("Dimension 1 Filter", CFForecastEntry."Global Dimension 1 Code");
AccSchedLine.CopyFilter("Dimension 2 Filter", CFForecastEntry."Global Dimension 2 Code");
OnSetCFEntryFiltersOnAfterAccShedLineCopyFilter(AccSchedLine, CFForecastEntry);
CFForecastEntry.FilterGroup(2);
CFForecastEntry.SetFilter("Global Dimension 1 Code", AccSchedLine."Dimension 1 Totaling");
CFForecastEntry.SetFilter("Global Dimension 2 Code", AccSchedLine."Dimension 2 Totaling");
CFForecastEntry.FilterGroup(8);
CFForecastEntry.SetFilter("Global Dimension 1 Code", GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"));
CFForecastEntry.SetFilter("Global Dimension 2 Code", GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"));
CFForecastEntry.FilterGroup(0);
end;
local procedure SetCFAnalysisViewEntryFilters(var CFAccount: Record "Cash Flow Account"; var AnalysisViewEntry: Record "Analysis View Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
AnalysisViewEntry.SetRange("Analysis View Code", AccSchedName."Analysis View Name");
AnalysisViewEntry.SetRange("Account Source", AnalysisViewEntry."Account Source"::"Cash Flow Account");
if CFAccount.Totaling = '' then
AnalysisViewEntry.SetRange("Account No.", CFAccount."No.")
else
AnalysisViewEntry.SetFilter("Account No.", CFAccount.Totaling);
CFAccount.CopyFilter("Date Filter", AnalysisViewEntry."Posting Date");
AccSchedLine.CopyFilter("Cash Flow Forecast Filter", AnalysisViewEntry."Cash Flow Forecast No.");
AnalysisViewEntry.CopyDimFilters(AccSchedLine);
AnalysisViewEntry.FilterGroup(2);
AnalysisViewEntry.SetDimFilters(
GetDimTotalingFilter(1, AccSchedLine."Dimension 1 Totaling"),
GetDimTotalingFilter(2, AccSchedLine."Dimension 2 Totaling"),
GetDimTotalingFilter(3, AccSchedLine."Dimension 3 Totaling"),
GetDimTotalingFilter(4, AccSchedLine."Dimension 4 Totaling"));
AnalysisViewEntry.FilterGroup(8);
AnalysisViewEntry.SetDimFilters(
GetDimTotalingFilter(1, ColumnLayout."Dimension 1 Totaling"),
GetDimTotalingFilter(2, ColumnLayout."Dimension 2 Totaling"),
GetDimTotalingFilter(3, ColumnLayout."Dimension 3 Totaling"),
GetDimTotalingFilter(4, ColumnLayout."Dimension 4 Totaling"));
AnalysisViewEntry.SetFilter("Account No.", ColumnLayout."G/L Account Totaling");
AnalysisViewEntry.FilterGroup(0);
OnAfterSetCFAnalysisViewEntryFilters(AnalysisViewEntry, AccSchedLine, ColumnLayout);
end;
/// <summary>
/// Applies mathematical operators to two decimal values with division error handling.
/// Supports addition, subtraction, multiplication, and division operations for account schedule formula calculations.
/// </summary>
/// <param name="LeftResult">Left operand decimal value for calculation</param>
/// <param name="RightResult">Right operand decimal value for calculation</param>
/// <param name="Operator">Mathematical operator character (+, -, *, /)</param>
/// <param name="DivisionError">Returns true if division by zero error occurred</param>
/// <returns>Calculated result of applying the operator to the two operands</returns>
procedure ApplyOperator(LeftResult: Decimal; RightResult: Decimal; Operator: Char; var DivisionError: Boolean) Result: Decimal
begin
case Operator of
'^':
Result := Power(LeftResult, RightResult);
'%':
if RightResult = 0 then begin
Result := 0;
DivisionError := true;
end else
Result := 100 * LeftResult / RightResult;
'*':
Result := LeftResult * RightResult;
'/':
if RightResult = 0 then begin
Result := 0;
DivisionError := true;
end else
Result := LeftResult / RightResult;
'+':
Result := LeftResult + RightResult;
'-':
Result := LeftResult - RightResult;
end;
end;
/// <summary>
/// Parses mathematical expressions to identify operator positions and validate expression structure.
/// Handles parentheses nesting and operator precedence for account schedule formula parsing.
/// </summary>
/// <param name="Expression">Mathematical expression text to parse for operators and structure</param>
/// <param name="i">Returns the position of the identified operator in the expression</param>
/// <returns>True if a valid expression structure with operators was found</returns>
procedure ParseExpression(Expression: Text; var i: Integer) IsExpression: Boolean
var
Parantheses: Integer;
Operators: Text[8];
OperatorNo: Integer;
begin
Parantheses := 0;
IsExpression := false;
Operators := '+-*/^%';
OperatorNo := 1;
repeat
i := StrLen(Expression);
repeat
if Expression[i] = '(' then
Parantheses := Parantheses + 1
else
if Expression[i] = ')' then
Parantheses := Parantheses - 1;
if (Parantheses = 0) and (Expression[i] = Operators[OperatorNo]) then
IsExpression := true
else
i := i - 1;
until IsExpression or (i <= 0);
if not IsExpression then
OperatorNo := OperatorNo + 1;
until (OperatorNo > StrLen(Operators)) or IsExpression;
end;
/// <summary>
/// Evaluates complex mathematical expressions for account schedule calculations.
/// Processes formulas with operators, parentheses, and cell references for financial reporting.
/// </summary>
/// <param name="IsAccSchedLineExpression">True if expression references account schedule line cells, false for column layout cells</param>
/// <param name="Expression">Mathematical expression text containing operators and cell references</param>
/// <param name="AccSchedLine">Account schedule line context for cell value calculations</param>
/// <param name="ColumnLayout">Column layout context for cell value calculations</param>
/// <param name="CalcAddCurr">Whether to calculate using additional currency amounts</param>
/// <returns>Calculated decimal result of the evaluated expression</returns>
procedure EvaluateExpression(IsAccSchedLineExpression: Boolean; Expression: Text; AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean): Decimal
var
AccSchedLine2: Record "Acc. Schedule Line";
Result: Decimal;
Operator: Char;
LeftOperand: Text;
RightOperand: Text;
LeftResult: Decimal;
RightResult: Decimal;
MaxLevel: Integer;
i: Integer;
IsExpression: Boolean;
IsFilter: Boolean;
begin
Result := 0;
OnBeforeEvaluateExpression(AccSchedLine, ColumnLayout, MaxLevel);
Expression := DelChr(Expression, '<>', ' ');
if StrLen(Expression) > 0 then begin
IsExpression := ParseExpression(Expression, i);
if IsExpression then begin
if i > 1 then
LeftOperand := CopyStr(Expression, 1, i - 1)
else
LeftOperand := '';
if i < StrLen(Expression) then
RightOperand := CopyStr(Expression, i + 1)
else
RightOperand := '';
Operator := Expression[i];
LeftResult :=
EvaluateExpression(
IsAccSchedLineExpression, LeftOperand, AccSchedLine, ColumnLayout, CalcAddCurr);
if (RightOperand = '') and (Operator = '%') and not IsAccSchedLineExpression and
(AccSchedLine."Totaling Type" <> AccSchedLine."Totaling Type"::"Set Base For Percent")
then begin
AccSchedLine2.Copy(AccSchedLine);
AccSchedLine2."Line No." := GetBasePercentLine(AccSchedLine, ColumnLayout);
AccSchedLine2.Find();
RightResult :=
EvaluateExpression(
IsAccSchedLineExpression, LeftOperand, AccSchedLine2, ColumnLayout, CalcAddCurr);
end else
RightResult :=
EvaluateExpression(
IsAccSchedLineExpression, RightOperand, AccSchedLine, ColumnLayout, CalcAddCurr);
Result := ApplyOperator(LeftResult, RightResult, Operator, DivisionError);
end else
if (Expression[1] = '(') and (Expression[StrLen(Expression)] = ')') then
Result :=
EvaluateExpression(
IsAccSchedLineExpression, CopyStr(Expression, 2, StrLen(Expression) - 2),
AccSchedLine, ColumnLayout, CalcAddCurr)
else begin
IsFilter := IsExpressionFilter(Expression);
if (StrLen(Expression) > 10) and (not IsFilter) then
Evaluate(Result, Expression)
else
Result := CalcCellValueInEvaluateExpression(IsAccSchedLineExpression, AccSchedLine, ColumnLayout, Expression, CalcAddCurr, IsFilter);
end;
end;
exit(Result);
end;
local procedure CalcCellValueInEvaluateExpression(IsAccSchedLineExpression: Boolean; AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; Expression: Text; CalcAddCurr: Boolean; IsFilter: Boolean) Result: Decimal
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCalcCellValueInEvaluateExpression(IsAccSchedLineExpression, AccSchedLine, ColumnLayout, Expression, CalcAddCurr, IsFilter, Result, IsHandled);
if IsHandled then
exit(Result);
if IsAccSchedLineExpression then
Result := CalcCellValueInAccSchedLines(AccSchedLine, ColumnLayout, Expression, CalcAddCurr, IsFilter)
else
Result := CalcCellValueInColumnLayouts(ColumnLayout, AccSchedLine, Expression, CalcAddCurr, IsFilter);
exit(Result);
end;
/// <summary>
/// Formats decimal values as text for display in account schedule reports with proper rounding and currency formatting.
/// Applies rounding factors, currency symbols, and percentage formatting based on column layout configuration.
/// </summary>
/// <param name="ColumnLayout2">Column layout containing formatting parameters including rounding factor and formula</param>
/// <param name="Value">Decimal value to format for display</param>
/// <param name="CalcAddCurr">Whether to apply additional currency formatting</param>
/// <returns>Formatted text representation of the value with applied formatting rules</returns>
procedure FormatCellAsText(var ColumnLayout2: Record "Column Layout"; Value: Decimal; CalcAddCurr: Boolean) ValueAsText: Text[30]
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeFormatCellAsText(ColumnLayout2, Value, IsHandled);
if IsHandled then
exit;
ValueAsText := MatrixMgt.FormatAmount(Value, ColumnLayout2."Rounding Factor", CalcAddCurr);
if (ValueAsText <> '') and
(ColumnLayout2."Column Type" = ColumnLayout2."Column Type"::Formula) and
(StrPos(ColumnLayout2.Formula, '%') > 1)
then
ValueAsText := ValueAsText + '%';
OnAfterFormatCellAsText(ColumnLayout2, ValueAsText, Value);
end;
/// <summary>
/// Returns the current division error status indicating if division by zero occurred during calculations.
/// Used for error handling and validation in account schedule formula processing.
/// </summary>
/// <returns>True if division by zero error was encountered, false otherwise</returns>
procedure GetDivisionError(): Boolean
begin
exit(DivisionError);
end;
/// <summary>
/// Returns the current period error status indicating if invalid date calculations occurred.
/// Used for error handling and validation in account schedule period processing.
/// </summary>
/// <returns>True if period calculation error was encountered, false otherwise</returns>
procedure GetPeriodError(): Boolean
begin
exit(PeriodError);
end;
/// <summary>
/// Displays detailed error messages for account schedule calculation failures with context information.
/// Shows the problematic account schedule line and column layout details to assist in debugging.
/// </summary>
/// <param name="MessageLine">Primary error message text describing the calculation failure</param>
/// <param name="AccSchedLine">Account schedule line context where the error occurred</param>
/// <param name="ColumnLayout">Column layout context where the error occurred</param>
procedure ShowError(MessageLine: Text; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
AccSchedLine.SetRange("Schedule Name", AccSchedLine."Schedule Name");
AccSchedLine.SetRange("Line No.", CallingAccSchedLineID);
if AccSchedLine.FindFirst() then;
ColumnLayout.SetRange("Column Layout Name", ColumnLayout."Column Layout Name");
ColumnLayout.SetRange("Line No.", CallingColumnLayoutID);
if ColumnLayout.FindFirst() then;
Error(Text016Err,
MessageLine,
Text017Txt,
StrSubstNo(Text018Txt, AccSchedLine."Row No.", AccSchedLine."Line No.", AccSchedLine.Totaling),
StrSubstNo(Text019Txt, ColumnLayout."Column No.", ColumnLayout."Line No.", ColumnLayout.Formula));
end;
/// <summary>
/// Opens G/L account selection dialog and inserts selected accounts as new account schedule lines.
/// Creates multiple lines based on user selection and maintains line numbering sequence.
/// </summary>
/// <param name="AccSchedLine">Account schedule line to use as insertion point for new G/L account lines</param>
procedure InsertGLAccounts(var AccSchedLine: Record "Acc. Schedule Line")
var
GLAcc: Record "G/L Account";
GLAccList: Page "G/L Account List";
AccCounter: Integer;
AccSchedLineNo: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeInsertGLAccounts(AccSchedLine, IsHandled);
if IsHandled then
exit;
GLAccList.LookupMode(true);
if GLAccList.RunModal() = ACTION::LookupOK then begin
GLAccList.SetSelection(GLAcc);
AccCounter := GLAcc.Count();
if AccCounter > 0 then begin
AccSchedLineNo := AccSchedLine."Line No.";
MoveAccSchedLines(AccSchedLine, AccCounter);
if GLAcc.FindSet() then
repeat
AccSchedLine.Init();
AccSchedLineNo := AccSchedLineNo + 10000;
AccSchedLine."Line No." := AccSchedLineNo;
AccSchedLine.Description := GLAcc.Name;
AccSchedLine.Validate(Indentation, GLAcc.Indentation);
AccSchedLine.Bold := GLAcc."Account Type" <> GLAcc."Account Type"::Posting;
if GLAcc."Account Type" in
[GLAcc."Account Type"::Posting, GLAcc."Account Type"::Total, GLAcc."Account Type"::"End-Total"]
then begin
AccSchedLine.Totaling := GLAcc."No.";
AccSchedLine."Row No." := CopyStr(GLAcc."No.", 1, MaxStrLen(AccSchedLine."Row No."));
end;
if GLAcc."Account Type" in
[GLAcc."Account Type"::Total, GLAcc."Account Type"::"End-Total"]
then
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Total Accounts"
else
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Posting Accounts";
OnInsertGLAccountsOnBeforeAccSchedLineInsert(AccSchedLine, GLAcc);
AccSchedLine.Insert();
until GLAcc.Next() = 0;
end;
end;
OnAfterInsertGLAccounts(AccSchedLine);
end;
/// <summary>
/// Opens cash flow account selection dialog and inserts selected accounts as new account schedule lines.
/// Creates multiple cash flow lines based on user selection with proper line numbering.
/// </summary>
/// <param name="AccSchedLine">Account schedule line to use as insertion point for new cash flow account lines</param>
procedure InsertCFAccounts(var AccSchedLine: Record "Acc. Schedule Line")
var
CashFlowAcc: Record "Cash Flow Account";
CashFlowAccList: Page "Cash Flow Account List";
AccCounter: Integer;
AccSchedLineNo: Integer;
begin
CashFlowAccList.LookupMode(true);
if CashFlowAccList.RunModal() = ACTION::LookupOK then begin
CashFlowAccList.SetSelection(CashFlowAcc);
AccCounter := CashFlowAcc.Count();
if AccCounter > 0 then begin
AccSchedLineNo := AccSchedLine."Line No.";
MoveAccSchedLines(AccSchedLine, AccCounter);
if CashFlowAcc.FindSet() then
repeat
AccSchedLine.Init();
AccSchedLineNo := AccSchedLineNo + 10000;
AccSchedLine."Line No." := AccSchedLineNo;
AccSchedLine.Description := CashFlowAcc.Name;
if CashFlowAcc."Account Type" in
[CashFlowAcc."Account Type"::Entry, CashFlowAcc."Account Type"::Total, CashFlowAcc."Account Type"::"End-Total"]
then begin
AccSchedLine.Totaling := CashFlowAcc."No.";
AccSchedLine."Row No." := CopyStr(CashFlowAcc."No.", 1, MaxStrLen(AccSchedLine."Row No."));
end;
if CashFlowAcc."Account Type" in
[CashFlowAcc."Account Type"::Total, CashFlowAcc."Account Type"::"End-Total"]
then
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Cash Flow Total Accounts"
else
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Cash Flow Entry Accounts";
AccSchedLine.Insert();
until CashFlowAcc.Next() = 0;
end;
end;
end;
/// <summary>
/// Opens cost type selection dialog and inserts selected cost types as new account schedule lines.
/// Creates multiple cost accounting lines based on user selection with appropriate totaling setup.
/// </summary>
/// <param name="AccSchedLine">Account schedule line to use as insertion point for new cost type lines</param>
procedure InsertCostTypes(var AccSchedLine: Record "Acc. Schedule Line")
var
CostType: Record "Cost Type";
CostTypeList: Page "Cost Type List";
AccCounter: Integer;
AccSchedLineNo: Integer;
begin
CostTypeList.LookupMode(true);
if CostTypeList.RunModal() = ACTION::LookupOK then begin
CostTypeList.SetSelection(CostType);
AccCounter := CostType.Count();
if AccCounter > 0 then begin
AccSchedLineNo := AccSchedLine."Line No.";
MoveAccSchedLines(AccSchedLine, AccCounter);
if CostType.FindSet() then
repeat
AccSchedLine.Init();
AccSchedLineNo := AccSchedLineNo + 10000;
AccSchedLine."Line No." := AccSchedLineNo;
AccSchedLine.Description := CostType.Name;
if CostType.Type in
[CostType.Type::"Cost Type", CostType.Type::Total, CostType.Type::"End-Total"]
then begin
AccSchedLine.Totaling := CostType."No.";
AccSchedLine."Row No." := CopyStr(CostType."No.", 1, MaxStrLen(AccSchedLine."Row No."));
end;
if CostType.Type in
[CostType.Type::Total, CostType.Type::"End-Total"]
then
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Cost Type Total"
else
AccSchedLine."Totaling Type" := AccSchedLine."Totaling Type"::"Cost Type";
AccSchedLine.Insert();
until CostType.Next() = 0;
end;
end;
end;
/// <summary>
/// Determines if an expression contains filter characters and should be processed as a filter rather than a direct value.
/// Checks for range operators, wildcards, and logical operators to identify filter expressions.
/// </summary>
/// <param name="Expression">Text expression to analyze for filter character patterns</param>
/// <returns>True if expression contains filter operators and should be treated as a filter</returns>
procedure IsExpressionFilter(Expression: Text) Result: Boolean
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeIsExpressionFilter(Expression, Result, IsHandled);
if IsHandled then
exit(Result);
exit(
StrPos(Expression, '..') +
StrPos(Expression, '|') +
StrPos(Expression, '<') +
StrPos(Expression, '>') +
StrPos(Expression, '&') +
StrPos(Expression, '=') > 0);
end;
local procedure ExchangeAmtAddCurrToLCY(AmountLCY: Decimal): Decimal
begin
GetGLSetup();
exit(
CurrExchRate.ExchangeAmtLCYToFCY(
WorkDate(), GLSetup."Additional Reporting Currency", AmountLCY,
CurrExchRate.ExchangeRate(WorkDate(), GLSetup."Additional Reporting Currency")));
end;
/// <summary>
/// Sets the current account schedule name for processing and calculations.
/// Updates the internal account schedule name reference used across calculation procedures.
/// </summary>
/// <param name="NewAccSchedName">Account schedule name record to set as current working schedule</param>
procedure SetAccSchedName(var NewAccSchedName: Record "Acc. Schedule Name")
begin
AccSchedName := NewAccSchedName;
end;
/// <summary>
/// Converts dimension totaling expressions into proper filter text for dimension filtering.
/// Processes dimension codes and totaling ranges to create valid dimension value filters.
/// </summary>
/// <param name="DimNo">Dimension number (1-4) to process totaling for</param>
/// <param name="DimTotaling">Dimension totaling expression containing codes and ranges</param>
/// <returns>Formatted filter text for dimension value filtering</returns>
procedure GetDimTotalingFilter(DimNo: Integer; DimTotaling: Text[250]): Text[1024]
var
DimTotaling2: Text[250];
DimTotalPart: Text[250];
ResultFilter: Text[1024];
ResultFilter2: Text[1024];
i: Integer;
begin
if DimTotaling = '' then
exit(DimTotaling);
DimTotaling2 := DimTotaling;
repeat
i := StrPos(DimTotaling2, '|');
if i > 0 then begin
DimTotalPart := CopyStr(DimTotaling2, 1, i - 1);
if i < StrLen(DimTotaling2) then
DimTotaling2 := CopyStr(DimTotaling2, i + 1)
else
DimTotaling2 := '';
end else
DimTotalPart := DimTotaling2;
ResultFilter2 := ConvDimTotalingFilter(DimNo, DimTotalPart);
if ResultFilter2 <> '' then
if StrLen(ResultFilter) + StrLen(ResultFilter2) + 1 > MaxStrLen(ResultFilter) then
Error(Text021, DimTotaling);
if ResultFilter <> '' then
ResultFilter := ResultFilter + '|';
ResultFilter := CopyStr(ResultFilter + ResultFilter2, 1, MaxStrLen(ResultFilter));
until i <= 0;
exit(ResultFilter);
end;
local procedure ConvDimTotalingFilter(DimNo: Integer; DimTotaling: Text[250]): Text[1024]
var
DimVal: Record "Dimension Value";
CostAccSetup: Record "Cost Accounting Setup";
DimCode: Code[20];
ResultFilter: Text[1024];
DimValTotaling: Boolean;
begin
GetCostAccSetup(CostAccSetup);
if DimTotaling = '' then
exit(DimTotaling);
CheckAnalysisView(AccSchedName.Name, '', false);
case DimNo of
1:
DimCode := AnalysisView."Dimension 1 Code";
2:
DimCode := AnalysisView."Dimension 2 Code";
3:
DimCode := AnalysisView."Dimension 3 Code";
4:
DimCode := AnalysisView."Dimension 4 Code";
5:
DimCode := CostAccSetup."Cost Center Dimension";
6:
DimCode := CostAccSetup."Cost Object Dimension";
else
OnConvDimTotalingFilterOnDimNoElseCase(DimNo, DimCode, AnalysisView, CostAccSetup);
end;
OnAfterGetConvDimCode(AnalysisView, DimCode);
if DimCode = '' then
exit(DimTotaling);
DimVal.SetRange("Dimension Code", DimCode);
DimVal.SetFilter(Code, DimTotaling);
if DimVal.Find('-') then
repeat
DimValTotaling :=
DimVal."Dimension Value Type" in
[DimVal."Dimension Value Type"::Total, DimVal."Dimension Value Type"::"End-Total"];
if DimValTotaling and (DimVal.Totaling <> '') then begin
if StrLen(ResultFilter) + StrLen(DimVal.Totaling) + 1 > MaxStrLen(ResultFilter) then
Error(Text021, DimTotaling);
if ResultFilter <> '' then
ResultFilter := ResultFilter + '|';
ResultFilter := ResultFilter + DimVal.Totaling;
end;
until (DimVal.Next() = 0) or not DimValTotaling;
if DimValTotaling then
exit(ResultFilter);
exit(DimTotaling);
end;
local procedure GetCostAccSetup(var CostAccSetup: Record "Cost Accounting Setup")
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeGetCostAccSetup(CostAccSetup, IsHandled);
if IsHandled then
exit;
if CostAccSetup.Get() then;
end;
/// <summary>
/// Calculates cost type values for account schedule line and column intersection with cost accounting integration.
/// Handles cost entry calculations, cost budget entries, and various amount types for cost accounting analysis.
/// </summary>
/// <param name="CostType">Cost Type record for calculation with applied filters</param>
/// <param name="AccSchedLine">Account schedule line containing cost type totaling configuration</param>
/// <param name="ColumnLayout">Column layout defining calculation parameters and date ranges</param>
/// <param name="CalcAddCurr">Whether to calculate using additional currency amounts</param>
/// <returns>Calculated decimal amount for the cost type account schedule cell</returns>
procedure CalcCostType(var CostType: Record "Cost Type"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean) ColValue: Decimal
var
CostEntry: Record "Cost Entry";
CostBudgEntry: Record "Cost Budget Entry";
AmountType: Enum "Account Schedule Amount Type";
UseDimFilter: Boolean;
TestBalance: Boolean;
Balance: Decimal;
IsHandled: Boolean;
begin
ColValue := 0;
IsHandled := false;
OnBeforeCalcCostType(CostType, AccSchedLine, ColumnLayout, CalcAddCurr, ColValue, IsHandled);
if IsHandled then
exit(ColValue);
if AccSchedName.Name <> AccSchedLine."Schedule Name" then
AccSchedName.Get(AccSchedLine."Schedule Name");
if ConflictAmountType(AccSchedLine, ColumnLayout."Amount Type", AmountType) then
exit(0);
TestBalance :=
AccSchedLine.Show in [AccSchedLine.Show::"When Positive Balance", AccSchedLine.Show::"When Negative Balance"];
if ColumnLayout."Column Type" <> ColumnLayout."Column Type"::Formula then begin
UseDimFilter := HasDimFilter(AccSchedLine, ColumnLayout) or HasCostDimFilter(AccSchedLine);
case ColumnLayout."Ledger Entry Type" of
ColumnLayout."Ledger Entry Type"::Entries:
begin
SetCostEntryFilters(CostType, CostEntry, AccSchedLine, ColumnLayout, UseDimFilter);
case AmountType of
AmountType::"Net Amount":
begin
if CalcAddCurr then begin
CostEntry.CalcSums("Additional-Currency Amount");
ColValue := CostEntry."Additional-Currency Amount";
end else begin
CostEntry.CalcSums(Amount);
ColValue := CostEntry.Amount;
end;
Balance := ColValue;
end;
AmountType::"Debit Amount":
if CalcAddCurr then begin
CostEntry.CalcSums("Add.-Currency Debit Amount", "Additional-Currency Amount");
if TestBalance then
Balance := CostEntry."Additional-Currency Amount";
ColValue := CostEntry."Add.-Currency Debit Amount";
end else begin
if TestBalance then begin
CostEntry.CalcSums("Debit Amount", Amount);
Balance := CostEntry.Amount;
end else
CostEntry.CalcSums("Debit Amount");
ColValue := CostEntry."Debit Amount";
end;
AmountType::"Credit Amount":
if CalcAddCurr then begin
CostEntry.CalcSums("Add.-Currency Credit Amount", "Additional-Currency Amount");
if TestBalance then
Balance := CostEntry."Additional-Currency Amount";
ColValue := CostEntry."Add.-Currency Credit Amount";
end else begin
if TestBalance then begin
CostEntry.CalcSums("Credit Amount", Amount);
Balance := CostEntry.Amount;
end else
CostEntry.CalcSums("Credit Amount");
ColValue := CostEntry."Credit Amount";
end;
end;
end;
ColumnLayout."Ledger Entry Type"::"Budget Entries":
begin
SetCostBudgetEntryFilters(CostType, CostBudgEntry, AccSchedLine, ColumnLayout);
CostBudgEntry.CalcSums(Amount);
case AmountType of
AmountType::"Net Amount":
ColValue := CostBudgEntry.Amount;
AmountType::"Debit Amount":
if CostBudgEntry.Amount > 0 then
ColValue := CostBudgEntry.Amount;
AmountType::"Credit Amount":
if CostBudgEntry.Amount < 0 then
ColValue := CostBudgEntry.Amount;
end;
Balance := CostBudgEntry.Amount;
if CalcAddCurr then
ColValue := CalcLCYToACY(ColValue);
end;
end;
if TestBalance then begin
if AccSchedLine.Show = AccSchedLine.Show::"When Positive Balance" then
if Balance < 0 then
exit(0);
if AccSchedLine.Show = AccSchedLine.Show::"When Negative Balance" then
if Balance > 0 then
exit(0);
end;
end;
exit(ColValue);
end;
local procedure SetCostEntryFilters(var CostType: Record "Cost Type"; var CostEntry: Record "Cost Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseDimFilter: Boolean)
begin
if UseDimFilter then
CostEntry.SetCurrentKey("Cost Type No.", "Cost Center Code", "Cost Object Code")
else
CostEntry.SetCurrentKey("Cost Type No.", "Posting Date");
if CostType.Totaling = '' then
CostEntry.SetRange("Cost Type No.", CostType."No.")
else
CostEntry.SetFilter("Cost Type No.", CostType.Totaling);
CostType.CopyFilter("Date Filter", CostEntry."Posting Date");
AccSchedLine.CopyFilter("Cost Center Filter", CostEntry."Cost Center Code");
AccSchedLine.CopyFilter("Cost Object Filter", CostEntry."Cost Object Code");
CostEntry.FilterGroup(2);
CostEntry.SetFilter("Cost Center Code", GetDimTotalingFilter(5, AccSchedLine."Cost Center Totaling"));
CostEntry.SetFilter("Cost Object Code", GetDimTotalingFilter(6, AccSchedLine."Cost Object Totaling"));
CostEntry.FilterGroup(8);
CostEntry.SetFilter("Cost Center Code", GetDimTotalingFilter(5, ColumnLayout."Cost Center Totaling"));
CostEntry.SetFilter("Cost Object Code", GetDimTotalingFilter(6, ColumnLayout."Cost Object Totaling"));
CostEntry.FilterGroup(0);
OnAfterSetCostEntryFilters(CostType, CostEntry, AccSchedLine, ColumnLayout, UseDimFilter);
end;
local procedure SetCostBudgetEntryFilters(var CostType: Record "Cost Type"; var CostBudgetEntry: Record "Cost Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
CostBudgetEntry.SetCurrentKey("Budget Name", "Cost Type No.", "Cost Center Code", "Cost Object Code", Date);
if CostType.Totaling = '' then
CostBudgetEntry.SetRange("Cost Type No.", CostType."No.")
else
CostBudgetEntry.SetFilter("Cost Type No.", CostType.Totaling);
CostType.CopyFilter("Date Filter", CostBudgetEntry.Date);
AccSchedLine.CopyFilter("Cost Budget Filter", CostBudgetEntry."Budget Name");
AccSchedLine.CopyFilter("Cost Center Filter", CostBudgetEntry."Cost Center Code");
AccSchedLine.CopyFilter("Cost Object Filter", CostBudgetEntry."Cost Object Code");
CostBudgetEntry.FilterGroup(2);
CostBudgetEntry.SetFilter("Cost Center Code", GetDimTotalingFilter(5, AccSchedLine."Cost Center Totaling"));
CostBudgetEntry.SetFilter("Cost Object Code", GetDimTotalingFilter(6, AccSchedLine."Cost Object Totaling"));
CostBudgetEntry.FilterGroup(8);
CostBudgetEntry.SetFilter("Cost Center Code", GetDimTotalingFilter(5, ColumnLayout."Cost Center Totaling"));
CostBudgetEntry.SetFilter("Cost Object Code", GetDimTotalingFilter(6, ColumnLayout."Cost Object Totaling"));
CostBudgetEntry.FilterGroup(0);
OnAfterSetCostBudgetEntryFilters(CostType, CostBudgetEntry, AccSchedLine, ColumnLayout);
end;
/// <summary>
/// Applies row-level filters to Cost Type record based on account schedule line configuration.
/// Sets cost type number filters, type filters, and cost center/object filters for cost accounting calculations.
/// </summary>
/// <param name="CostType">Cost Type record to apply filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing cost type totaling and filter specifications</param>
/// <param name="ColumnLayout">Column layout containing additional cost accounting filter parameters</param>
procedure SetCostTypeRowFilters(var CostType: Record "Cost Type"; var AccSchedLine2: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
case AccSchedLine2."Totaling Type" of
AccSchedLine2."Totaling Type"::"Cost Type":
begin
CostType.SetFilter("No.", AccSchedLine2.Totaling);
CostType.SetRange(Type, CostType.Type::"Cost Type");
end;
AccSchedLine2."Totaling Type"::"Cost Type Total":
begin
CostType.SetFilter("No.", AccSchedLine2.Totaling);
CostType.SetFilter(Type, '<>%1', CostType.Type::"Cost Type");
end;
end;
CostType.SetFilter("Cost Center Filter", AccSchedLine2.GetFilter("Cost Center Filter"));
CostType.SetFilter("Cost Object Filter", AccSchedLine2.GetFilter("Cost Object Filter"));
if ColumnLayout."Ledger Entry Type" = ColumnLayout."Ledger Entry Type"::"Budget Entries" then
CostType.SetFilter("Budget Filter", AccSchedLine2.GetFilter("Cost Budget Filter"));
OnAfterSetCostTypeRowFilters(CostType, AccSchedLine2);
end;
/// <summary>
/// Applies column-level date filters to Cost Type record based on column layout and row type configuration.
/// Handles cost accounting date range filtering for different column types and row calculations.
/// </summary>
/// <param name="CostType">Cost Type record to apply column-based date filters to</param>
/// <param name="AccSchedLine2">Account schedule line containing row type specification for date filter logic</param>
/// <param name="ColumnLayout">Column layout containing column type and date calculation parameters</param>
procedure SetCostTypeColumnFilters(var CostType: Record "Cost Type"; AccSchedLine2: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
var
FromDate: Date;
ToDate: Date;
FiscalStartDate2: Date;
begin
CalcColumnDates(ColumnLayout, FromDate, ToDate, FiscalStartDate2);
case ColumnLayout."Column Type" of
ColumnLayout."Column Type"::"Net Change":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CostType.SetRange("Date Filter", FromDate, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CostType.SetFilter("Date Filter", '<%1', FromDate);
AccSchedLine2."Row Type"::"Balance at Date":
CostType.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout."Column Type"::"Balance at Date":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Beginning Balance" then
CostType.SetRange("Date Filter", 0D)
// Force a zero return
else
CostType.SetRange("Date Filter", 0D, ToDate);
ColumnLayout."Column Type"::"Beginning Balance":
if AccSchedLine2."Row Type" = AccSchedLine2."Row Type"::"Balance at Date" then
CostType.SetRange("Date Filter", 0D)
// Force a zero return
else
CostType.SetRange(
"Date Filter", 0D, CalcDate('<-1D>', FromDate));
ColumnLayout."Column Type"::"Year to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CostType.SetRange("Date Filter", FiscalStartDate2, ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CostType.SetFilter("Date Filter", '<%1', FiscalStartDate2);
AccSchedLine2."Row Type"::"Balance at Date":
CostType.SetRange("Date Filter", 0D, ToDate);
end;
ColumnLayout."Column Type"::"Rest of Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CostType.SetRange(
"Date Filter", CalcDate('<+1D>', ToDate), AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
CostType.SetRange("Date Filter", 0D, ToDate);
AccSchedLine2."Row Type"::"Balance at Date":
CostType.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout."Column Type"::"Entire Fiscal Year":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CostType.SetRange(
"Date Filter", FiscalStartDate2, AccountingPeriodMgt.FindEndOfFiscalYear(FiscalStartDate2));
AccSchedLine2."Row Type"::"Beginning Balance":
CostType.SetFilter("Date Filter", '<%1', FiscalStartDate2);
AccSchedLine2."Row Type"::"Balance at Date":
CostType.SetRange("Date Filter", 0D, AccountingPeriodMgt.FindEndOfFiscalYear(ToDate));
end;
ColumnLayout."Column Type"::"Month to Date":
case AccSchedLine2."Row Type" of
AccSchedLine2."Row Type"::"Net Change":
CostType.SetRange("Date Filter", CalcDate('<-CM>', ToDate), ToDate);
AccSchedLine2."Row Type"::"Beginning Balance":
CostType.SetFilter("Date Filter", '<%1', ClosingDate(CalcDate('<-CM>', ToDate) - 1));
AccSchedLine2."Row Type"::"Balance at Date":
CostType.SetRange("Date Filter", 0D, ToDate);
end;
end;
OnAfterSetCostTypeColumnFilters(CostType, AccSchedLine2, ColumnLayout);
end;
/// <summary>
/// Determines if dimension filtering is active on either account schedule line or column layout.
/// Checks dimension totaling fields and dimension filters to identify multi-dimensional analysis requirements.
/// </summary>
/// <param name="AccSchedLine">Account schedule line to check for dimension totaling and filters</param>
/// <param name="ColumnLayout">Column layout to check for dimension totaling specifications</param>
/// <returns>True if any dimension filtering is configured, false if no dimensional analysis is required</returns>
procedure HasDimFilter(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout") Result: Boolean
begin
Result := (AccSchedLine."Dimension 1 Totaling" <> '') or
(AccSchedLine."Dimension 2 Totaling" <> '') or
(AccSchedLine."Dimension 3 Totaling" <> '') or
(AccSchedLine."Dimension 4 Totaling" <> '') or
(AccSchedLine.GetFilter("Dimension 1 Filter") <> '') or
(AccSchedLine.GetFilter("Dimension 2 Filter") <> '') or
(AccSchedLine.GetFilter("Dimension 3 Filter") <> '') or
(AccSchedLine.GetFilter("Dimension 4 Filter") <> '') or
(ColumnLayout."Dimension 1 Totaling" <> '') or
(ColumnLayout."Dimension 2 Totaling" <> '') or
(ColumnLayout."Dimension 3 Totaling" <> '') or
(ColumnLayout."Dimension 4 Totaling" <> '') or
(ColumnLayout."Cost Center Totaling" <> '') or
(ColumnLayout."Cost Object Totaling" <> '');
OnAfterHasDimFilter(AccSchedLine, ColumnLayout, Result);
end;
local procedure HasCostDimFilter(var AccSchedLine: Record "Acc. Schedule Line") Result: Boolean
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeHasCostDimFilter(AccSchedLine, Result, IsHandled);
if IsHandled then
exit(Result);
exit((AccSchedLine."Cost Center Totaling" <> '') or
(AccSchedLine."Cost Object Totaling" <> '') or
(AccSchedLine.GetFilter("Cost Center Filter") <> '') or
(AccSchedLine.GetFilter("Cost Object Filter") <> ''));
end;
/// <summary>
/// Calculates date ranges for column layout based on comparison date formulas and period formulas.
/// Processes relative date calculations and fiscal period adjustments for financial reporting.
/// </summary>
/// <param name="ColumnLayout">Column layout containing date calculation formulas and parameters</param>
/// <param name="FromDate">Calculated start date returned for the column period</param>
/// <param name="ToDate">Calculated end date returned for the column period</param>
/// <param name="FiscalStartDate2">Fiscal year start date used for period calculations</param>
procedure CalcColumnDates(ColumnLayout: Record "Column Layout"; var FromDate: Date; var ToDate: Date; var FiscalStartDate2: Date)
var
ComparisonDateFormula: DateFormula;
ComparisonPeriodFormula: Code[20];
begin
ComparisonDateFormula := ColumnLayout."Comparison Date Formula";
ComparisonPeriodFormula := ColumnLayout."Comparison Period Formula";
if (Format(ComparisonDateFormula) <> '0') and (Format(ComparisonDateFormula) <> '') then begin
FromDate := CalcDate(ComparisonDateFormula, StartDate);
ToDate := CalcDate(ComparisonDateFormula, EndDate);
if (StartDate = CalcDate('<-CM>', StartDate)) and
(FromDate = CalcDate('<-CM>', FromDate)) and
(EndDate = CalcDate('<CM>', EndDate))
then
ToDate := CalcDate('<CM>', ToDate);
FiscalStartDate2 := AccountingPeriodMgt.FindFiscalYear(ToDate);
end else
if ComparisonPeriodFormula <> '' then begin
AccPeriodStartEnd(ColumnLayout, StartDate, FromDate, ToDate);
FiscalStartDate2 := AccountingPeriodMgt.FindFiscalYear(ToDate);
end else begin
FromDate := StartDate;
ToDate := EndDate;
FiscalStartDate2 := FiscalStartDate;
end;
OnAfterCalcColumnDates(ColumnLayout, FromDate, ToDate, FiscalStartDate2, PeriodError);
end;
/// <summary>
/// Moves account schedule lines within a schedule to create space for insertions or reorganization.
/// Adjusts line numbers by shifting subsequent lines to maintain proper ordering.
/// </summary>
/// <param name="AccSchedLine">Account schedule line record used to identify the schedule and position</param>
/// <param name="Place">Number of line positions to shift (positive moves lines down, negative moves up)</param>
procedure MoveAccSchedLines(var AccSchedLine: Record "Acc. Schedule Line"; Place: Integer)
var
AccSchedLineNo: Integer;
I: Integer;
begin
AccSchedLineNo := AccSchedLine."Line No.";
AccSchedLine.SetRange("Schedule Name", AccSchedLine."Schedule Name");
if AccSchedLine.Find('+') then
repeat
I := AccSchedLine."Line No.";
if I > AccSchedLineNo then begin
AccSchedLine.Delete();
OnMoveAccSchedLinesOnAfterAccSchedLineDelete(AccSchedLine, Place);
AccSchedLine."Line No." := I + 10000 * Place;
AccSchedLine.Insert();
OnAfterAccSchedLineInsert(AccSchedLine);
end;
until (I <= AccSchedLineNo) or (AccSchedLine.Next(-1) = 0);
end;
/// <summary>
/// Sets the global start and end date range for account schedule calculations.
/// Updates the internal date variables used across all calculation procedures.
/// </summary>
/// <param name="NewStartDate">Start date for the calculation period</param>
/// <param name="NewEndDate">End date for the calculation period</param>
procedure SetStartDateEndDate(NewStartDate: Date; NewEndDate: Date)
begin
StartDate := NewStartDate;
EndDate := NewEndDate;
end;
/// <summary>
/// Retrieves the current global start and end date range used for account schedule calculations.
/// Returns the internal date variables set through SetStartDateEndDate procedure.
/// </summary>
/// <param name="OutputStartDate">Returns the current calculation period start date</param>
/// <param name="OutputEndDate">Returns the current calculation period end date</param>
procedure GetStartDateEndDate(var OutputStartDate: Date; var OutputEndDate: Date)
begin
OutputStartDate := StartDate;
OutputEndDate := EndDate;
end;
/// <summary>
/// Determines if there is a conflict between account schedule line and column layout amount types.
/// Resolves amount type precedence and returns the effective amount type for calculations.
/// </summary>
/// <param name="AccSchedLine">Account schedule line with specified amount type configuration</param>
/// <param name="ColumnLayoutAmtType">Column layout amount type to compare and resolve conflicts with</param>
/// <param name="AmountType">Returns the resolved amount type to use for calculations</param>
/// <returns>True if there was a conflict that prevents calculation, false if amount types are compatible</returns>
procedure ConflictAmountType(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayoutAmtType: Enum "Account Schedule Amount Type"; var AmountType: Enum "Account Schedule Amount Type"): Boolean
begin
if (ColumnLayoutAmtType = AccSchedLine."Amount Type") or
(AccSchedLine."Amount Type" = AccSchedLine."Amount Type"::"Net Amount")
then
AmountType := ColumnLayoutAmtType
else
if ColumnLayoutAmtType = ColumnLayoutAmtType::"Net Amount" then
AmountType := AccSchedLine."Amount Type"
else
exit(true);
exit(false);
end;
/// <summary>
/// Opens drill-down detail view for account schedule line and column intersection.
/// Navigates to appropriate ledger entries or detail pages based on source type.
/// </summary>
/// <param name="TempColumnLayout">Column layout containing period and display parameters</param>
/// <param name="AccScheduleLine">Account schedule line containing totaling and filter settings</param>
/// <param name="PeriodLength">Period length option for date calculations</param>
procedure DrillDown(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; PeriodLength: Option)
var
AccScheduleOverview: Page "Acc. Schedule Overview";
ErrorType: Option "None","Division by Zero","Period Error",Both;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDrillDown(TempColumnLayout, AccScheduleLine, PeriodLength, IsHandled);
if IsHandled then
exit;
if TempColumnLayout."Column Type" = TempColumnLayout."Column Type"::Formula then begin
CalcFieldError(ErrorType, AccScheduleLine."Line No.", TempColumnLayout."Line No.");
if ErrorType <> ErrorType::None then
Message(StrSubstNo(ColumnFormulaErrorMsg, TempColumnLayout.Formula, Format(ErrorType)))
else
Message(ColumnFormulaMsg, TempColumnLayout.Formula);
exit;
end;
if AccScheduleLine."Totaling Type" in [AccScheduleLine."Totaling Type"::Formula, AccScheduleLine."Totaling Type"::"Set Base For Percent"] then begin
AccScheduleOverview.SetAccSchedName(AccScheduleLine."Schedule Name");
AccScheduleOverview.SetColumnDefinition(TempColumnLayout."Column Layout Name");
AccScheduleOverview.SetTableView(AccScheduleLine);
AccScheduleOverview.SetRecord(AccScheduleLine);
AccScheduleOverview.SetViewOnlyMode(true);
AccScheduleOverview.SetPeriodType(PeriodLength);
AccScheduleOverview.Run();
exit;
end;
OnBeforeDrillDownOnAccounts(AccScheduleLine, TempColumnLayout, PeriodLength, StartDate, EndDate);
if AccScheduleLine.Totaling = '' then
exit;
case AccScheduleLine."Totaling Type" of
AccScheduleLine."Totaling Type"::"Posting Accounts", AccScheduleLine."Totaling Type"::"Total Accounts",
AccScheduleLine."Totaling Type"::"Cost Type", AccScheduleLine."Totaling Type"::"Cost Type Total":
DrillDownOnGLAccount(TempColumnLayout, AccScheduleLine);
AccScheduleLine."Totaling Type"::"Cash Flow Entry Accounts",
AccScheduleLine."Totaling Type"::"Cash Flow Total Accounts":
DrillDownOnCFAccount(TempColumnLayout, AccScheduleLine);
AccScheduleLine."Totaling Type"::"Account Category":
DrillDownOnGLAccCategory(TempColumnLayout, AccScheduleLine);
else
OnDrillDownTotalingTypeElseCase(TempColumnLayout, AccScheduleLine);
end;
end;
/// <summary>
/// Handles drill-down navigation from account schedule overview page.
/// Provides formula information display or navigates to detailed data views.
/// </summary>
/// <param name="TempColumnLayout">Column layout containing formula and display configuration</param>
/// <param name="AccScheduleLine">Account schedule line with totaling type and calculation settings</param>
/// <param name="PeriodLength">Period length option for date range calculations</param>
procedure DrillDownFromOverviewPage(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; PeriodLength: Option)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDrillDownFromOverviewPage(TempColumnLayout, AccScheduleLine, PeriodLength, IsHandled);
if IsHandled then
exit;
if (AccScheduleLine."Totaling Type" = AccScheduleLine."Totaling Type"::Formula) and
(TempColumnLayout."Column Type" = TempColumnLayout."Column Type"::Formula)
then
Message(RowFormulaMsg, TempColumnLayout.Formula)
else
if AccScheduleLine."Totaling Type" in [AccScheduleLine."Totaling Type"::Formula, AccScheduleLine."Totaling Type"::"Set Base For Percent"] then
Message(RowFormulaMsg, AccScheduleLine.Totaling)
else
DrillDown(TempColumnLayout, AccScheduleLine, PeriodLength);
end;
/// <summary>
/// Generates formatted text representation of G/L Account Categories for account schedule line totaling.
/// Creates pipe-separated list of account category descriptions for display and reporting purposes.
/// </summary>
/// <param name="AccScheduleLine">Account schedule line containing G/L account category totaling</param>
/// <returns>Formatted text containing account category names separated by pipe characters</returns>
procedure GLAccCategoryText(AccScheduleLine: Record "Acc. Schedule Line"): Text[250]
var
GLAccountCategory: Record "G/L Account Category";
CategoriesList: Text[250];
begin
CategoriesList := '';
if AccScheduleLine.Totaling = '' then
exit(CategoriesList);
GLAccountCategory.SetFilter("Entry No.", AccScheduleLine.Totaling);
if GLAccountCategory.FindSet() then
repeat
if CategoriesList <> '' then
CategoriesList := CopyStr(CategoriesList + '|', 1, 250);
CategoriesList := CopyStr(CategoriesList + GLAccountCategory.Description, 1, 250);
until GLAccountCategory.Next() = 0;
exit(CategoriesList);
end;
local procedure DrillDownOnGlAccCategory(TempColumnLayout: Record "Column Layout" temporary; var AccSchedLine: Record "Acc. Schedule Line")
var
GLAccountCategory: Record "G/L Account Category";
GLAccCategoriesToVisit: Record "G/L Acc. Cat. Buffer";
GLAccCategoriesVisited: Record "G/L Acc. Cat. Buffer";
GLAccCatCode: Integer;
CatsFilter: Text;
begin
AccSchedLine.CopyFilters(AccountScheduleLine);
GLAccountCategory.SetFilter("Entry No.", AccSchedLine.Totaling);
if GLAccountCategory.FindSet() then
repeat
GLAccCategoriesToVisit."Entry No." := GLAccountCategory."Entry No.";
GLAccCategoriesToVisit.Insert();
until GLAccountCategory.Next() = 0;
CatsFilter := '';
while GLAccCategoriesToVisit.Count() > 0 do begin
GLAccCategoriesToVisit.FindFirst();
GLAccCatCode := GLAccCategoriesToVisit."Entry No.";
if CatsFilter = '' then
CatsFilter := format(GLAccCatCode)
else
CatsFilter := CatsFilter + '|' + format(GLAccCatCode);
GLAccCategoriesVisited."Entry No." := GLAccCatCode;
GLAccCategoriesVisited.Insert();
GLAccountCategory.Reset();
GLAccountCategory.SetRange("Parent Entry No.", GLAccCatCode);
if GLAccountCategory.FindSet() then
repeat
if (not GLAccCategoriesVisited.Get(GLAccountCategory."Entry No.")) and (not GLAccCategoriesToVisit.Get(GLAccountCategory."Entry No.")) then begin
GLAccCategoriesToVisit."Entry No." := GLAccountCategory."Entry No.";
GLAccCategoriesToVisit.Insert();
end;
until GLAccountCategory.Next() = 0;
GLAccCategoriesToVisit."Entry No." := GLAccCatCode;
GLAccCategoriesToVisit.Delete();
end;
DrillDownOnGLAccCatFilter(TempColumnLayout, AccSchedLine, CatsFilter);
end;
local procedure DrillDownOnGLAccCatFilter(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; SubcategoryEntryFilter: Text)
var
GLAcc: Record "G/L Account";
GLAccAnalysisView: Record "G/L Account (Analysis View)";
CostType: Record "Cost Type";
ChartOfAccsAnalysisView: Page "Chart of Accs. (Analysis View)";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeDrillDownOnGLAccount(TempColumnLayout, AccScheduleLine, IsHandled);
if IsHandled then
exit;
if AccScheduleLine."Totaling Type" in [AccScheduleLine."Totaling Type"::"Cost Type", AccScheduleLine."Totaling Type"::"Cost Type Total"] then begin
SetCostTypeRowFilters(CostType, AccScheduleLine, TempColumnLayout);
SetCostTypeColumnFilters(CostType, AccScheduleLine, TempColumnLayout);
AccScheduleLine.CopyFilter("Cost Center Filter", CostType."Cost Center Filter");
AccScheduleLine.CopyFilter("Cost Object Filter", CostType."Cost Object Filter");
AccScheduleLine.CopyFilter("Cost Budget Filter", CostType."Budget Filter");
CostType.FilterGroup(2);
CostType.SetFilter("Cost Center Filter", GetDimTotalingFilter(1, AccScheduleLine."Cost Center Totaling"));
CostType.SetFilter("Cost Object Filter", GetDimTotalingFilter(1, AccScheduleLine."Cost Object Totaling"));
CostType.FilterGroup(8);
CostType.SetFilter("Cost Center Filter", GetDimTotalingFilter(1, TempColumnLayout."Cost Center Totaling"));
CostType.SetFilter("Cost Object Filter", GetDimTotalingFilter(1, TempColumnLayout."Cost Object Totaling"));
CostType.FilterGroup(0);
PAGE.Run(PAGE::"Chart of Cost Types", CostType);
end else begin
AccScheduleLine.CopyFilter("Business Unit Filter", GLAcc."Business Unit Filter");
if TempColumnLayout."Ledger Entry Type" = TempColumnLayout."Ledger Entry Type"::"Budget Entries" then begin
if TempColumnLayout."Budget Name" <> '' then
GLAcc.SetRange("Budget Filter", TempColumnLayout."Budget Name")
else
AccScheduleLine.CopyFilter("G/L Budget Filter", GLAcc."Budget Filter");
end else
AccScheduleLine.CopyFilter("G/L Budget Filter", GLAcc."Budget Filter");
SetGLAccRowFilters(GLAcc, AccScheduleLine);
SetGLAccColumnFilters(GLAcc, AccScheduleLine, TempColumnLayout);
AccSchedName.Get(AccScheduleLine."Schedule Name");
if AccSchedName."Analysis View Name" = '' then begin
OnDrillDownOnGLAccountOnBeforeCopyFiltersEmptyAnalysisViewName(AccScheduleLine, TempColumnLayout, GLAcc);
AccScheduleLine.CopyFilter("Dimension 1 Filter", GLAcc."Global Dimension 1 Filter");
AccScheduleLine.CopyFilter("Dimension 2 Filter", GLAcc."Global Dimension 2 Filter");
AccScheduleLine.CopyFilter("Business Unit Filter", GLAcc."Business Unit Filter");
GLAcc.FilterGroup(2);
OnDrillDownOnGLAccCatFilterOnAfterGLAccSetFilterGroup2(AccScheduleLine, GLAcc);
GLAcc.SetFilter("Global Dimension 1 Filter", GetDimTotalingFilter(1, AccScheduleLine."Dimension 1 Totaling"));
GLAcc.SetFilter("Global Dimension 2 Filter", GetDimTotalingFilter(2, AccScheduleLine."Dimension 2 Totaling"));
GLAcc.FilterGroup(8);
GLAcc.SetFilter("Business Unit Filter", TempColumnLayout."Business Unit Totaling");
GLAcc.SetFilter("Global Dimension 1 Filter", GetDimTotalingFilter(1, TempColumnLayout."Dimension 1 Totaling"));
GLAcc.SetFilter("Global Dimension 2 Filter", GetDimTotalingFilter(2, TempColumnLayout."Dimension 2 Totaling"));
if TempColumnLayout."G/L Account Totaling" <> '' then
GLAcc.SetFilter("No.", TempColumnLayout."G/L Account Totaling");
if SubcategoryEntryFilter <> '' then begin
GlAcc.SetRange("Account Type", GlAcc."Account Type"::Posting);
GLAcc.SetFilter("Account Subcategory Entry No.", SubcategoryEntryFilter);
end;
GLAcc.FilterGroup(0);
PAGE.Run(PAGE::"Chart of Accounts (G/L)", GLAcc)
end else begin
OnDrillDownOnGLAccountOnBeforeCopyFiltersWithAnalysisView(AccScheduleLine, TempColumnLayout, GLAcc, GLAccAnalysisView);
GLAcc.CopyFilter("Date Filter", GLAccAnalysisView."Date Filter");
GLAcc.CopyFilter("Budget Filter", GLAccAnalysisView."Budget Filter");
GLAcc.CopyFilter("Business Unit Filter", GLAccAnalysisView."Business Unit Filter");
GLAccAnalysisView.SetRange("Analysis View Filter", AccSchedName."Analysis View Name");
GLAccAnalysisView.CopyDimFilters(AccScheduleLine);
GLAccAnalysisView.FilterGroup(2);
GLAccAnalysisView.SetDimFilters(
GetDimTotalingFilter(1, AccScheduleLine."Dimension 1 Totaling"), GetDimTotalingFilter(2, AccScheduleLine."Dimension 2 Totaling"),
GetDimTotalingFilter(3, AccScheduleLine."Dimension 3 Totaling"), GetDimTotalingFilter(4, AccScheduleLine."Dimension 4 Totaling"));
GLAccAnalysisView.FilterGroup(8);
GLAccAnalysisView.SetDimFilters(
GetDimTotalingFilter(1, TempColumnLayout."Dimension 1 Totaling"),
GetDimTotalingFilter(2, TempColumnLayout."Dimension 2 Totaling"),
GetDimTotalingFilter(3, TempColumnLayout."Dimension 3 Totaling"),
GetDimTotalingFilter(4, TempColumnLayout."Dimension 4 Totaling"));
GLAccAnalysisView.SetFilter("Business Unit Filter", TempColumnLayout."Business Unit Totaling");
if TempColumnLayout."G/L Account Totaling" <> '' then begin
GLAccAnalysisView.SetFilter("No.", TempColumnLayout."G/L Account Totaling");
GLAcc.SetFilter("No.", TempColumnLayout."G/L Account Totaling");
end;
if SubcategoryEntryFilter <> '' then begin
GlAcc.SetRange("Account Type", GlAcc."Account Type"::Posting);
GLAcc.SetFilter("Account Subcategory Entry No.", SubcategoryEntryFilter);
end;
GLAccAnalysisView.FilterGroup(0);
Clear(ChartOfAccsAnalysisView);
ChartOfAccsAnalysisView.InsertTempGLAccAnalysisViews(GLAcc);
ChartOfAccsAnalysisView.SetTableView(GLAccAnalysisView);
ChartOfAccsAnalysisView.Run();
end;
end;
end;
/// <summary>
/// Opens drill-down view for G/L account totaling in account schedule line.
/// Navigates to General Ledger Entries filtered by account schedule parameters.
/// </summary>
/// <param name="TempColumnLayout">Column layout containing period and filter settings</param>
/// <param name="AccScheduleLine">Account schedule line containing G/L account totaling</param>
procedure DrillDownOnGLAccount(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line")
begin
DrillDownOnGLAccCatFilter(TempColumnLayout, AccScheduleLine, '');
end;
/// <summary>
/// Opens drill-down view for cash flow account totaling in account schedule line.
/// Navigates to Cash Flow Ledger Entries filtered by account schedule parameters.
/// </summary>
/// <param name="TempColumnLayout">Column layout containing period and filter settings</param>
/// <param name="AccScheduleLine">Account schedule line containing cash flow account totaling</param>
procedure DrillDownOnCFAccount(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line")
var
CFAccount: Record "Cash Flow Account";
GLAccAnalysisView: Record "G/L Account (Analysis View)";
ChartOfAccsAnalysisView: Page "Chart of Accs. (Analysis View)";
begin
AccScheduleLine.CopyFilter("Cash Flow Forecast Filter", CFAccount."Cash Flow Forecast Filter");
SetCFAccRowFilter(CFAccount, AccScheduleLine);
SetCFAccColumnFilter(CFAccount, AccScheduleLine, TempColumnLayout);
AccSchedName.Get(AccScheduleLine."Schedule Name");
if AccSchedName."Analysis View Name" = '' then begin
AccScheduleLine.CopyFilter("Dimension 1 Filter", CFAccount."Global Dimension 1 Filter");
AccScheduleLine.CopyFilter("Dimension 2 Filter", CFAccount."Global Dimension 2 Filter");
CFAccount.FilterGroup(2);
CFAccount.SetFilter("Global Dimension 1 Filter", GetDimTotalingFilter(1, AccScheduleLine."Dimension 1 Totaling"));
CFAccount.SetFilter("Global Dimension 2 Filter", GetDimTotalingFilter(2, AccScheduleLine."Dimension 2 Totaling"));
CFAccount.FilterGroup(8);
CFAccount.SetFilter("Global Dimension 1 Filter", GetDimTotalingFilter(1, TempColumnLayout."Dimension 1 Totaling"));
CFAccount.SetFilter("Global Dimension 2 Filter", GetDimTotalingFilter(2, TempColumnLayout."Dimension 2 Totaling"));
CFAccount.FilterGroup(0);
PAGE.Run(PAGE::"Chart of Cash Flow Accounts", CFAccount)
end else begin
CFAccount.CopyFilter("Date Filter", GLAccAnalysisView."Date Filter");
CFAccount.CopyFilter("Cash Flow Forecast Filter", GLAccAnalysisView."Cash Flow Forecast Filter");
GLAccAnalysisView.SetRange("Analysis View Filter", AccSchedName."Analysis View Name");
GLAccAnalysisView.CopyDimFilters(AccScheduleLine);
GLAccAnalysisView.FilterGroup(2);
GLAccAnalysisView.SetDimFilters(
GetDimTotalingFilter(1, AccScheduleLine."Dimension 1 Totaling"),
GetDimTotalingFilter(2, AccScheduleLine."Dimension 2 Totaling"),
GetDimTotalingFilter(3, AccScheduleLine."Dimension 3 Totaling"),
GetDimTotalingFilter(4, AccScheduleLine."Dimension 4 Totaling"));
GLAccAnalysisView.FilterGroup(8);
GLAccAnalysisView.SetDimFilters(
GetDimTotalingFilter(1, TempColumnLayout."Dimension 1 Totaling"),
GetDimTotalingFilter(2, TempColumnLayout."Dimension 2 Totaling"),
GetDimTotalingFilter(3, TempColumnLayout."Dimension 3 Totaling"),
GetDimTotalingFilter(4, TempColumnLayout."Dimension 4 Totaling"));
GLAccAnalysisView.FilterGroup(0);
Clear(ChartOfAccsAnalysisView);
ChartOfAccsAnalysisView.InsertTempCFAccountAnalysisVie(CFAccount);
ChartOfAccsAnalysisView.SetTableView(GLAccAnalysisView);
ChartOfAccsAnalysisView.Run();
end;
end;
/// <summary>
/// Navigates to a specific period within account schedule lines based on search text and period type.
/// Updates the date filter on the account schedule line to match the found period.
/// </summary>
/// <param name="AccScheduleLine">Account schedule line to update with period date filter</param>
/// <param name="SearchText">Navigation text ('+', '-', or specific date pattern) for period search</param>
/// <param name="PeriodType">Type of period for navigation (Day, Week, Month, Quarter, Year)</param>
procedure FindPeriod(var AccScheduleLine: Record "Acc. Schedule Line"; SearchText: Text[3]; PeriodType: Enum "Analysis Period Type")
var
Calendar: Record Date;
PeriodPageMgt: Codeunit PeriodPageManagement;
begin
if AccScheduleLine.GetFilter("Date Filter") <> '' then begin
Calendar.SetFilter("Period Start", AccScheduleLine.GetFilter("Date Filter"));
if not PeriodPageMgt.FindDate('+', Calendar, PeriodType) then
PeriodPageMgt.FindDate('+', Calendar, PeriodType::Day);
Calendar.SetRange("Period Start");
end;
PeriodPageMgt.FindDate(SearchText, Calendar, PeriodType);
AccScheduleLine.SetRange("Date Filter", Calendar."Period Start", Calendar."Period End");
if AccScheduleLine.GetRangeMin("Date Filter") = AccScheduleLine.GetRangeMax("Date Filter") then
AccScheduleLine.SetRange("Date Filter", AccScheduleLine.GetRangeMin("Date Filter"));
end;
/// <summary>
/// Determines calculation error type for specific account schedule cell intersection.
/// Checks for division by zero errors and period calculation problems.
/// </summary>
/// <param name="ErrorType">Error type found in cell calculation returned as option value</param>
/// <param name="RowNo">Account schedule line number to check for errors</param>
/// <param name="ColumnNo">Column layout line number to check for errors</param>
procedure CalcFieldError(var ErrorType: Option "None","Division by Zero","Period Error",Both; RowNo: Integer; ColumnNo: Integer)
begin
TempAccSchedCellValue.SetRange("Row No.", RowNo);
TempAccSchedCellValue.SetRange("Column No.", ColumnNo);
ErrorType := ErrorType::None;
if TempAccSchedCellValue.FindFirst() then
case true of
TempAccSchedCellValue."Has Error":
ErrorType := ErrorType::"Division by Zero";
TempAccSchedCellValue."Period Error":
ErrorType := ErrorType::"Period Error";
TempAccSchedCellValue."Has Error" and TempAccSchedCellValue."Period Error":
ErrorType := ErrorType::Both;
end;
TempAccSchedCellValue.SetRange("Row No.");
TempAccSchedCellValue.SetRange("Column No.");
end;
/// <summary>
/// Forces recalculation of account schedule values by setting the recalculate flag.
/// Controls whether cached values should be refreshed for financial reporting calculations.
/// </summary>
/// <param name="NewRecalculate">True to force recalculation of cached values, false to use existing cache</param>
procedure ForceRecalculate(NewRecalculate: Boolean)
begin
Recalculate := NewRecalculate;
end;
/// <summary>
/// Converts local currency amounts to additional currency amounts for multi-currency reporting.
/// Uses exchange rates and additional reporting currency setup from general ledger configuration.
/// </summary>
/// <param name="ColValue">Amount in local currency to convert</param>
/// <returns>Converted amount in additional reporting currency</returns>
procedure CalcLCYToACY(ColValue: Decimal): Decimal
begin
if GetGLSetup() then
if GLSetup."Additional Reporting Currency" <> '' then
AddRepCurrency.Get(GLSetup."Additional Reporting Currency");
if GLSetup."Additional Reporting Currency" <> '' then
exit(Round(ExchangeAmtAddCurrToLCY(ColValue), AddRepCurrency."Amount Rounding Precision"));
exit(0);
end;
/// <summary>
/// Sets the fiscal year start date for financial period calculations and reporting.
/// Used to align account schedule calculations with company fiscal calendar.
/// </summary>
/// <param name="NewFiscalStartDate">Fiscal year start date to set for period calculations</param>
procedure SetFiscalStartDate(NewFiscalStartDate: Date)
begin
FiscalStartDate := NewFiscalStartDate;
end;
/// <summary>
/// Retrieves the currently set fiscal year start date used for period calculations.
/// Returns the fiscal start date for account schedule reporting and analysis.
/// </summary>
/// <returns>Current fiscal year start date</returns>
procedure GetFiscalStartDate(): Date
begin
exit(FiscalStartDate);
end;
/// <summary>
/// Calculates the column header text for account schedule reports based on column layout configuration.
/// Generates dynamic headers incorporating dates, periods, and custom formatting.
/// </summary>
/// <param name="AccSchedLine">Account schedule line providing context for header calculation</param>
/// <param name="ColumnLayout">Column layout record defining header format and calculation rules</param>
/// <returns>Formatted column header text for display in account schedule reports</returns>
procedure CalcColumnHeader(var AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout") NewColumnHeader: Text
var
DateText: Text;
FiscalStartDate2: Date;
FromDate: Date;
ToDate: Date;
IsHandled: Boolean;
begin
OnBeforeCalcColumnHeader(AccSchedLine, ColumnLayout, NewColumnHeader, IsHandled);
if IsHandled then
exit(NewColumnHeader);
NewColumnHeader := ColumnLayout."Column Header";
if ColumnLayout."Include Date In Header" = ColumnLayout."Include Date In Header"::Blank then
exit;
StartDate := AccSchedLine.GetRangeMin("Date Filter");
if EndDate <> AccSchedLine.GetRangeMax("Date Filter") then begin
EndDate := AccSchedLine.GetRangeMax("Date Filter");
FiscalStartDate := AccountingPeriodMgt.FindFiscalYear(EndDate);
end;
CalcColumnDates(ColumnLayout, FromDate, ToDate, FiscalStartDate2);
if ToDate = 0D then
exit;
case ColumnLayout."Include Date In Header" of
ColumnLayout."Include Date In Header"::Weekday:
DateText := Format(ToDate, 0, '<Weekday Text>');
ColumnLayout."Include Date In Header"::Week:
DateText := StrSubstNo(WeekTxt, Format(ToDate, 0, '<Week>'));
ColumnLayout."Include Date In Header"::Month:
DateText := Format(ToDate, 0, '<Month Text>');
ColumnLayout."Include Date In Header"::MonthAndYear:
DateText := Format(ToDate, 0, '<Month Text> <Year4>');
ColumnLayout."Include Date In Header"::Quarter:
DateText := StrSubstNo(QuarterTxt, Format(ToDate, 0, '<Quarter>'));
ColumnLayout."Include Date In Header"::QuarterAndYear:
DateText := StrSubstNo(QuarterTxt, Format(ToDate, 0, '<Quarter> <Year4>'));
ColumnLayout."Include Date In Header"::Year:
DateText := Format(ToDate, 0, '<Year4>');
ColumnLayout."Include Date In Header"::FullDate:
DateText := Format(ToDate);
else begin
IsHandled := false;
OnCalcColumnHeaderElseCase(AccSchedLine, ColumnLayout, FromDate, ToDate, DateText, IsHandled)
end;
end;
if ColumnLayout."Column Header" = '' then
NewColumnHeader := DateText
else
NewColumnHeader := StrSubstNo(ColumnHeaderTxt, ColumnLayout."Column Header", DateText);
end;
/// <summary>
/// Integration event raised before calculating column header text in account schedule reports.
/// Enables custom header calculation logic and formatting based on column layout configuration.
/// </summary>
/// <param name="AccSchedLine">Account schedule line providing context for header calculation</param>
/// <param name="ColumnLayout">Column layout record defining header format and calculation rules</param>
/// <param name="NewColumnHeader">Variable to receive custom column header text</param>
/// <param name="IsHandled">Set to true to skip standard header calculation processing</param>
[IntegrationEvent(false, false)]
local procedure OnBeforeCalcColumnHeader(var AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; var NewColumnHeader: Text; var IsHandled: Boolean)
begin
end;
/// <summary>
/// Integration event raised for custom date formatting in column headers when standard formats don't apply.
/// Enables custom date text generation for specialized column header requirements.
/// </summary>
/// <param name="AccSchedLine">Account schedule line providing context for date formatting</param>
/// <param name="ColumnLayout">Column layout record defining date format requirements</param>
/// <param name="FromDate">Start date of the period for header text generation</param>
/// <param name="ToDate">End date of the period for header text generation</param>
/// <param name="DateText">Variable to receive custom formatted date text</param>
/// <param name="IsHandled">Set to true to skip standard date text formatting</param>
[IntegrationEvent(false, false)]
local procedure OnCalcColumnHeaderElseCase(var AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; FromDate: Date; ToDate: Date; var DateText: Text; var IsHandled: Boolean)
begin
end;
/// <summary>
/// Integration event raised after inserting a new account schedule line.
/// Enables custom processing and validation when account schedule lines are created.
/// </summary>
/// <param name="AccSchedLine">Newly inserted account schedule line record</param>
[IntegrationEvent(false, false)]
local procedure OnAfterAccSchedLineInsert(var AccSchedLine: Record "Acc. Schedule Line")
begin
end;
/// <summary>
/// Integration event raised after calculating cell values in account schedule reports.
/// Enables custom cell value processing and result modification for specialized calculations.
/// </summary>
/// <param name="AccSchedLine">Account schedule line used in calculation</param>
/// <param name="ColumnLayout">Column layout record defining calculation parameters</param>
/// <param name="Result">Calculated decimal result value</param>
/// <param name="SourceAccScheduleLine">Source account schedule line for calculation context</param>
/// <param name="GLAcc">G/L Account record used in calculation</param>
[IntegrationEvent(true, false)]
local procedure OnAfterCalcCellValue(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var Result: Decimal; var SourceAccScheduleLine: Record "Acc. Schedule Line"; var GLAcc: Record "G/L Account")
begin
end;
/// <summary>
/// Integration event raised after validating analysis view compatibility with account schedule configuration.
/// Enables custom analysis view processing and dimension validation logic.
/// </summary>
/// <param name="AccSchedName">Account schedule name record for analysis view validation</param>
/// <param name="ColumnLayoutName">Column layout name record for analysis view configuration</param>
/// <param name="AnalysisView">Analysis view record used for validation and processing</param>
[IntegrationEvent(false, false)]
local procedure OnAfterCheckAnalysisView(AccSchedName: Record "Acc. Schedule Name"; ColumnLayoutName: Record "Column Layout Name"; var AnalysisView: Record "Analysis View")
begin
end;
/// <summary>
/// Integration event raised after validating and checking account schedule name.
/// Enables custom processing and validation logic after account schedule name verification.
/// </summary>
/// <param name="CurrentScheduleName">Account schedule name that was validated</param>
[IntegrationEvent(false, false)]
local procedure OnAfterCheckName(CurrentScheduleName: Code[10])
begin
end;
/// <summary>
/// Integration event raised after validating and checking column layout name.
/// Enables custom processing and validation logic after column layout name verification.
/// </summary>
/// <param name="CurrentColumnName">Column layout name that was validated</param>
[IntegrationEvent(false, false)]
local procedure OnAfterCheckColumnName(CurrentColumnName: Code[10])
begin
end;
/// <summary>
/// Integration event raised after checking account schedule template and setting filters.
/// Enables custom template validation and filter modification after standard processing.
/// </summary>
/// <param name="CurrentScheduleName">Account schedule name being processed</param>
/// <param name="AccScheduleLine">Account schedule line record with applied filters</param>
[IntegrationEvent(false, false)]
local procedure OnAfterCheckTemplateAndSetFilter(var CurrentScheduleName: Code[10]; var AccScheduleLine: Record "Acc. Schedule Line")
begin
end;
/// <summary>
/// Integration event raised after determining whether dimension filtering is active.
/// Enables custom dimension filter detection logic and result modification.
/// </summary>
/// <param name="AccScheduleLine">Account schedule line checked for dimension filters</param>
/// <param name="ColumnLayout">Column layout checked for dimension filters</param>
/// <param name="Result">Variable indicating whether dimension filtering is active</param>
[IntegrationEvent(false, false)]
local procedure OnAfterHasDimFilter(var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var Result: Boolean)
begin
end;
/// <summary>
/// Integration event raised after formatting decimal cell values to text representation.
/// Enables custom cell text formatting and display logic for account schedule reports.
/// </summary>
/// <param name="ColumnLayout2">Column layout containing formatting specifications</param>
/// <param name="ValueAsText">Formatted text representation of the cell value</param>
/// <param name="Value">Original decimal value being formatted</param>
[IntegrationEvent(false, false)]
local procedure OnAfterFormatCellAsText(var ColumnLayout2: Record "Column Layout"; var ValueAsText: Text[30]; Value: Decimal)
begin
end;
/// <summary>
/// Integration event raised after inserting G/L accounts into account schedule lines.
/// Enables custom processing and validation after account insertion operations.
/// </summary>
/// <param name="AccScheduleLine">Account schedule line record after G/L account insertion</param>
[IntegrationEvent(false, false)]
local procedure OnAfterInsertGLAccounts(var AccScheduleLine: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterOpenColumns(var CurrentColumnName: Code[10]; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccRowFilters(var GLAccount: Record "G/L Account"; var AccScheduleLine: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCFAccRowFilter(var CashFlowAccount: Record "Cash Flow Account"; var AccScheduleLine: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCFAnalysisViewEntryFilters(var AnalysisViewEntry: Record "Analysis View Entry"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccColumnFilters(var GLAccount: Record "G/L Account"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; StartDate: Date; EndDate: Date)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCFAccColumnFilter(var CashFlowAccount: Record "Cash Flow Account"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; StartDate: Date; EndDate: Date)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCostTypeColumnFilters(var CostType: Record "Cost Type"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccGLEntryFilters(var GLAccount: Record "G/L Account"; var GLEntry: Record "G/L Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccGLBudgetEntryFilters(var GLAcc: Record "G/L Account"; var GLBudgetEntry: Record "G/L Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccAnalysisViewEntryFilters(var GLAcc: Record "G/L Account"; var AnalysisViewEntry: Record "Analysis View Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetGLAccAnalysisViewBudgetEntries(var GLAcc: Record "G/L Account"; var AnalysisViewBudgetEntry: Record "Analysis View Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCostEntryFilters(var CostType: Record "Cost Type"; var CostEntry: Record "Cost Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseDimFilter: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCostTypeRowFilters(var CostType: Record "Cost Type"; var AccSchedLine2: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterSetCostBudgetEntryFilters(var CostType: Record "Cost Type"; var CostBudgetEntry: Record "Cost Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCalcCell(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var Result: Decimal; var IsHandled: Boolean; var Recalculate: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcCellExit(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var Result: Decimal)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcCellValueInEvaluateExpression(IsAccSchedLineExpression: Boolean; AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; Expression: Text; CalcAddCurr: Boolean; IsFilter: Boolean; var Result: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcCellValue(var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var CalcAddCurr: Boolean; var Result: Decimal; var IsHandled: Boolean; AccountScheduleLine: Record "Acc. Schedule Line"; var TempAccSchedCellValue: Record "Acc. Sched. Cell Value" temporary)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcGLAcc(var GLAcc: Record "G/L Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var ColValue: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcCFAcc(var CFAccount: Record "Cash Flow Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var ColValue: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeCalcCostType(var CostType: Record "Cost Type"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var ColValue: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCopyColumnsToTemp(NewColumnName: Code[10]; var TempColumnLayout: Record "Column Layout"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeFormatCellResult(AccSchedLine: Record "Acc. Schedule Line"; ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var Result: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeEvaluateExpression(var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var MaxLevel: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeLookupColumnName(CurrentColumnName: Code[10]; var EntrdColumnName: Text[10]; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetCostAccSetup(var CostAccSetup: Record "Cost Accounting Setup"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeIsExpressionFilter(Expression: Text; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDrillDown(TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; PeriodLength: Option; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTestBalance(var GLAccount: Record "G/L Account"; var AccScheduleName: Record "Acc. Schedule Name"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; AmountType: Integer; var ColValue: Decimal; CalcAddCurr: Boolean; var TestBalance: Boolean; var GLEntry: Record "G/L Entry"; var GLBudgetEntry: Record "G/L Budget Entry"; var Balance: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDrillDownFromOverviewPage(var TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; PeriodLength: Option; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDrillDownOnAccounts(var AccScheduleLine: Record "Acc. Schedule Line"; var TempColumnLayout: Record "Column Layout" temporary; PeriodLength: Option; StartDate: Date; EndDate: Date)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeDrillDownOnGLAccount(var TempColumnLayout: Record "Column Layout" temporary; var AccScheduleLine: Record "Acc. Schedule Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeInsertGLAccounts(var AccScheduleLine: Record "Acc. Schedule Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetGLAccRowFilters(var GLAcc: Record "G/L Account"; var AccSchedLine2: Record "Acc. Schedule Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetCFAccRowFilter(var CFAccount: Record "Cash Flow Account"; var AccSchedLine2: Record "Acc. Schedule Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeSetGLAccGLEntryFilters(var GLAcc: Record "G/L Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean; var IsHandled: Boolean; var GLEntry: Record "G/L Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetGLAccGLBudgetEntryFilters(var GLAcc: Record "G/L Account"; var GLBudgetEntry: Record "G/L Budget Entry"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; UseBusUnitFilter: Boolean; UseDimFilter: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCalcCellValueOnBeforeExit(var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; StartDate: Date; EndDate: Date; var Result: Decimal)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnCalcCellValueOnElseTotalingType(AccSchedLine: Record "Acc. Schedule Line"; AccountScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var Result: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnConvDimTotalingFilterOnDimNoElseCase(DimNo: Integer; var DimCode: Code[20]; AnalysisView: Record "Analysis View"; CostAccountingSetup: Record "Cost Accounting Setup")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnDrillDownOnGLAccountOnBeforeCopyFiltersEmptyAnalysisViewName(var AccScheduleLine: Record "Acc. Schedule Line"; var TempColumnLayout: Record "Column Layout"; var GLAcc: Record "G/L Account")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnDrillDownOnGLAccountOnBeforeCopyFiltersWithAnalysisView(var AccScheduleLine: Record "Acc. Schedule Line"; var TempColumnLayout: Record "Column Layout"; var GLAcc: Record "G/L Account"; var GLAccAnalysisView: Record "G/L Account (Analysis View)")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnEvaluateExpressionOnBeforeCalcAccSchedLineCellValue(SourceAccSchedLine: Record "Acc. Schedule Line"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var IsHandled: Boolean; var CellValue: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnEvaluateExpressionOnBeforeCalcColumnLayoutCellValue(SourceColumnLayout: Record "Column Layout"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var IsHandled: Boolean; var CellValue: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnInsertGLAccountsOnBeforeAccSchedLineInsert(var AccSchedLine: Record "Acc. Schedule Line"; GLAccount: Record "G/L Account")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnMoveAccSchedLinesOnAfterAccSchedLineDelete(var AccSchedLine: Record "Acc. Schedule Line"; Place: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCalcCellValueInAccSchedLinesOnBeforeShowError(SourceAccScheduleLine: Record "Acc. Schedule Line"; var AccScheduleLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var CellValue: Decimal; StartDate: Date; EndDate: Date; var Result: Decimal; var IsHandled: Boolean; Expression: Text; var DivisionError: Boolean; var PeriodError: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnSetGLAccAnalysisViewEntryFiltersOnBeforeAccSchedLineCopyFilter(var AccScheduleLine: Record "Acc. Schedule Line"; AnalysisViewEntry: Record "Analysis View Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCopyColumnsToTempOnAfterColumnLayoutInsert(AccSchedName: Record "Acc. Schedule Name"; NewColumnName: Code[10]; ColumnLayout: Record "Column Layout"; var TempColumnLayout: Record "Column Layout" temporary)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCheckTemplateName(CurrentSchedName: Code[10])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCopyColumnsToTempOnBeforeFind(AccSchedName: Record "Acc. Schedule Name"; NewColumnName: Code[10]; var TempColumnLayout: Record "Column Layout" temporary)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnDrillDownTotalingTypeElseCase(var TempColumnLayout: Record "Column Layout" temporary; var AccSchedLine: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnDrillDownOnGLAccCatFilterOnAfterGLAccSetFilterGroup2(var AccScheduleLine: Record "Acc. Schedule Line"; var GLAccount: Record "G/L Account")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCalcColumnDates(ColumnLayout: Record "Column Layout"; var FromDate: Date; var ToDate: Date; var FiscalStartDate2: Date; var PeriodError: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeHasCostDimFilter(var AccScheduleLine: Record "Acc. Schedule Line"; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCalcCellOnAfterAccountScheduleLineCopyFilters(ColumnLayout: Record "Column Layout"; var AccScheduleLine: Record "Acc. Schedule Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnSetCFEntryFiltersOnAfterAccShedLineCopyFilter(var AccSchedLine: Record "Acc. Schedule Line"; var CFForecastEntry: Record "Cash Flow Forecast Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeFormatCellAsText(var ColumnLayout2: Record "Column Layout"; Value: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCalcCFAccountOnAfterSetEntryFilters(var CFAccount: Record "Cash Flow Account"; var AccSchedLine: Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; var ColValue: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterGetConvDimCode(AnalysisView: Record "Analysis View"; var DimCode: Code[20])
begin
end;
}