Codeunit 197 Update Acc. Sched. KPI Data, source in 29
Source29
src/Layers/W1/BaseApp/Finance/FinancialReports/UpdateAccSchedKPIData.Codeunit.al247 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.Finance.GeneralLedger.Ledger;
using Microsoft.Foundation.Period;
using System.Environment;
/// <summary>
/// Updates account schedule KPI buffer data for web service consumption and external reporting.
/// Manages data refresh operations, period calculations, and KPI buffer population for published web services.
/// </summary>
/// <remarks>
/// Automated data update codeunit for KPI web service functionality. Handles period-based data collection,
/// account schedule calculations, and buffer table maintenance for real-time KPI exposure through web services.
/// Integrates with G/L entries and budget data for comprehensive financial KPI reporting.
/// </remarks>
codeunit 197 "Update Acc. Sched. KPI Data"
{
Permissions = TableData "Acc. Sched. KPI Web Srv. Setup" = rim,
TableData "Acc. Sched. KPI Buffer" = rimd;
trigger OnRun()
begin
InitSetupData();
end;
var
AccSchedKPIWebSrvSetup: Record "Acc. Sched. KPI Web Srv. Setup";
AccSchedKPIBuffer: Record "Acc. Sched. KPI Buffer";
TempAccScheduleLine: Record "Acc. Schedule Line" temporary;
TempColumnLayout: Record "Column Layout" temporary;
AccSchedManagement: Codeunit AccSchedManagement;
NoOfActiveAccSchedLines: Integer;
NoOfLines: Integer;
LastLineNo: Integer;
StartDate: Date;
EndDate: Date;
LastClosedDate: Date;
Date: Date;
UpdatingMsg: Label 'Updating buffer table @1@@@@@@@@@@@@@@@@@@@', Comment = '@1 is a number';
local procedure InitSetupData()
var
AccSchedKPIWebSrvLine: Record "Acc. Sched. KPI Web Srv. Line";
AccScheduleLine: Record "Acc. Schedule Line";
ColumnLayout: Record "Column Layout";
GLEntry: Record "G/L Entry";
LogInManagement: Codeunit LogInManagement;
Window: Dialog;
i: Integer;
begin
// Exit quickly to avoid lock
if AccSchedKPIWebSrvSetup.Get() then
if AccSchedKPIWebSrvSetup."Data Time To Live (hours)" >= 1 then
if not AccSchedKPIBuffer.IsEmpty() then
if AccSchedKPIWebSrvSetup."Data Last Updated" >
CurrentDateTime - AccSchedKPIWebSrvSetup."Data Time To Live (hours)" * 3600000
then
exit;
AccSchedKPIWebSrvSetup.LockTable();
if not AccSchedKPIWebSrvSetup.Get() then begin
AccSchedKPIWebSrvSetup.Init();
AccSchedKPIWebSrvSetup.Insert();
end;
if AccSchedKPIWebSrvSetup."Data Time To Live (hours)" < 1 then
AccSchedKPIWebSrvSetup."Data Time To Live (hours)" := 24;
if AccSchedKPIWebSrvSetup."Last G/L Entry Included" > 0 then begin
GLEntry.SetFilter("Entry No.", '>%1', AccSchedKPIWebSrvSetup."Last G/L Entry Included");
GLEntry.SetCurrentKey("Posting Date");
end;
if GLEntry.IsEmpty() then
exit; // nothing to update
Window.Open(UpdatingMsg);
if not GuiAllowed then
WorkDate := LogInManagement.GetDefaultWorkDate();
AccSchedKPIBuffer.DeleteAll();
if not AccSchedKPIWebSrvLine.FindSet() then
exit;
AccScheduleLine.SetFilter(Totaling, '<>%1', '');
repeat
AccScheduleLine.SetRange("Schedule Name", AccSchedKPIWebSrvLine."Acc. Schedule Name");
if AccScheduleLine.FindSet() then
repeat
NoOfActiveAccSchedLines += 1;
TempAccScheduleLine := AccScheduleLine;
TempAccScheduleLine."Line No." := NoOfActiveAccSchedLines;
TempAccScheduleLine.Insert();
until AccScheduleLine.Next() = 0;
until AccSchedKPIWebSrvLine.Next() = 0;
OnInitSetupDataAnAfterTempAccScheduleLineInsert(TempAccScheduleLine, NoOfActiveAccSchedLines);
// Net Change Actual
InsertTempColumn(ColumnLayout."Column Type"::"Net Change", ColumnLayout."Ledger Entry Type"::Entries, false);
// Balance at Date Actual
InsertTempColumn(ColumnLayout."Column Type"::"Balance at Date", ColumnLayout."Ledger Entry Type"::Entries, false);
// Net Change Budget
InsertTempColumn(ColumnLayout."Column Type"::"Net Change", ColumnLayout."Ledger Entry Type"::"Budget Entries", false);
// Balance at Date Budget
InsertTempColumn(ColumnLayout."Column Type"::"Balance at Date", ColumnLayout."Ledger Entry Type"::"Budget Entries", false);
// Net Change Actual Last Year
InsertTempColumn(ColumnLayout."Column Type"::"Net Change", ColumnLayout."Ledger Entry Type"::Entries, true);
// Balance at Date Actual Last Year
InsertTempColumn(ColumnLayout."Column Type"::"Balance at Date", ColumnLayout."Ledger Entry Type"::Entries, true);
// Net Change Budget Last Year
InsertTempColumn(ColumnLayout."Column Type"::"Net Change", ColumnLayout."Ledger Entry Type"::"Budget Entries", true);
// Balance at Date Budget Last Year
InsertTempColumn(ColumnLayout."Column Type"::"Balance at Date", ColumnLayout."Ledger Entry Type"::"Budget Entries", true);
AccSchedKPIWebSrvSetup.GetPeriodLength(NoOfLines, StartDate, EndDate);
NoOfLines *= NoOfActiveAccSchedLines;
LastClosedDate := AccSchedKPIWebSrvSetup.GetLastClosedAccDate();
for i := 0 to NoOfLines - 1 do begin
if i mod 10 = 0 then
Window.Update(1, 10000 * i div NoOfLines);
CalcValues(i);
end;
AccSchedKPIWebSrvSetup."Data Last Updated" := CurrentDateTime;
GLEntry.Reset();
AccSchedKPIWebSrvSetup."Last G/L Entry Included" := GLEntry.GetLastEntryNo();
AccSchedKPIWebSrvSetup.Modify();
Commit();
Window.Close();
end;
local procedure InsertTempColumn(ColumnType: Enum "Column Layout Type"; EntryType: Enum "Column Layout Entry Type"; LastYear: Boolean)
begin
if TempColumnLayout.FindLast() then;
TempColumnLayout.Init();
TempColumnLayout."Line No." += 10000;
TempColumnLayout."Column Type" := ColumnType;
TempColumnLayout."Ledger Entry Type" := EntryType;
if LastYear then
Evaluate(TempColumnLayout."Comparison Date Formula", '<-1Y>');
TempColumnLayout.Insert();
end;
local procedure CalcValues(Number: Integer)
var
AccountingPeriod: Record "Accounting Period";
ToDate: Date;
ColNo: Integer;
CalculatedValue: Decimal;
begin
Date := AccSchedKPIWebSrvSetup.CalcNextStartDate(StartDate, Number div NoOfActiveAccSchedLines);
ToDate := AccSchedKPIWebSrvSetup.CalcNextStartDate(Date, 1) - 1;
TempAccScheduleLine.FindSet();
if Number mod NoOfActiveAccSchedLines > 0 then
TempAccScheduleLine.Next(Number mod NoOfActiveAccSchedLines);
TempAccScheduleLine.SetRange("Date Filter", Date, ToDate);
TempAccScheduleLine.SetRange("G/L Budget Filter", AccSchedKPIWebSrvSetup."G/L Budget Name");
LastLineNo += 1;
AccSchedKPIBuffer.Init();
AccSchedKPIBuffer."No." := LastLineNo;
AccSchedKPIBuffer.Date := Date;
AccSchedKPIBuffer."Closed Period" :=
AccountingPeriod.CorrespondingAccountingPeriodExists(AccountingPeriod, Date) and AccountingPeriod.Closed;
AccSchedKPIBuffer."Account Schedule Name" := TempAccScheduleLine."Schedule Name";
AccSchedKPIBuffer."KPI Code" := CopyStr(TempAccScheduleLine."Row No.", 1, MaxStrLen(AccSchedKPIBuffer."KPI Code"));
AccSchedKPIBuffer."KPI Name" := CopyStr(TempAccScheduleLine.Description, 1, MaxStrLen(AccSchedKPIBuffer."KPI Name"));
ColNo := 0;
TempColumnLayout.FindSet();
repeat
CalculatedValue := AccSchedManagement.CalcCell(TempAccScheduleLine, TempColumnLayout, false);
OnCalcValuesOnAfterCalculateValue(TempAccScheduleLine, TempColumnLayout, CalculatedValue);
ColNo += 1;
case ColNo of
1:
AccSchedKPIBuffer."Net Change Actual" := CalculatedValue;
2:
AccSchedKPIBuffer."Balance at Date Actual" := CalculatedValue;
3:
AccSchedKPIBuffer."Net Change Budget" := CalculatedValue;
4:
AccSchedKPIBuffer."Balance at Date Budget" := CalculatedValue;
5:
AccSchedKPIBuffer."Net Change Actual Last Year" := CalculatedValue;
6:
AccSchedKPIBuffer."Balance at Date Act. Last Year" := CalculatedValue;
7:
AccSchedKPIBuffer."Net Change Budget Last Year" := CalculatedValue;
8:
AccSchedKPIBuffer."Balance at Date Bud. Last Year" := CalculatedValue;
9:
AccSchedKPIBuffer."Net Change Forecast" := CalculatedValue;
10:
AccSchedKPIBuffer."Balance at Date Forecast" := CalculatedValue;
end;
until TempColumnLayout.Next() = 0;
// Forecasted values
if ((AccSchedKPIWebSrvSetup."Forecasted Values Start" = AccSchedKPIWebSrvSetup."Forecasted Values Start"::"After Latest Closed Period") and
not (Date <= LastClosedDate)) or
((AccSchedKPIWebSrvSetup."Forecasted Values Start" = AccSchedKPIWebSrvSetup."Forecasted Values Start"::"After Current Date") and (Date > WorkDate()))
then begin
AccSchedKPIBuffer."Net Change Forecast" := AccSchedKPIBuffer."Net Change Budget";
// Net Change Budget
AccSchedKPIBuffer."Balance at Date Forecast" := AccSchedKPIBuffer."Balance at Date Budget";
// Balance at Date Budget
end else begin
AccSchedKPIBuffer."Net Change Forecast" := AccSchedKPIBuffer."Net Change Actual";
// Net Change Actual
AccSchedKPIBuffer."Balance at Date Forecast" := AccSchedKPIBuffer."Balance at Date Actual";
// Balance at Date Actual
end;
AccSchedKPIBuffer.Insert();
end;
/// <summary>
/// Integration event raised after calculating values during KPI data update process.
/// Enables custom modification of calculated values before final buffer insertion.
/// </summary>
/// <param name="TempAccScheduleLine">Temporary account schedule line being processed</param>
/// <param name="TempColumnLayout">Temporary column layout being processed</param>
/// <param name="CalculatedValue">Calculated value that can be modified</param>
[IntegrationEvent(false, false)]
local procedure OnCalcValuesOnAfterCalculateValue(var TempAccScheduleLine: Record "Acc. Schedule Line" temporary; var TempColumnLayout: Record "Column Layout" temporary; var CalculatedValue: Decimal)
begin
end;
/// <summary>
/// Integration event raised after inserting temporary account schedule lines during setup data initialization.
/// Enables custom modifications to account schedule line setup and line counting logic.
/// </summary>
/// <param name="TempAccScheduleLine">Temporary account schedule line that was inserted</param>
/// <param name="NoOfLines">Number of lines processed, can be modified</param>
[IntegrationEvent(false, false)]
local procedure OnInitSetupDataAnAfterTempAccScheduleLineInsert(var TempAccScheduleLine: Record "Acc. Schedule Line" temporary; var NoOfLines: Integer)
begin
end;
}