From dfeb6337640266ac09835ac3e0da5118ec4945ff Mon Sep 17 00:00:00 2001 From: v-shuklad Date: Thu, 20 Aug 2026 12:03:16 +0530 Subject: [PATCH] Changes and Automation --- .../Utilities/DocumentTotals.Codeunit.al | 31 ++++++ .../Utilities/DocumentTotals.Codeunit.al | 30 +++++- .../Utilities/DocumentTotals.Codeunit.al | 28 ++++++ .../Tests/ERM/DocumentTotalsPages.Codeunit.al | 98 +++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) diff --git a/src/Layers/BE/BaseApp/Utilities/DocumentTotals.Codeunit.al b/src/Layers/BE/BaseApp/Utilities/DocumentTotals.Codeunit.al index 81934a5b4c2..e2f3fda12ec 100644 --- a/src/Layers/BE/BaseApp/Utilities/DocumentTotals.Codeunit.al +++ b/src/Layers/BE/BaseApp/Utilities/DocumentTotals.Codeunit.al @@ -7,6 +7,7 @@ namespace Microsoft.Utilities; using Microsoft.Finance.Currency; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.SalesTax; +using Microsoft.Finance.VAT.Calculation; using Microsoft.Purchases.Document; using Microsoft.Purchases.History; using Microsoft.Purchases.Posting; @@ -671,6 +672,8 @@ codeunit 57 "Document Totals" TotalPurchaseLine2: Record "Purchase Line"; PurchaseLineWithReverseChargeVAT: Record "Purchase Line"; VATAmountOfLinesWithRevChargeVAT: Decimal; + NonDeductibleVATAmount: Decimal; + GroupedVATAmount: Decimal; IsHandled: Boolean; begin IsHandled := false; @@ -747,14 +750,42 @@ codeunit 57 "Document Totals" repeat TotalPurchaseLine2.Amount += PurchaseLine2.GetNonDeductibleVATAmount(); VATAmount -= PurchaseLine2.GetNonDeductibleVATAmount(); + NonDeductibleVATAmount += PurchaseLine2.GetNonDeductibleVATAmount(); until PurchaseLine2.Next() = 0; + if (VATAmountOfLinesWithRevChargeVAT = 0) and (NonDeductibleVATAmount = 0) then + if GetGroupedVATAmount(TotalPurchaseHeader, GroupedVATAmount) and (GroupedVATAmount <> VATAmount) then begin + VATAmount := GroupedVATAmount; + TotalPurchaseLine2."Amount Including VAT" := TotalPurchaseLine2.Amount + VATAmount; + TotalPurchaseLine."Amount Including VAT" := TotalPurchaseLine2."Amount Including VAT"; + end; + OnAfterCalculatePurchaseSubPageTotals( TotalPurchaseHeader, TotalPurchaseLine, VATAmount, InvoiceDiscountAmount, InvoiceDiscountPct, TotalPurchaseLine2); TotalPurchaseLine := TotalPurchaseLine2; end; + local procedure GetGroupedVATAmount(var PurchHeader: Record "Purchase Header"; var GroupedVATAmount: Decimal): Boolean + var + PurchLine: Record "Purchase Line"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + begin + if PurchHeader."No." = '' then + exit(false); + + PurchasesPayablesSetup.Get(); + if not PurchasesPayablesSetup."Allow VAT Difference" then + exit(false); + + if PurchHeader."Tax Liable" then + exit(false); + + PurchLine.CalcVATAmountLines(0, PurchHeader, PurchLine, TempVATAmountLine); + GroupedVATAmount := TempVATAmountLine.GetTotalVATAmount(); + exit(true); + end; + procedure CalculatePostedPurchInvoiceTotals(var PurchInvHeader: Record "Purch. Inv. Header"; var VATAmount: Decimal; PurchInvLine: Record "Purch. Inv. Line") var CurrPurchInvLine: Record "Purch. Inv. Line"; diff --git a/src/Layers/NA/BaseApp/Utilities/DocumentTotals.Codeunit.al b/src/Layers/NA/BaseApp/Utilities/DocumentTotals.Codeunit.al index 9329f220b22..133ca7b757a 100644 --- a/src/Layers/NA/BaseApp/Utilities/DocumentTotals.Codeunit.al +++ b/src/Layers/NA/BaseApp/Utilities/DocumentTotals.Codeunit.al @@ -7,6 +7,7 @@ namespace Microsoft.Utilities; using Microsoft.Finance.Currency; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.SalesTax; +using Microsoft.Finance.VAT.Calculation; using Microsoft.Purchases.Document; using Microsoft.Purchases.History; using Microsoft.Purchases.Posting; @@ -666,6 +667,7 @@ codeunit 57 "Document Totals" PurchaseHeader: Record "Purchase Header"; PurchaseLine2: Record "Purchase Line"; TotalPurchaseLine2: Record "Purchase Line"; + GroupedVATAmount: Decimal; IsHandled: Boolean; begin IsHandled := false; @@ -723,12 +725,38 @@ codeunit 57 "Document Totals" end; end; + if GetGroupedVATAmount(TotalPurchaseHeader, GroupedVATAmount) and (GroupedVATAmount <> VATAmount) then begin + VATAmount := GroupedVATAmount; + TotalPurchaseLine2."Amount Including VAT" := TotalPurchaseLine2.Amount + VATAmount; + TotalPurchaseLine."Amount Including VAT" := TotalPurchaseLine2."Amount Including VAT"; + end; + OnAfterCalculatePurchaseSubPageTotals( TotalPurchaseHeader, TotalPurchaseLine, VATAmount, InvoiceDiscountAmount, InvoiceDiscountPct, TotalPurchaseLine2); TotalPurchaseLine := TotalPurchaseLine2; end; + local procedure GetGroupedVATAmount(var PurchHeader: Record "Purchase Header"; var GroupedVATAmount: Decimal): Boolean + var + PurchLine: Record "Purchase Line"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + begin + if PurchHeader."No." = '' then + exit(false); + + PurchasesPayablesSetup.Get(); + if not PurchasesPayablesSetup."Allow VAT Difference" then + exit(false); + + if PurchHeader."Tax Liable" then + exit(false); + + PurchLine.CalcVATAmountLines(0, PurchHeader, PurchLine, TempVATAmountLine); + GroupedVATAmount := TempVATAmountLine.GetTotalVATAmount(); + exit(true); + end; + procedure CalculatePostedPurchInvoiceTotals(var PurchInvHeader: Record "Purch. Inv. Header"; var VATAmount: Decimal; PurchInvLine: Record "Purch. Inv. Line") var IsHandled: Boolean; @@ -963,7 +991,7 @@ codeunit 57 "Document Totals" procedure PurchaseCalculateTotalsNoRounding(var TempCurrentPurchaseLine: Record "Purchase Line"; var VATAmount: Decimal; var TempTotalPurchaseLine: Record "Purchase Line"; var TaxAreaCode: Code[20]) var PurchaseLine: Record "Purchase Line"; - IsHandled: Boolean; + IsHandled: Boolean; begin IsHandled := false; OnBeforePurchaseCalculateTotalsNoRounding(TempCurrentPurchaseLine, VATAmount, TempTotalPurchaseLine, TaxAreaCode, IsHandled); diff --git a/src/Layers/W1/BaseApp/Utilities/DocumentTotals.Codeunit.al b/src/Layers/W1/BaseApp/Utilities/DocumentTotals.Codeunit.al index e36b31e1dbc..f9c32e94d59 100644 --- a/src/Layers/W1/BaseApp/Utilities/DocumentTotals.Codeunit.al +++ b/src/Layers/W1/BaseApp/Utilities/DocumentTotals.Codeunit.al @@ -7,6 +7,7 @@ namespace Microsoft.Utilities; using Microsoft.Finance.Currency; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.SalesTax; +using Microsoft.Finance.VAT.Calculation; using Microsoft.Purchases.Document; using Microsoft.Purchases.History; using Microsoft.Purchases.Posting; @@ -651,6 +652,7 @@ codeunit 57 "Document Totals" PurchaseHeader: Record "Purchase Header"; PurchaseLine2: Record "Purchase Line"; TotalPurchaseLine2: Record "Purchase Line"; + GroupedVATAmount: Decimal; IsHandled: Boolean; begin IsHandled := false; @@ -708,12 +710,38 @@ codeunit 57 "Document Totals" end; end; + if GetGroupedVATAmount(TotalPurchaseHeader, GroupedVATAmount) and (GroupedVATAmount <> VATAmount) then begin + VATAmount := GroupedVATAmount; + TotalPurchaseLine2."Amount Including VAT" := TotalPurchaseLine2.Amount + VATAmount; + TotalPurchaseLine."Amount Including VAT" := TotalPurchaseLine2."Amount Including VAT"; + end; + OnAfterCalculatePurchaseSubPageTotals( TotalPurchaseHeader, TotalPurchaseLine, VATAmount, InvoiceDiscountAmount, InvoiceDiscountPct, TotalPurchaseLine2); TotalPurchaseLine := TotalPurchaseLine2; end; + local procedure GetGroupedVATAmount(var PurchHeader: Record "Purchase Header"; var GroupedVATAmount: Decimal): Boolean + var + PurchLine: Record "Purchase Line"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + begin + if PurchHeader."No." = '' then + exit(false); + + PurchasesPayablesSetup.Get(); + if not PurchasesPayablesSetup."Allow VAT Difference" then + exit(false); + + if PurchHeader."Tax Liable" then + exit(false); + + PurchLine.CalcVATAmountLines(0, PurchHeader, PurchLine, TempVATAmountLine); + GroupedVATAmount := TempVATAmountLine.GetTotalVATAmount(); + exit(true); + end; + procedure CalculatePostedPurchInvoiceTotals(var PurchInvHeader: Record "Purch. Inv. Header"; var VATAmount: Decimal; PurchInvLine: Record "Purch. Inv. Line") var IsHandled: Boolean; diff --git a/src/Layers/W1/Tests/ERM/DocumentTotalsPages.Codeunit.al b/src/Layers/W1/Tests/ERM/DocumentTotalsPages.Codeunit.al index 0bf48e6a64e..7138d8f03ae 100644 --- a/src/Layers/W1/Tests/ERM/DocumentTotalsPages.Codeunit.al +++ b/src/Layers/W1/Tests/ERM/DocumentTotalsPages.Codeunit.al @@ -2192,6 +2192,80 @@ codeunit 134344 "Document Totals Pages" Assert.AreEqual(NewDescription, SalesOrder.SalesLines.Description.Value(), LineDescriptionRevertedErr); end; + [Test] + [HandlerFunctions('PurchaseInvoiceStatisticsUpdateVATAmountPageHandler')] + procedure PurchInvTotalInclVATMatchesStatisticsAfterVATAdjMixedVATGroupsSameAccount() + var + GLAccount: Record "G/L Account"; + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + VATPostingSetup: array[2] of Record "VAT Posting Setup"; + Vendor: Record Vendor; + PurchaseInvoicePage: TestPage "Purchase Invoice"; + GLAccountNo: Code[20]; + MaxVATDifference: Decimal; + TotalAmountInclVATBefore: Decimal; + TotalVATAmountBefore: Decimal; + VATAdjustment: Decimal; + begin + // [FEATURE] [UI] [VAT] [Purchase] [VAT Difference] + // [SCENARIO 637288] "Total VAT Amount" and "Total Amount Incl. VAT" on Purchase Invoice subform must update + // after VAT adjustment when invoice has mixed VAT groups on the same G/L Account with negative lines. + Initialize(); + + // [GIVEN] "VAT Difference" is allowed with random Max VAT Difference + MaxVATDifference := LibraryRandom.RandDecInRange(1, 5, 2); + LibraryERM.SetMaxVATDifferenceAllowed(MaxVATDifference); + LibraryPurchase.SetAllowVATDifference(true); + + // [GIVEN] Create two VAT Posting Setups with random VAT%, same VAT Bus. Posting Group + CreateVATPostingSetup(VATPostingSetup); + + // [GIVEN] Purchase Invoice with mixed VAT lines on the same G/L Account, including negative adjustment lines + GLAccount.Get(LibraryERM.CreateGLAccountWithPurchSetup()); + GLAccount.Validate("VAT Prod. Posting Group", VATPostingSetup[1]."VAT Prod. Posting Group"); + GLAccount.Modify(true); + Vendor.Get(LibraryPurchase.CreateVendorNo()); + Vendor.Validate("VAT Bus. Posting Group", VATPostingSetup[1]."VAT Bus. Posting Group"); + Vendor.Modify(); + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, Vendor."No."); + CreatePurchLineWithGLAccAndVATSetup(PurchaseLine, PurchaseHeader, VATPostingSetup[1], GLAccount."No.", LibraryRandom.RandDecInRange(1000, 5000, 2)); + CreatePurchLineWithGLAccAndVATSetup(PurchaseLine, PurchaseHeader, VATPostingSetup[1], GLAccount."No.", -LibraryRandom.RandDecInRange(100, 500, 2)); + CreatePurchLineWithGLAccAndVATSetup(PurchaseLine, PurchaseHeader, VATPostingSetup[2], GLAccount."No.", LibraryRandom.RandDecInRange(1000, 5000, 2)); + CreatePurchLineWithGLAccAndVATSetup(PurchaseLine, PurchaseHeader, VATPostingSetup[2], GLAccount."No.", -LibraryRandom.RandDecInRange(100, 900, 2)); + + // [GIVEN] Open Purchase Invoice page and capture totals before adjustment + PurchaseInvoicePage.OpenEdit(); + PurchaseInvoicePage.Filter.SetFilter("No.", PurchaseHeader."No."); + PurchaseInvoicePage.PurchLines.Last(); + TotalVATAmountBefore := PurchaseInvoicePage.PurchLines."Total VAT Amount".AsDecimal(); + TotalAmountInclVATBefore := PurchaseInvoicePage.PurchLines."Total Amount Incl. VAT".AsDecimal(); + + // [WHEN] VAT Amount adjusted on Statistics page (within allowed VAT difference) + VATAdjustment := -LibraryRandom.RandDecInRange(0, MaxVATDifference, 2); + LibraryVariableStorage.Enqueue(VATAdjustment); + PurchaseInvoicePage.PurchaseStatistics.Invoke(); + PurchaseInvoicePage.Close(); + + // [THEN] "Total VAT Amount" on the subform reflects the VAT adjustment + PurchaseInvoicePage.OpenEdit(); + PurchaseInvoicePage.Filter.SetFilter("No.", PurchaseHeader."No."); + PurchaseInvoicePage.PurchLines.Last(); + Assert.AreEqual( + TotalVATAmountBefore + VATAdjustment, + PurchaseInvoicePage.PurchLines."Total VAT Amount".AsDecimal(), + StrSubstNo(VATAmountErr, PurchaseInvoicePage.PurchLines."Total VAT Amount".Caption, 'expected Total VAT Amount')); + + // [THEN] "Total Amount Incl. VAT" on the subform reflects the VAT adjustment + Assert.AreEqual( + TotalAmountInclVATBefore + VATAdjustment, + PurchaseInvoicePage.PurchLines."Total Amount Incl. VAT".AsDecimal(), + StrSubstNo(VATAmountErr, PurchaseInvoicePage.PurchLines."Total Amount Incl. VAT".Caption, 'expected Total Amount Incl. VAT')); + + PurchaseInvoicePage.Close(); + LibraryVariableStorage.AssertEmpty(); + end; + local procedure Initialize() begin LibrarySetupStorage.Restore(); @@ -2461,6 +2535,30 @@ codeunit 134344 "Document Totals Pages" SalesLine.Modify(); end; + local procedure CreateVATPostingSetup(var VATPostingSetup: array[2] of Record "VAT Posting Setup") + var + VATProductPostingGroup: Record "VAT Product Posting Group"; + begin + LibraryERM.CreateVATPostingSetupWithAccounts( + VATPostingSetup[1], VATPostingSetup[1]."VAT Calculation Type"::"Normal VAT", LibraryRandom.RandIntInRange(5, 15)); + LibraryERM.CreateVATProductPostingGroup(VATProductPostingGroup); + LibraryERM.CreateVATPostingSetup(VATPostingSetup[2], VATPostingSetup[1]."VAT Bus. Posting Group", VATProductPostingGroup.Code); + VATPostingSetup[2].Validate("VAT Calculation Type", VATPostingSetup[2]."VAT Calculation Type"::"Normal VAT"); + VATPostingSetup[2].Validate("VAT %", LibraryRandom.RandIntInRange(16, 25)); + VATPostingSetup[2].Validate("VAT Identifier", CopyStr(VATProductPostingGroup.Code, 1, MaxStrLen(VATPostingSetup[2]."VAT Identifier"))); + VATPostingSetup[2]."Purchase VAT Account" := LibraryERM.CreateGLAccountNo(); + VATPostingSetup[2].Modify(true); + end; + + local procedure CreatePurchLineWithGLAccAndVATSetup(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; VATPostingSetup: Record "VAT Posting Setup"; GLAccountNo: Code[20]; DirectUnitCost: Decimal) + begin + LibraryPurchase.CreatePurchaseLine( + PurchaseLine, PurchaseHeader, PurchaseLine.Type::"G/L Account", GLAccountNo, 1); + PurchaseLine.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); + PurchaseLine.Validate("Direct Unit Cost", DirectUnitCost); + PurchaseLine.Modify(true); + end; + [ConfirmHandler] [Scope('OnPrem')] procedure ConfirmHandlerYes(Question: Text[1024]; var Reply: Boolean)