Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -336,17 +336,17 @@ report 4413 "EXR Fixed Asset Projected"
DaysInPeriod := 0;
end;

if ProjectionDate = EndCurrentFiscalYear then begin
EntryAmounts[3] := 0;
UpdateToNextFiscalYearEndDate(DepreciationBook, EndCurrentFiscalYear);
end;

if AssetWasDepreciated then begin
AccumulateProjectionEntryAmounts(DepreciationAmount, Custom1Amount, EntryAmounts);
if ProjectDisposal then
CalculateDisposal.CalcGainLoss(FixedAssetNo, DepreciationBookCode, EntryAmounts);
end;

if ProjectionDate = EndCurrentFiscalYear then begin
EntryAmounts[3] := 0;
UpdateToNextFiscalYearEndDate(DepreciationBook, EndCurrentFiscalYear);
end;

InsertProjectedFixedAssetLedgerEntry(ProjectionDate, FixedAssetNo, DepreciationAmount, NumberOfDays, TempFixedAssetLedgerEntry);
LastProjectionInserted := ProjectionDate >= ProjectionsEnd;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
namespace Microsoft.Finance.ExcelReports.Test;

using Microsoft.Finance.ExcelReports;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.FixedAssets.Depreciation;
using Microsoft.FixedAssets.FixedAsset;
using Microsoft.FixedAssets.Journal;
using Microsoft.FixedAssets.Posting;
using Microsoft.FixedAssets.Setup;
using Microsoft.Foundation.Period;
using System.TestLibraries.Utilities;

codeunit 139545 "Fixed Asset Excel Reports"
Expand All @@ -17,11 +21,22 @@ codeunit 139545 "Fixed Asset Excel Reports"
RequiredTestIsolation = Disabled;
TestPermissions = Disabled;

trigger OnRun()
begin
isInitialized := false;
end;

var
LibraryERM: Codeunit "Library - ERM";
LibraryFixedAsset: Codeunit "Library - Fixed Asset";
LibraryRandom: Codeunit "Library - Random";
LibraryReportDataset: Codeunit "Library - Report Dataset";
LibrarySetupStorage: Codeunit "Library - Setup Storage";
LibraryTestInitialize: Codeunit "Library - Test Initialize";
LibraryVariableStorage: Codeunit "Library - Variable Storage";
Assert: Codeunit Assert;
isInitialized: Boolean;
ProjectedDeprMismatchLbl: Label 'Projected depreciation should be calculated from the latest closing book value.';

[Test]
[HandlerFunctions('EXRFixedAssetAnalysisExcelHandler')]
Expand Down Expand Up @@ -80,6 +95,124 @@ codeunit 139545 "Fixed Asset Excel Reports"
Assert.AreEqual(FADepreciationBook."Acquisition Date", ReportAcquisitionDate, 'Acquisition date of first fixed asset should match the one in the depreciation book');
end;

[Test]
[HandlerFunctions('EXRFixedAssetProjectedHandler')]
procedure ProjectedValueDeclBalShouldUseCorrectBookValueAcrossFiscalYear()
var
AccountingPeriod: Record "Accounting Period";
DepreciationBook: Record "Depreciation Book";
FADepreciationBook: Record "FA Depreciation Book";
FAJournalSetup: Record "FA Journal Setup";
FAJournalTemplate: Record "FA Journal Template";
FASetup: Record "FA Setup";
FixedAsset: Record "Fixed Asset";
AcquisitionAmount: Decimal;
BookValueAfterDepr: Decimal;
DecliningBalancePct: Decimal;
ExpectedProjectedDepr: Decimal;
MonthlyDeprAmount: Decimal;
ReportAmount: Decimal;
I: Integer;
AcquisitionDate: Date;
BasePostingDate: Date;
DeprStartDate: Date;
FirstReportDeprDate: Date;
FiscalYearStartDate: Date;
LastReportDeprDate: Date;
PostingDate: Date;
Variant: Variant;
begin
// [SCENARIO 631253] Report 4413 "Fixed Asset Projected Value (Excel)" should calculate depreciation
// using the last posted month's book value when crossing a fiscal year boundary with Declining-Balance 1.
// Previously it incorrectly used the penultimate month's book value.
Initialize();

// [GIVEN] Create Accounting periods with fiscal year.
CleanupFixedAssetData();
AccountingPeriod.DeleteAll();
FiscalYearStartDate := DMY2Date(1, 9, 2025);
CreateMonthlyAccountingPeriods(FiscalYearStartDate, 24);

// [GIVEN] Create a depreciation book.
LibraryFixedAsset.CreateDepreciationBook(DepreciationBook);
ModifyDepreciationBook(DepreciationBook);

FASetup.Get();
FASetup.Validate("Default Depr. Book", DepreciationBook.Code);
FASetup.Modify(true);

LibraryFixedAsset.CreateFAJournalSetup(FAJournalSetup, DepreciationBook.Code, '');
SetupFAJournalSetup(FAJournalSetup);

