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;
+}