diff --git a/src/Apps/W1/ExpenseAgent/app/src/APIs/ExpenseUsersAPI.Page.al b/src/Apps/W1/ExpenseAgent/app/src/APIs/ExpenseUsersAPI.Page.al index 2fc6cdac2ab..28455c35f00 100644 --- a/src/Apps/W1/ExpenseAgent/app/src/APIs/ExpenseUsersAPI.Page.al +++ b/src/Apps/W1/ExpenseAgent/app/src/APIs/ExpenseUsersAPI.Page.al @@ -135,9 +135,12 @@ page 6918 "Expense Users API" // and blocks sign-in there. Apply the constraint in FilterGroup 2 so it // AND-combines with any caller-supplied $filter on Employee No., rather // than replacing it in the default FilterGroup 0. + // The same applies when the employee posting group was removed from the + // employee after the expense user was linked. OriginalFilterGroup := Rec.FilterGroup(); Rec.FilterGroup(2); Rec.SetFilter("Employee No.", '<>%1', ''); + Rec.SetFilter("Employee Posting Group", '<>%1', ''); Rec.FilterGroup(OriginalFilterGroup); end; } \ No newline at end of file diff --git a/src/Apps/W1/ExpenseAgent/app/src/MasterData/Tables/ExpenseUser.Table.al b/src/Apps/W1/ExpenseAgent/app/src/MasterData/Tables/ExpenseUser.Table.al index 4af2e4245a7..3eab8fd285b 100644 --- a/src/Apps/W1/ExpenseAgent/app/src/MasterData/Tables/ExpenseUser.Table.al +++ b/src/Apps/W1/ExpenseAgent/app/src/MasterData/Tables/ExpenseUser.Table.al @@ -38,6 +38,11 @@ table 6923 "Expense User" if Rec."Employee No." <> '' then begin Employee.Get("Employee No."); + if Employee."Employee Posting Group" = '' then + Error( + EmployeePostingGroupMissingErr, + Employee.TableCaption(), Employee."No.", Rec.TableCaption(), Employee.FieldCaption("Employee Posting Group")); + CheckDuplicateEmployeeNo(); if ConfirmOverwriteExpenseUserInformation(Employee) then begin @@ -147,6 +152,14 @@ table 6923 "Expense User" CalcFormula = lookup(Employee.Status where("No." = field("Employee No."))); Editable = false; } + field(25; "Employee Posting Group"; Code[20]) + { + Caption = 'Employee Posting Group'; + ToolTip = 'Specifies the employee posting group of the related employee. Expenses cannot be posted without it.'; + FieldClass = FlowField; + CalcFormula = lookup(Employee."Employee Posting Group" where("No." = field("Employee No."))); + Editable = false; + } field(23; "Approver No."; Code[20]) { Caption = 'Approver No.'; @@ -227,6 +240,7 @@ table 6923 "Expense User" ExpenseApprovalSetupErr: Label 'You cannot remove approval rights from expense user %1. This expense user is currently configured as an approver in the %2.', Comment = '%1 - Expense User No., %2 - Table Caption'; DuplicateEmailErr: Label '%1 %2 is already used by another %3. %1 must be unique.', Comment = '%1 = Email Caption, %2 = Email address, %3 = Expense User Table Caption'; DuplicateEmployeeNoErr: Label '%1 %2 is already linked to another %3. Each employee can only be linked to one %3.', Comment = '%1 = Employee No. Caption, %2 = Employee No., %3 = Expense User Table Caption'; + EmployeePostingGroupMissingErr: Label '%1 %2 cannot be linked to an %3 because %4 is not specified on the %1.', Comment = '%1 = Employee Table Caption, %2 = Employee No., %3 = Expense User Table Caption, %4 = Employee Posting Group Field Caption'; OnlyBCUserCanApproveErr: Label 'In order to be an expense approver there must be a user in Business Central for email %1 for expense user %2.', Comment = '%1 - Email, %2 - Expense User No.'; CannotDeleteExpenseUserWithExpenseErr: Label 'You cannot delete Expense User %1 because they have active expense.', Comment = '%1 = Expense User No.'; CannotDeleteExpenseUserWithExpenseReportErr: Label 'You cannot delete Expense User %1 because they have active expense report.', Comment = '%1 = Expense User No.'; diff --git a/src/Apps/W1/ExpenseAgent/demo data/Country/CreateExpenseCountryData.Codeunit.al b/src/Apps/W1/ExpenseAgent/demo data/Country/CreateExpenseCountryData.Codeunit.al index c6bed8083b5..89777dbc3c4 100644 --- a/src/Apps/W1/ExpenseAgent/demo data/Country/CreateExpenseCountryData.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/demo data/Country/CreateExpenseCountryData.Codeunit.al @@ -122,6 +122,9 @@ codeunit 8222 "Create Expense Country Data" begin CountryCode := GetCountryCode(); + if CountryCode = 'ES' then + Codeunit.Run(Codeunit::"Update Employee ES"); + Codeunit.Run(Codeunit::"Create Expense Location"); Codeunit.Run(Codeunit::"Create Expense Categories DM"); Codeunit.Run(Codeunit::"Create Expense Subcategories"); @@ -130,12 +133,7 @@ codeunit 8222 "Create Expense Country Data" Codeunit.Run(Codeunit::"Create Expense User"); case CountryCode of - 'ES': - begin - Codeunit.Run(Codeunit::"Update Employee ES"); - CreateCountryMasterData(CountryCode); - end; - 'AT', 'AU', 'BE', 'CA', 'CH', 'CZ', 'DE', 'DK', 'FI', 'FR', 'GB', 'IT', 'NL', 'NO', 'NZ', 'US': + 'AT', 'AU', 'BE', 'CA', 'CH', 'CZ', 'DE', 'DK', 'ES', 'FI', 'FR', 'GB', 'IT', 'NL', 'NO', 'NZ', 'US': CreateCountryMasterData(CountryCode); end; end; diff --git a/src/Apps/W1/ExpenseAgent/test/src/ExpenseTestII.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/ExpenseTestII.Codeunit.al index 722114c2da5..f19f8e90668 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/ExpenseTestII.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/ExpenseTestII.Codeunit.al @@ -36,6 +36,7 @@ codeunit 148309 "Expense Test II" LibraryVariableStorage: Codeunit "Library - Variable Storage"; LibraryNotificationMgt: Codeunit "Library - Notification Mgt."; LibraryTemplates: Codeunit "Library - Templates"; + LibraryHumanResource: Codeunit "Library - Human Resource"; NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt."; IsInitialized: Boolean; AddExpenseTo: Option "New Expense Report","Existing Expense Report"; @@ -59,6 +60,7 @@ codeunit 148309 "Expense Test II" CannotDeleteEmployeeWithExpenseReportErr: Label 'You cannot delete Employee %1 because they have active expense report.', Comment = '%1 = Employee No.'; CannotDeleteEmployeeWithExpenseErr: Label 'You cannot delete Employee %1 because they have active expense.', Comment = '%1 = Employee No.'; CannotDeletePaymentMethodInUseErr: Label 'You cannot delete %1 %2 because it is used as the %3 for %4 %5.', Comment = '%1 = Table Caption, %2 = Payment Method Code, %3 = Default Payment Method Field Caption, %4 = Expense Category Table Caption, %5 = Expense Category Code'; + EmployeePostingGroupMissingErr: Label '%1 %2 cannot be linked to an %3 because %4 is not specified on the %1.', Comment = '%1 = Employee Table Caption, %2 = Employee No., %3 = Expense User Table Caption, %4 = Employee Posting Group Field Caption'; [Test] procedure ExpenseDetailRequiredMustFlowToExpenseFromExpenseCategory() @@ -3115,6 +3117,67 @@ codeunit 148309 "Expense Test II" Assert.ExpectedError(StrSubstNo(BillableCustomerAndProjectErr, Expense.FieldCaption("Billable to Customer"), Expense.FieldCaption("Job No."))); end; + [Test] + procedure ExpenseUserCannotBeLinkedToEmployeeWithoutPostingGroup() + var + Employee: Record Employee; + ExpenseUser: Record "Expense User"; + begin + // [FEATURE] [AI TEST] + // [SCENARIO 645043] Verify that an Expense User cannot be linked to an Employee without an Employee Posting Group. + Initialize(); + + // [GIVEN] An Employee "E" without an Employee Posting Group. + LibraryHumanResource.CreateEmployee(Employee); + Employee.Validate("Employee Posting Group", ''); + Employee.Modify(true); + + // [WHEN] Link Employee "E" to a new Expense User "U". + ExpenseUser.Init(); + ExpenseUser.Validate("No.", LibraryUtility.GenerateRandomCode(ExpenseUser.FieldNo("No."), Database::"Expense User")); + asserterror ExpenseUser.Validate("Employee No.", Employee."No."); + + // [THEN] An error is thrown stating that the Employee Posting Group is not specified on the Employee. + Assert.ExpectedError( + StrSubstNo( + EmployeePostingGroupMissingErr, Employee.TableCaption(), Employee."No.", + ExpenseUser.TableCaption(), Employee.FieldCaption("Employee Posting Group"))); + Assert.ExpectedErrorCode('Dialog'); + end; + + [Test] + procedure ExpenseUserCanBeLinkedToEmployeeWithPostingGroup() + var + Employee: Record Employee; + ExpenseUser: Record "Expense User"; + begin + // [FEATURE] [AI TEST] + // [SCENARIO 645043] Verify that an Expense User can be linked to an Employee with an Employee Posting Group. + Initialize(); + + // [GIVEN] An Employee "E" with an Employee Posting Group. + LibraryHumanResource.CreateEmployee(Employee); + + // [WHEN] Link Employee "E" to a new Expense User "U". + ExpenseUser.Init(); + ExpenseUser.Validate("No.", LibraryUtility.GenerateRandomCode(ExpenseUser.FieldNo("No."), Database::"Expense User")); + ExpenseUser.Validate("Employee No.", Employee."No."); + ExpenseUser.Insert(true); + + // [THEN] Expense User "U" is linked to Employee "E" and shows the Employee Posting Group of "E". + ExpenseUser.CalcFields("Employee Posting Group"); + Assert.AreEqual( + Employee."No.", + ExpenseUser."Employee No.", + StrSubstNo(ValueMustBeEqualErr, ExpenseUser.FieldCaption("Employee No."), Employee."No.", ExpenseUser.TableCaption())); + Assert.AreEqual( + Employee."Employee Posting Group", + ExpenseUser."Employee Posting Group", + StrSubstNo( + ValueMustBeEqualErr, ExpenseUser.FieldCaption("Employee Posting Group"), + Employee."Employee Posting Group", ExpenseUser.TableCaption())); + end; + local procedure Initialize() var Workflow: Record Workflow;