// [GIVEN] Create a fixed asset with Declining-Balance 1 and randomized amount/% values.
AcquisitionDate := DMY2Date(1, 1, 2025);
DeprStartDate := AcquisitionDate;
AcquisitionAmount := 10000 + Round(LibraryRandom.RandDec(90000, 0), 1);
DecliningBalancePct := 10 + Round(LibraryRandom.RandDec(20, 0), 1);

LibraryFixedAsset.CreateFAWithPostingGroup(FixedAsset);
LibraryFixedAsset.CreateFADepreciationBook(FADepreciationBook, FixedAsset."No.", DepreciationBook.Code);
FADepreciationBook.Validate("FA Posting Group", FixedAsset."FA Posting Group");
FADepreciationBook.Validate("Depreciation Starting Date", DeprStartDate);
FADepreciationBook.Validate("Depreciation Method", FADepreciationBook."Depreciation Method"::"Declining-Balance 1");
FADepreciationBook.Validate("Declining-Balance %", DecliningBalancePct);
FADepreciationBook.Modify(true);

// [GIVEN] Post acquisition on the randomized acquisition date.
LibraryFixedAsset.CreateJournalTemplate(FAJournalTemplate);
CreateAndPostFAJournalLine(
FAJournalTemplate.Name, FixedAsset."No.", AcquisitionDate,
"FA Journal Line FA Posting Type"::"Acquisition Cost",
DepreciationBook.Code, AcquisitionAmount, FixedAsset."No.");

// [GIVEN] Post depreciation starting from the acquisition month.
BasePostingDate := CalcDate('<CM>', AcquisitionDate);
BookValueAfterDepr := AcquisitionAmount;
for I := 1 to 8 do begin
MonthlyDeprAmount := Round(BookValueAfterDepr * DecliningBalancePct / 100 / 12, 1);
PostingDate := CalcDate('<' + Format(I - 1) + 'M>', BasePostingDate);

CreateAndPostFAJournalLine(
FAJournalTemplate.Name, FixedAsset."No.", PostingDate,
"FA Journal Line FA Posting Type"::Depreciation,
DepreciationBook.Code, -MonthlyDeprAmount, CopyStr(FixedAsset."No." + '-' + Format(I), 1, MaxStrLen(FixedAsset."No.")));

BookValueAfterDepr -= MonthlyDeprAmount;
end;

// The next projected month should be based on this closing book value.
ExpectedProjectedDepr := -Round(BookValueAfterDepr * DecliningBalancePct / 100 / 12, 1);
Commit();

// [WHEN] Running the Fixed Asset Projected Value (Excel) report.
FirstReportDeprDate := CalcDate('<CM>', CalcDate('<8M>', BasePostingDate));
LastReportDeprDate := CalcDate('<11M>', FirstReportDeprDate);
RunFixedAssetProjectedReport(DepreciationBook.Code, FirstReportDeprDate, LastReportDeprDate, false);

// [THEN] Verify the projected depreciation in the first projected month uses the latest closing book value.
LibraryReportDataset.SetXmlNodeList('DataItem[@name="FixedAssetLedgerEntries"]');
LibraryReportDataset.GetNextRow();
LibraryReportDataset.FindCurrentRowValue('Amount', Variant);
ReportAmount := Variant;
ReportAmount := Round(ReportAmount, 1);
Assert.AreEqual(ExpectedProjectedDepr, ReportAmount, ProjectedDeprMismatchLbl);
end;

local procedure Initialize()
begin
LibraryTestInitialize.OnTestInitialize(Codeunit::"Fixed Asset Excel Reports");
LibrarySetupStorage.Restore();
if isInitialized then
exit;
LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Fixed Asset Excel Reports");

EnsureGeneralPostingSetup();
LibrarySetupStorage.Save(Database::"FA Setup");
isInitialized := true;
Commit();
LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"Fixed Asset Excel Reports");
end;

local procedure CleanupFixedAssetData()
var
FAPostingType: Record "FA Posting Type";
Expand All @@ -89,6 +222,91 @@ codeunit 139545 "Fixed Asset Excel Reports"
FixedAsset.DeleteAll();
end;

local procedure CreateMonthlyAccountingPeriods(FiscalYearStart: Date; NumberOfMonths: Integer)
var
AccountingPeriod: Record "Accounting Period";
PeriodStart: Date;
I: Integer;
begin
// Create a fiscal year starting at FiscalYearStart with monthly periods
// Also create the prior fiscal year.
PeriodStart := CalcDate('<-1Y>', FiscalYearStart);
AccountingPeriod.Init();
AccountingPeriod."Starting Date" := PeriodStart;
AccountingPeriod."New Fiscal Year" := true;
AccountingPeriod.Insert();
for I := 1 to 11 do begin
PeriodStart := CalcDate('<1M>', PeriodStart);
AccountingPeriod.Init();
AccountingPeriod."Starting Date" := PeriodStart;
AccountingPeriod."New Fiscal Year" := false;
AccountingPeriod.Insert();
end;

