diff --git a/src/Apps/W1/ExcelReports/App/src/Financials/TrialBalance.Codeunit.al b/src/Apps/W1/ExcelReports/App/src/Financials/TrialBalance.Codeunit.al index 268ad055ff..32d6a211fb 100644 --- a/src/Apps/W1/ExcelReports/App/src/Financials/TrialBalance.Codeunit.al +++ b/src/Apps/W1/ExcelReports/App/src/Financials/TrialBalance.Codeunit.al @@ -247,12 +247,11 @@ codeunit 4410 "Trial Balance" TrialBalanceData."Net Change (ACY)" := EXRTrialBalanceQuery.ACYAmount; TrialBalanceData."Net Change (Debit) (ACY)" := EXRTrialBalanceQuery.ACYDebitAmount; TrialBalanceData."Net Change (Credit) (ACY)" := EXRTrialBalanceQuery.ACYCreditAmount; - TrialBalanceData.CheckAllZero(); - if not TrialBalanceData."All Zero" then begin - TrialBalanceData.Insert(true); - InsertUsedDimensionValue(1, TrialBalanceData."Dimension 1 Code", Dimension1Values); - InsertUsedDimensionValue(2, TrialBalanceData."Dimension 2 Code", Dimension2Values); - end; + // Every combination the query returns has entries, so it represents real activity and is kept even when it + // nets to zero. The second pass adjusts any that also have an opening balance. + TrialBalanceData.Insert(true); + InsertUsedDimensionValue(1, TrialBalanceData."Dimension 1 Code", Dimension1Values); + InsertUsedDimensionValue(2, TrialBalanceData."Dimension 2 Code", Dimension2Values); end; EXRTrialBalanceQuery.Close(); @@ -263,7 +262,9 @@ codeunit 4410 "Trial Balance" TrialBalanceData.SetRange("G/L Account No.", EXRTrialBalanceQuery.AccountNumber); TrialBalanceData.SetRange("Dimension 1 Code", EXRTrialBalanceQuery.DimensionValue1Code); TrialBalanceData.SetRange("Dimension 2 Code", EXRTrialBalanceQuery.DimensionValue2Code); - if not TrialBalanceData.FindFirst() then begin // This shouldn't happen, but we consider it regardless + if not TrialBalanceData.FindFirst() then begin + // This shouldn't happen now that the first pass inserts every combination with entries up to the ending date, but we Init() and consider it regardless. + TrialBalanceData.Init(); TrialBalanceData."G/L Account No." := EXRTrialBalanceQuery.AccountNumber; TrialBalanceData."Dimension 1 Code" := EXRTrialBalanceQuery.DimensionValue1Code; TrialBalanceData."Dimension 2 Code" := EXRTrialBalanceQuery.DimensionValue2Code; @@ -315,12 +316,11 @@ codeunit 4410 "Trial Balance" TrialBalanceData."Net Change (ACY)" := EXRTrialBalanceBUQuery.ACYAmount; TrialBalanceData."Net Change (Debit) (ACY)" := EXRTrialBalanceBUQuery.ACYDebitAmount; TrialBalanceData."Net Change (Credit) (ACY)" := EXRTrialBalanceBUQuery.ACYCreditAmount; - TrialBalanceData.CheckAllZero(); - if not TrialBalanceData."All Zero" then begin - TrialBalanceData.Insert(true); - InsertUsedDimensionValue(1, TrialBalanceData."Dimension 1 Code", Dimension1Values); - InsertUsedDimensionValue(2, TrialBalanceData."Dimension 2 Code", Dimension2Values); - end; + // Every combination the query returns has entries, so it represents real activity and is kept even when it + // nets to zero. The second pass adjusts any that also have an opening balance. + TrialBalanceData.Insert(true); + InsertUsedDimensionValue(1, TrialBalanceData."Dimension 1 Code", Dimension1Values); + InsertUsedDimensionValue(2, TrialBalanceData."Dimension 2 Code", Dimension2Values); end; EXRTrialBalanceBUQuery.Close(); @@ -333,6 +333,8 @@ codeunit 4410 "Trial Balance" TrialBalanceData.SetRange("Dimension 2 Code", EXRTrialBalanceBUQuery.DimensionValue2Code); TrialBalanceData.SetRange("Business Unit Code", EXRTrialBalanceBUQuery.BusinessUnitCode); if not TrialBalanceData.FindFirst() then begin + // This shouldn't happen now that the first pass inserts every combination with entries up to the ending date, but we Init() and consider it regardless. + TrialBalanceData.Init(); TrialBalanceData."G/L Account No." := EXRTrialBalanceBUQuery.AccountNumber; TrialBalanceData."Dimension 1 Code" := EXRTrialBalanceBUQuery.DimensionValue1Code; TrialBalanceData."Dimension 2 Code" := EXRTrialBalanceBUQuery.DimensionValue2Code; diff --git a/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al b/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al index c789c3de90..5a4f6c2a5e 100644 --- a/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al +++ b/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al @@ -641,24 +641,27 @@ codeunit 139544 "Trial Balance Excel Reports" end; [Test] - procedure QueryPathSkipsAllZeroRecords() + procedure QueryPathIncludesAccountsThatNetToZero() var GLAccount: Record "G/L Account"; TempDimension1Values, TempDimension2Values : Record "Dimension Value" temporary; TrialBalanceData: Record "EXR Trial Balance Buffer"; TrialBalance: Codeunit "Trial Balance"; ZeroAccount, NonZeroAccount : Code[20]; + GrossAmount: Decimal; begin - // [SCENARIO] Accounts with entries that sum to zero are not included in the buffer. - // [GIVEN] One account with cancelling entries (net zero) and another with a non-zero balance + // [SCENARIO] Accounts that have entries are included even when they net to zero. The query only returns + // accounts with activity, so a zero net change still represents real (offsetting) turnover worth showing. + // [GIVEN] One account with cancelling entries (net zero, gross turnover) and another with a non-zero balance Initialize(); LibraryERM.CreateGLAccount(GLAccount); ZeroAccount := GLAccount."No."; LibraryERM.CreateGLAccount(GLAccount); NonZeroAccount := GLAccount."No."; - CreateGLEntryWithAmount(ZeroAccount, '', '', '', WorkDate(), 500); - CreateGLEntryWithAmount(ZeroAccount, '', '', '', WorkDate(), -500); + GrossAmount := 500; + CreateGLEntryWithAmount(ZeroAccount, '', '', '', WorkDate(), GrossAmount); + CreateGLEntryWithAmount(ZeroAccount, '', '', '', WorkDate(), -GrossAmount); CreateGLEntryWithAmount(NonZeroAccount, '', '', '', WorkDate(), 100); // [WHEN] Running the trial balance @@ -667,10 +670,54 @@ codeunit 139544 "Trial Balance Excel Reports" TrialBalance.ConfigureTrialBalance(false, false); TrialBalance.InsertTrialBalanceReportData(GLAccount, TempDimension1Values, TempDimension2Values, TrialBalanceData); - // [THEN] Only the non-zero account appears - Assert.AreEqual(1, TrialBalanceData.Count(), 'Only the non-zero account should be in the buffer'); - TrialBalanceData.FindFirst(); - Assert.AreEqual(NonZeroAccount, TrialBalanceData."G/L Account No.", 'The non-zero account should be the one returned'); + // [THEN] Both accounts are in the buffer + Assert.AreEqual(2, TrialBalanceData.Count(), 'Both accounts with entries should be in the buffer'); + // [THEN] The net-zero account is present with zero net change and balance, but its gross turnover is reported + TrialBalanceData.SetRange("G/L Account No.", ZeroAccount); + Assert.IsTrue(TrialBalanceData.FindFirst(), 'The net-zero account should be included'); + Assert.AreEqual(0, TrialBalanceData."Net Change", 'Net Change should be zero'); + Assert.AreEqual(0, TrialBalanceData.Balance, 'Balance should be zero'); + Assert.AreEqual(GrossAmount, TrialBalanceData."Net Change (Debit)", 'Gross debit turnover should be reported'); + Assert.AreEqual(GrossAmount, TrialBalanceData."Net Change (Credit)", 'Gross credit turnover should be reported'); + end; + + [Test] + procedure QueryPathReportsCorrectDebitCreditSplitsForZeroEndBalance() + var + GLAccount, KeptAccount : Record "G/L Account"; + TempDimension1Values, TempDimension2Values : Record "Dimension Value" temporary; + TrialBalanceData: Record "EXR Trial Balance Buffer"; + TrialBalance: Codeunit "Trial Balance"; + OpeningDebit: Decimal; + PriorYear: Integer; + begin + // [SCENARIO] A combination that nets to zero at the end date but has period activity keeps correct debit/credit + // splits: the first pass inserts it (carrying the end-date totals) so the second pass can subtract the opening. + Initialize(); + PriorYear := Date2DMY(WorkDate(), 3) - 1; + OpeningDebit := 1000; + + // [GIVEN] An account whose opening debit is fully reversed by a credit within the period (net-zero end, period activity) + CreateGLAccount(KeptAccount); + CreateGLEntryWithAmount(KeptAccount."No.", '', '', '', DMY2Date(15, 6, PriorYear), OpeningDebit); + CreateGLEntryWithAmount(KeptAccount."No.", '', '', '', DMY2Date(15, 6, Date2DMY(WorkDate(), 3)), -OpeningDebit); + + // [WHEN] Running the query-based trial balance for the current year + GLAccount.SetRange("Date Filter", DMY2Date(1, 1, Date2DMY(WorkDate(), 3)), DMY2Date(31, 12, Date2DMY(WorkDate(), 3))); + TrialBalance.ConfigureTrialBalance(false, false); + TrialBalance.InsertTrialBalanceReportData(GLAccount, TempDimension1Values, TempDimension2Values, TrialBalanceData); + + // [THEN] The combination is present with correct net AND gross debit/credit columns + TrialBalanceData.SetRange("G/L Account No.", KeptAccount."No."); + Assert.IsTrue(TrialBalanceData.FindFirst(), 'Buffer record should exist for the net-zero-at-end combination'); + Assert.AreEqual(OpeningDebit, TrialBalanceData."Starting Balance", 'Starting Balance should equal the opening debit'); + Assert.AreEqual(-OpeningDebit, TrialBalanceData."Net Change", 'Net Change should reverse the opening'); + Assert.AreEqual(0, TrialBalanceData.Balance, 'Balance should net to zero at the end date'); + Assert.AreEqual(OpeningDebit, TrialBalanceData."Starting Balance (Debit)", 'Opening debit split'); + Assert.AreEqual(0, TrialBalanceData."Net Change (Debit)", 'No period debit turnover'); + Assert.AreEqual(OpeningDebit, TrialBalanceData."Net Change (Credit)", 'Period credit turnover equals the reversal'); + Assert.AreEqual(OpeningDebit, TrialBalanceData."Balance (Debit)", 'Cumulative debit at the end date'); + Assert.AreEqual(OpeningDebit, TrialBalanceData."Balance (Credit)", 'Cumulative credit at the end date'); end; [Test]