diff --git a/src/Apps/W1/EDocument/App/Permissions/EDocCoreObjects.PermissionSet.al b/src/Apps/W1/EDocument/App/Permissions/EDocCoreObjects.PermissionSet.al index 7ea0a55df6..6db1b6dc7c 100644 --- a/src/Apps/W1/EDocument/App/Permissions/EDocCoreObjects.PermissionSet.al +++ b/src/Apps/W1/EDocument/App/Permissions/EDocCoreObjects.PermissionSet.al @@ -58,6 +58,7 @@ permissionset 6100 "E-Doc. Core - Objects" codeunit "E-Document Create Jnl. Line" = X, codeunit "E-Document Create Purch. Doc." = X, codeunit "E-Document Helper" = X, + codeunit "E-Document VAT Helper" = X, codeunit "E-Document Processing" = X, codeunit "E-Document Import Helper" = X, codeunit "E-Document Log Helper" = X, diff --git a/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClause.TableExt.al b/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClause.TableExt.al new file mode 100644 index 0000000000..74ec3abacc --- /dev/null +++ b/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClause.TableExt.al @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.eServices.EDocument; + +using Microsoft.Finance.VAT.Clause; + +tableextension 6173 "E-Doc. VAT Clause" extends "VAT Clause" +{ + fields + { + field(6100; "VATEX Code"; Code[30]) + { + Caption = 'VATEX Code'; + DataClassification = CustomerContent; + ToolTip = 'Specifies the VATEX exemption reason code (BT-121) from the CEF VATEX code list, e.g. VATEX-EU-AE, VATEX-EU-G, VATEX-EU-IC.'; + } + } +} diff --git a/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClauses.PageExt.al b/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClauses.PageExt.al new file mode 100644 index 0000000000..c460fa1802 --- /dev/null +++ b/src/Apps/W1/EDocument/App/src/Extensions/EDocVATClauses.PageExt.al @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.eServices.EDocument; + +using Microsoft.Finance.VAT.Clause; + +pageextension 6173 "E-Doc. VAT Clauses" extends "VAT Clauses" +{ + layout + { + addlast(group) + { + field("VATEX Code"; Rec."VATEX Code") + { + ApplicationArea = Basic, Suite; + } + } + } +} diff --git a/src/Apps/W1/EDocument/App/src/Helpers/EDocumentVATHelper.Codeunit.al b/src/Apps/W1/EDocument/App/src/Helpers/EDocumentVATHelper.Codeunit.al new file mode 100644 index 0000000000..4702895827 --- /dev/null +++ b/src/Apps/W1/EDocument/App/src/Helpers/EDocumentVATHelper.Codeunit.al @@ -0,0 +1,38 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.eServices.EDocument; + +using Microsoft.Finance.VAT.Clause; +using Microsoft.Finance.VAT.Setup; + +codeunit 6403 "E-Document VAT Helper" +{ + /// + /// Resolves VAT Bus./Prod. Posting Group to VATEX Code and VAT Clause Description. + /// If a translation exists for the given language code, the translated description is returned. + /// + /// The VAT Business Posting Group code. + /// The VAT Product Posting Group code. + /// The language code for VAT Clause description translation. Empty for default. + /// Return value: the VATEX exemption reason code from the VAT Clause. + /// Return value: the VAT Clause description, translated if available. + procedure GetVATClauseInfo(VATBusPostingGroup: Code[20]; VATProductPostingGroup: Code[20]; LanguageCode: Code[10]; var VATEXCode: Text; var VATClauseDescription: Text) + var + VATPostingSetup: Record "VAT Posting Setup"; + VATClause: Record "VAT Clause"; + begin + VATEXCode := ''; + VATClauseDescription := ''; + if not VATPostingSetup.Get(VATBusPostingGroup, VATProductPostingGroup) then + exit; + if VATPostingSetup."VAT Clause Code" = '' then + exit; + if not VATClause.Get(VATPostingSetup."VAT Clause Code") then + exit; + VATClause.TranslateDescription(LanguageCode); + VATEXCode := VATClause."VATEX Code"; + VATClauseDescription := VATClause.Description; + end; +} diff --git a/src/Apps/W1/EDocument/Demo Data/1.Setup Data/CreateEDocVATClauseData.Codeunit.al b/src/Apps/W1/EDocument/Demo Data/1.Setup Data/CreateEDocVATClauseData.Codeunit.al new file mode 100644 index 0000000000..c07eb25f96 --- /dev/null +++ b/src/Apps/W1/EDocument/Demo Data/1.Setup Data/CreateEDocVATClauseData.Codeunit.al @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.eServices.EDocument.DemoData; + +using Microsoft.DemoData.Finance; +using Microsoft.Finance.VAT.Clause; + +codeunit 5398 "Create E-Doc. VAT Clause Data" +{ + InherentEntitlements = X; + InherentPermissions = X; + + trigger OnRun() + begin + UpdateVATClauseVATEXCodes(); + end; + + local procedure UpdateVATClauseVATEXCodes() + var + VATClause: Record "VAT Clause"; + CreateVATPostingGroups: Codeunit "Create VAT Posting Groups"; + begin + if VATClause.Get(CreateVATPostingGroups.NoVAT()) then begin + VATClause."VATEX Code" := VATEXCodeNoVATLbl; + VATClause.Modify(); + end; + end; + + var + VATEXCodeNoVATLbl: Label 'VATEX-EU-O', MaxLength = 30, Locked = true; +} diff --git a/src/Apps/W1/EDocument/Demo Data/EDocumentContosoModule.Codeunit.al b/src/Apps/W1/EDocument/Demo Data/EDocumentContosoModule.Codeunit.al index 96f0dc103e..4237e0182f 100644 --- a/src/Apps/W1/EDocument/Demo Data/EDocumentContosoModule.Codeunit.al +++ b/src/Apps/W1/EDocument/Demo Data/EDocumentContosoModule.Codeunit.al @@ -32,6 +32,7 @@ codeunit 5373 "E-Document Contoso Module" implements "Contoso Demo Data Module" begin Codeunit.Run(Codeunit::"Create E-Document Setup"); Codeunit.Run(Codeunit::"Create E-Doc DemoData Service"); + Codeunit.Run(Codeunit::"Create E-Doc. VAT Clause Data"); end; procedure CreateMasterData() diff --git a/src/Apps/W1/EDocument/Test/src/Helpers/EDocVATHelperTests.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Helpers/EDocVATHelperTests.Codeunit.al new file mode 100644 index 0000000000..5c26a1f264 --- /dev/null +++ b/src/Apps/W1/EDocument/Test/src/Helpers/EDocVATHelperTests.Codeunit.al @@ -0,0 +1,130 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.eServices.EDocument.Test; + +using Microsoft.eServices.EDocument; +using Microsoft.Finance.VAT.Clause; +using Microsoft.Finance.VAT.Setup; +using Microsoft.Foundation.Enums; +using System.Globalization; + +codeunit 139620 "E-Doc. VAT Helper Tests" +{ + Subtype = Test; + TestType = UnitTest; + + var + Assert: Codeunit Assert; + LibraryRandom: Codeunit "Library - Random"; + LibraryUtility: Codeunit "Library - Utility"; + LibraryERM: Codeunit "Library - ERM"; + + [Test] + procedure GetVATClauseInfoReturnsVATEXCodeAndDescription() + var + VATPostingSetup: Record "VAT Posting Setup"; + VATClause: Record "VAT Clause"; + EDocVATHelper: Codeunit "E-Document VAT Helper"; + VATEXCode: Text; + VATClauseDescription: Text; + begin + // [SCENARIO] GetVATClauseInfo returns VATEX Code and Description when VAT Posting Setup and VAT Clause exist + // [GIVEN] A VAT Posting Setup with a VAT Clause that has a VATEX Code + CreateVATPostingSetupWithVATClause(VATPostingSetup, VATClause); + + // [WHEN] GetVATClauseInfo is called + EDocVATHelper.GetVATClauseInfo(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", '', VATEXCode, VATClauseDescription); + + // [THEN] VATEX Code and Description are returned + Assert.AreEqual(VATClause."VATEX Code", VATEXCode, 'VATEX Code mismatch'); + Assert.AreEqual(VATClause.Description, VATClauseDescription, 'VAT Clause Description mismatch'); + end; + + [Test] + procedure GetVATClauseInfoReturnsEmptyWhenVATClauseCodeIsBlank() + var + VATPostingSetup: Record "VAT Posting Setup"; + EDocVATHelper: Codeunit "E-Document VAT Helper"; + VATEXCode: Text; + VATClauseDescription: Text; + begin + // [SCENARIO] GetVATClauseInfo returns empty when VAT Posting Setup exists but VAT Clause Code is blank + // [GIVEN] A VAT Posting Setup with no VAT Clause Code + LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::"Tax Calculation Type"::"Normal VAT", LibraryRandom.RandInt(25)); + + // [WHEN] GetVATClauseInfo is called + EDocVATHelper.GetVATClauseInfo(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", '', VATEXCode, VATClauseDescription); + + // [THEN] Both values are empty + Assert.AreEqual('', VATEXCode, 'VATEX Code should be empty'); + Assert.AreEqual('', VATClauseDescription, 'VAT Clause Description should be empty'); + end; + + [Test] + procedure GetVATClauseInfoReturnsEmptyWhenVATClauseNotFound() + var + VATPostingSetup: Record "VAT Posting Setup"; + EDocVATHelper: Codeunit "E-Document VAT Helper"; + VATEXCode: Text; + VATClauseDescription: Text; + begin + // [SCENARIO] GetVATClauseInfo returns empty when VAT Clause record does not exist + // [GIVEN] A VAT Posting Setup with a non-existing VAT Clause Code + LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::"Tax Calculation Type"::"Normal VAT", LibraryRandom.RandInt(25)); + VATPostingSetup."VAT Clause Code" := CopyStr(LibraryUtility.GenerateRandomCode20(VATPostingSetup.FieldNo("VAT Clause Code"), Database::"VAT Posting Setup"), 1, MaxStrLen(VATPostingSetup."VAT Clause Code")); + VATPostingSetup.Modify(); + + // [WHEN] GetVATClauseInfo is called + EDocVATHelper.GetVATClauseInfo(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", '', VATEXCode, VATClauseDescription); + + // [THEN] Both values are empty + Assert.AreEqual('', VATEXCode, 'VATEX Code should be empty'); + Assert.AreEqual('', VATClauseDescription, 'VAT Clause Description should be empty'); + end; + + [Test] + procedure GetVATClauseInfoReturnsTranslatedDescription() + var + VATPostingSetup: Record "VAT Posting Setup"; + VATClause: Record "VAT Clause"; + VATClauseTranslation: Record "VAT Clause Translation"; + Language: Record Language; + EDocVATHelper: Codeunit "E-Document VAT Helper"; + VATEXCode: Text; + VATClauseDescription: Text; + TranslatedDescription: Text[250]; + begin + // [SCENARIO] GetVATClauseInfo returns translated description when a translation exists for the given language + // [GIVEN] A VAT Posting Setup with a VAT Clause that has a translation + CreateVATPostingSetupWithVATClause(VATPostingSetup, VATClause); + Language.SetFilter(Code, '<>%1', ''); + Language.FindFirst(); + TranslatedDescription := CopyStr(LibraryUtility.GenerateRandomAlphabeticText(50, 0), 1, MaxStrLen(TranslatedDescription)); + VATClauseTranslation.Init(); + VATClauseTranslation."VAT Clause Code" := VATClause.Code; + VATClauseTranslation."Language Code" := Language.Code; + VATClauseTranslation.Description := TranslatedDescription; + VATClauseTranslation.Insert(); + + // [WHEN] GetVATClauseInfo is called with the translation language + EDocVATHelper.GetVATClauseInfo(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", Language.Code, VATEXCode, VATClauseDescription); + + // [THEN] Translated description is returned + Assert.AreEqual(VATClause."VATEX Code", VATEXCode, 'VATEX Code mismatch'); + Assert.AreEqual(TranslatedDescription, VATClauseDescription, 'Should return translated description'); + end; + + local procedure CreateVATPostingSetupWithVATClause(var VATPostingSetup: Record "VAT Posting Setup"; var VATClause: Record "VAT Clause") + begin + LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::"Tax Calculation Type"::"Normal VAT", LibraryRandom.RandInt(25)); + VATClause.Init(); + VATClause.Code := CopyStr(LibraryUtility.GenerateRandomCode20(VATClause.FieldNo(Code), Database::"VAT Clause"), 1, MaxStrLen(VATClause.Code)); + VATClause.Description := CopyStr(LibraryUtility.GenerateRandomAlphabeticText(50, 0), 1, MaxStrLen(VATClause.Description)); + VATClause."VATEX Code" := CopyStr(LibraryUtility.GenerateRandomAlphabeticText(10, 0), 1, MaxStrLen(VATClause."VATEX Code")); + VATClause.Insert(); + VATPostingSetup."VAT Clause Code" := VATClause.Code; + VATPostingSetup.Modify(); + end; +}