// Create the target fiscal year and its periods.
for I := 0 to NumberOfMonths - 1 do begin
PeriodStart := CalcDate('<' + Format(I) + 'M>', FiscalYearStart);
AccountingPeriod.Init();
AccountingPeriod."Starting Date" := PeriodStart;
AccountingPeriod."New Fiscal Year" := (I = 0);
AccountingPeriod.Insert();
end;
end;

local procedure SetupFAJournalSetup(var FAJournalSetup: Record "FA Journal Setup")
var
DefaultFAJournalSetup: Record "FA Journal Setup";
begin
DefaultFAJournalSetup.SetRange("Depreciation Book Code", LibraryFixedAsset.GetDefaultDeprBook());
DefaultFAJournalSetup.FindFirst();
FAJournalSetup.TransferFields(DefaultFAJournalSetup, false);
FAJournalSetup.Modify(true);
end;

local procedure CreateAndPostFAJournalLine(FAJournalTemplateName: Code[10]; FANo: Code[20]; PostingDate: Date; FAPostingType: Enum "FA Journal Line FA Posting Type"; DepreciationBookCode: Code[10]; Amount: Decimal; DocumentNo: Code[20])
var
FAJournalBatch: Record "FA Journal Batch";
FAJournalLine: Record "FA Journal Line";
begin
LibraryFixedAsset.CreateFAJournalBatch(FAJournalBatch, FAJournalTemplateName);
LibraryFixedAsset.CreateFAJournalLine(FAJournalLine, FAJournalTemplateName, FAJournalBatch.Name);
FAJournalLine.Validate("FA No.", FANo);
FAJournalLine.Validate("FA Posting Date", PostingDate);
FAJournalLine.Validate("Posting Date", PostingDate);
FAJournalLine.Validate("FA Posting Type", FAPostingType);
FAJournalLine.Validate("Depreciation Book Code", DepreciationBookCode);
FAJournalLine.Validate(Amount, Amount);
FAJournalLine.Validate("Document No.", DocumentNo);
FAJournalLine.Modify(true);

LibraryFixedAsset.PostFAJournalLine(FAJournalLine);
end;

local procedure RunFixedAssetProjectedReport(DepreciationBookCode: Code[10]; FirstDeprDate: Date; LastDeprDate: Date; UseAccountingPeriod: Boolean)
var
Variant: Variant;
RequestPageXml: Text;
begin
LibraryVariableStorage.Enqueue(DepreciationBookCode);
LibraryVariableStorage.Enqueue(FirstDeprDate);
LibraryVariableStorage.Enqueue(LastDeprDate);
LibraryVariableStorage.Enqueue(UseAccountingPeriod);
RequestPageXml := Report.RunRequestPage(Report::"EXR Fixed Asset Projected", RequestPageXml);
LibraryReportDataset.RunReportAndLoad(Report::"EXR Fixed Asset Projected", Variant, RequestPageXml);
end;

local procedure EnsureGeneralPostingSetup()
var
GeneralPostingSetup: Record "General Posting Setup";
begin
GeneralPostingSetup.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
if not GeneralPostingSetup.IsEmpty() then
exit;

LibraryERM.CreateGeneralPostingSetupInvt(GeneralPostingSetup);
end;

[RequestPageHandler]
procedure EXRFixedAssetAnalysisExcelHandler(var EXRFixedAssetAnalysisExcel: TestRequestPage "EXR Fixed Asset Analysis Excel")
var
Expand All @@ -101,4 +319,30 @@ codeunit 139545 "Fixed Asset Excel Reports"
EXRFixedAssetAnalysisExcel.OK().Invoke();
end;

}
local procedure ModifyDepreciationBook(var DepreciationBook: Record "Depreciation Book")
begin
DepreciationBook.Validate("G/L Integration - Acq. Cost", false);
DepreciationBook.Validate("G/L Integration - Depreciation", false);
DepreciationBook.Modify(true);
end;

[RequestPageHandler]
procedure EXRFixedAssetProjectedHandler(var EXRFixedAssetProjected: TestRequestPage "EXR Fixed Asset Projected")
var
DepreciationBookCode: Code[10];
FirstDeprDate: Date;
LastDeprDate: Date;
UseAccountingPeriod: Boolean;
begin
DepreciationBookCode := CopyStr(LibraryVariableStorage.DequeueText(), 1, 10);
FirstDeprDate := LibraryVariableStorage.DequeueDate();
LastDeprDate := LibraryVariableStorage.DequeueDate();
UseAccountingPeriod := LibraryVariableStorage.DequeueBoolean();

EXRFixedAssetProjected.DepreciationBookCodeField.SetValue(DepreciationBookCode);
EXRFixedAssetProjected.FirstDepreciationDateField.SetValue(FirstDeprDate);
EXRFixedAssetProjected.SecondDepreciationDateField.SetValue(LastDeprDate);
EXRFixedAssetProjected.UseAccountingPeriodField.SetValue(UseAccountingPeriod);
EXRFixedAssetProjected.OK().Invoke();
end;
}
Loading