diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 6cf5247b8501..7bf544b7f010 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -179,6 +179,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const {isOffline} = useNetwork(); const isOnHold = isOnHoldTransactionUtils(transaction); + const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [isHoldMenuVisible, setIsHoldMenuVisible] = useState(false); const [paymentType, setPaymentType] = useState(); const [requestType, setRequestType] = useState(); @@ -577,8 +578,8 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea if (!moneyRequestReport) { return []; } - return getSecondaryReportActions(moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, canUseRetractNewDot, canUseTableReportView); - }, [moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, canUseRetractNewDot, canUseTableReportView]); + return getSecondaryReportActions(moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, canUseRetractNewDot, canUseTableReportView, policies); + }, [moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, canUseRetractNewDot, canUseTableReportView, policies]); const secondaryActionsImplementation: Record, DropdownOption>> = { [CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS]: { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 4acb68d879e6..b43a42dd030a 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -1239,10 +1239,6 @@ function getAllPoliciesLength() { return Object.keys(allPolicies ?? {}).length; } -function getAllPolicies() { - return Object.values(allPolicies ?? {}).filter((p) => !!p); -} - function getActivePolicy(): OnyxEntry { return getPolicy(activePolicyId); } @@ -1532,7 +1528,6 @@ export { getWorkflowApprovalsUnavailable, getNetSuiteImportCustomFieldLabel, getAllPoliciesLength, - getAllPolicies, getActivePolicy, getUserFriendlyWorkspaceType, isPolicyAccessible, diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index 604be8bbd97f..61c7e858a5d7 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -1,12 +1,12 @@ import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report, ReportAction, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx'; import {isApprover as isApproverUtils} from './actions/Policy/Member'; import {getCurrentUserAccountID} from './actions/Report'; import { arePaymentsEnabled as arePaymentsEnabledUtils, - getAllPolicies, getConnectedIntegration, getCorrectedAutoReportingFrequency, getSubmitToAccountID, @@ -18,6 +18,7 @@ import {getIOUActionForReportID, getIOUActionForTransactionID, getOneTransaction import { canAddTransaction, canEditFieldOfMoneyRequest, + canEditReportPolicy, isArchivedReport, isClosedReport as isClosedReportUtils, isCurrentUserSubmitter, @@ -318,10 +319,14 @@ function isHoldActionForTransaction(report: Report, reportTransaction: Transacti return isProcessingReport; } -function isChangeWorkspaceAction(report: Report, policy?: Policy): boolean { - const policies = getAllPolicies(); - const session = getSession(); - return policies.filter((newPolicy) => isWorkspaceEligibleForReportChange(newPolicy, report, session, policy)).length > 0; +function isChangeWorkspaceAction(report: Report, policies: OnyxCollection): boolean { + const availablePolicies = Object.values(policies ?? {}).filter((newPolicy) => isWorkspaceEligibleForReportChange(newPolicy, report, policies)); + let hasAvailablePolicies = availablePolicies.length > 1; + if (!hasAvailablePolicies && availablePolicies.length === 1) { + hasAvailablePolicies = !report.policyID || report.policyID !== availablePolicies?.at(0)?.id; + } + const reportPolicy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; + return hasAvailablePolicies && canEditReportPolicy(report, reportPolicy); } function isMoveTransactionAction(reportTransactions: Transaction[], reportActions?: ReportAction[]) { @@ -395,6 +400,7 @@ function getSecondaryReportActions( reportActions?: ReportAction[], canUseRetractNewDot?: boolean, canUseTableReportView?: boolean, + policies?: OnyxCollection, ): Array> { const options: Array> = []; @@ -438,7 +444,7 @@ function getSecondaryReportActions( options.push(CONST.REPORT.SECONDARY_ACTIONS.DOWNLOAD_PDF); - if (isChangeWorkspaceAction(report, policy)) { + if (isChangeWorkspaceAction(report, policies)) { options.push(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 11882161be61..86765a85ca09 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -72,7 +72,6 @@ import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/o import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; import {createDraftTransaction, getIOUReportActionToApproveOrPay, setMoneyRequestParticipants, unholdRequest} from './actions/IOU'; -import {isApprover as isApproverMember} from './actions/Policy/Member'; import {createDraftWorkspace} from './actions/Policy/Policy'; import {autoSwitchToFocusMode} from './actions/PriorityMode'; import {hasCreditBankAccount} from './actions/ReimbursementAccount/store'; @@ -129,6 +128,7 @@ import { isPaidGroupPolicy as isPaidGroupPolicyPolicyUtils, isPolicyAdmin as isPolicyAdminPolicyUtils, isPolicyAuditor, + isPolicyMember, isPolicyOwner, isSubmitAndClose, shouldShowPolicy, @@ -3823,6 +3823,40 @@ function canEditMoneyRequest(reportAction: OnyxInputOrEntry, reportPolicy: OnyxEntry): boolean { + const isAdmin = isPolicyAdminPolicyUtils(reportPolicy); + const isManager = isReportManager(report); + const isSubmitter = isReportOwner(report); + const isReportAuditor = isAuditor(report); + const isIOUType = isIOUReport(report); + const isInvoiceType = isInvoiceReport(report); + const isExpenseType = isExpenseReport(report); + const isOpen = isOpenReport(report); + const isSubmitted = isProcessingReport(report); + + if (isIOUType) { + return isOpen || isSubmitted; + } + + if (isInvoiceType) { + return isOpen && !isReportAuditor; + } + + if (isExpenseType) { + if (isOpen) { + return isSubmitter || isAdmin; + } + + if (isSubmitted) { + return (isSubmitter && isAwaitingFirstLevelApproval(report)) || isManager || isAdmin; + } + + return isManager || isAdmin; + } + + return false; +} + /** * Checks if the current user can edit the provided property of an expense * @@ -10446,78 +10480,12 @@ function hasExportError(reportActions: OnyxEntry | ReportAction[] return Object.values(reportActions).some((action) => isIntegrationMessageAction(action)); } -function verifyState(report: OnyxEntry, validStates: Array>): boolean { - if (report?.stateNum === undefined || report?.stateNum === null) { - return false; - } - return validStates.includes(report?.stateNum); -} - -function verifyStatus(report: OnyxEntry, validStatuses: Array>): boolean { - if (report?.statusNum === undefined || report?.statusNum === null) { - return false; - } - return validStatuses.includes(report?.statusNum); -} - /** * Determines whether the report can be moved to the workspace. */ -function isWorkspaceEligibleForReportChange(newPolicy: OnyxEntry, report: OnyxEntry, session: OnyxEntry, currentPolicy?: OnyxEntry): boolean { - if (!session?.accountID) { - return false; - } - - const isIOU = isIOUReport(report); - const submitterLogin = report?.ownerAccountID && getLoginByAccountID(report?.ownerAccountID); - const isSubmitterMember = !!submitterLogin && !!newPolicy?.employeeList?.[submitterLogin]; - const managerLogin = report?.managerID && getLoginByAccountID(report?.managerID); - const isManagerMember = !!managerLogin && !!newPolicy?.employeeList?.[managerLogin]; - const isCurrentUserAdmin = isPolicyAdminPolicyUtils(newPolicy, session?.email); - const isAdminOfCurrentPolicy = isPolicyAdminPolicyUtils(currentPolicy, session?.email); - const isPaidGroupPolicyType = isPaidGroupPolicyPolicyUtils(newPolicy); - const isReportOpenOrSubmitted = verifyState(report, [CONST.REPORT.STATE_NUM.OPEN, CONST.REPORT.STATE_NUM.SUBMITTED]); - - // For IOUs, the sender and receiver can only change the workspace if: - // 1. The sender AND receiver are both members of the new policy OR - // 2. The sender OR receiver is an admin of the new policy. In this case, changing the policy also invites the non-member to the policy - if (isIOU && isReportOpenOrSubmitted && isPaidGroupPolicyType && ((isSubmitterMember && isManagerMember) || isCurrentUserAdmin)) { - return true; - } - - // From this point on, reports must be of type Expense, the policy must be a paid type. - // The submitter and manager must also be policy members OR the current user is an admin so they can invite the non-members to the policy. - // Additionally, if the report is not open or submitted, the current user must be an admin. - // We're temporarily disabling moving reports to a workspace if the submitter is not a member of the new policy because this flow requires additional API changes. - const isExpenseReportType = isExpenseReport(report); - if (!isExpenseReportType || !isPaidGroupPolicyType || !isSubmitterMember || (!isReportOpenOrSubmitted && !isAdminOfCurrentPolicy)) { - return false; - } - - const isCurrentUserReportSubmitter = session.accountID === report?.ownerAccountID; - if (isCurrentUserReportSubmitter) { - return true; - } - - const isCurrentUserReportApprover = isApproverMember(newPolicy, session.accountID); - if (isCurrentUserReportApprover && verifyState(report, [CONST.REPORT.STATE_NUM.SUBMITTED])) { - return true; - } - - const isCurrentUserReportPayer = isPayer(session, report, false, newPolicy); - if (isCurrentUserReportPayer && verifyState(report, [CONST.REPORT.STATE_NUM.APPROVED])) { - return true; - } - - if ( - isCurrentUserAdmin && - verifyState(report, [CONST.REPORT.STATE_NUM.APPROVED]) && - verifyStatus(report, [CONST.REPORT.STATUS_NUM.APPROVED, CONST.REPORT.STATUS_NUM.REIMBURSED, CONST.REPORT.STATUS_NUM.CLOSED]) - ) { - return true; - } - - return false; +function isWorkspaceEligibleForReportChange(newPolicy: OnyxEntry, report: OnyxEntry, policies: OnyxCollection): boolean { + const submitterEmail = getLoginByAccountID(report?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID); + return isPaidGroupPolicyPolicyUtils(newPolicy) && (isPolicyMember(submitterEmail, newPolicy?.id) || isPolicyAdmin(newPolicy?.id, policies)); } function getApprovalChain(policy: OnyxEntry, expenseReport: OnyxEntry): string[] { @@ -10792,6 +10760,7 @@ export { canCurrentUserOpenReport, canDeleteReportAction, canHoldUnholdReportAction, + canEditReportPolicy, canEditFieldOfMoneyRequest, canEditMoneyRequest, canEditPolicyDescription, diff --git a/src/pages/ReportChangeWorkspacePage.tsx b/src/pages/ReportChangeWorkspacePage.tsx index 3f4869167461..1e7dac0d7d44 100644 --- a/src/pages/ReportChangeWorkspacePage.tsx +++ b/src/pages/ReportChangeWorkspacePage.tsx @@ -56,14 +56,13 @@ function ReportChangeWorkspacePage({report}: ReportChangeWorkspacePageProps) { [session?.email, report, reportID], ); - const reportPolicy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; const {sections, shouldShowNoResultsFoundMessage, shouldShowSearchInput} = useWorkspaceList({ policies, currentUserLogin: session?.email, shouldShowPendingDeletePolicy: false, selectedPolicyID: report.policyID, searchTerm: debouncedSearchTerm, - additionalFilter: (newPolicy) => isWorkspaceEligibleForReportChange(newPolicy, report, session, reportPolicy), + additionalFilter: (newPolicy) => isWorkspaceEligibleForReportChange(newPolicy, report, policies), }); if (!isMoneyRequestReport(report) || isMoneyRequestReportPendingDeletion(report)) { diff --git a/tests/unit/PolicyUtilsTest.ts b/tests/unit/PolicyUtilsTest.ts index bcb60c0f15ac..daf66cb12c7e 100644 --- a/tests/unit/PolicyUtilsTest.ts +++ b/tests/unit/PolicyUtilsTest.ts @@ -644,18 +644,18 @@ describe('PolicyUtils', () => { await waitForBatchedUpdatesWithAct(); }); - it('returns true if report is IOU and both submitter and receiver are members of the policy', () => { + it('returns false if policy is not paid group policy', async () => { const currentUserLogin = employeeEmail; const currentUserAccountID = employeeAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), + ...createRandomPolicy(1, CONST.POLICY.TYPE.PERSONAL), employeeList: { [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - [approverEmail]: {email: approverEmail, role: CONST.POLICY.ROLE.USER}, }, }; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`]: newPolicy}; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`, newPolicy); const report = { ...createRandomReport(0), type: CONST.REPORT.TYPE.IOU, @@ -664,219 +664,56 @@ describe('PolicyUtils', () => { managerID: approverAccountID, }; - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); - expect(result).toBe(true); - }); - - it('returns true if report is IOU and the submitter is not a member but the current user is a policy admin', () => { - const currentUserLogin = adminEmail; - const currentUserAccountID = adminAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - role: CONST.POLICY.ROLE.ADMIN, - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN}, - }, - }; - const report = { - ...createRandomReport(0), - type: CONST.REPORT.TYPE.IOU, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - ownerAccountID: employeeAccountID, - }; - - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); - expect(result).toBe(true); - }); - - it('returns false if current user is not a member of the new policy', () => { - const newPolicy = { - ...createRandomPolicy(1), - employeeList: {}, - }; - const report = createRandomReport(0); - const currentUserLogin = 'nonmember@tests.com'; - const session = {email: currentUserLogin, accountID: 0}; - - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); + const result = isWorkspaceEligibleForReportChange(newPolicy, report, policies); expect(result).toBe(false); }); - it('returns true if current user is the submitter', () => { + it('returns true if policy is paid group policy and submitter is a member of the new policy', async () => { const currentUserLogin = employeeEmail; const currentUserAccountID = employeeAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; const newPolicy = { ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), employeeList: { [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - [approverEmail]: {email: approverEmail, role: CONST.POLICY.ROLE.USER}, }, }; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`]: newPolicy}; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`, newPolicy); const report = { ...createRandomReport(0), - type: CONST.REPORT.TYPE.EXPENSE, - stateNum: CONST.REPORT.STATE_NUM.OPEN, - ownerAccountID: currentUserAccountID, - managerID: approverAccountID, - }; - - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); - expect(result).toBe(true); - }); - - it('returns true if current user is a policy admin and the report is processing', () => { - const currentUserLogin = adminEmail; - const currentUserAccountID = adminAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - role: CONST.POLICY.ROLE.ADMIN, - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN}, - }, - }; - const report = { - ...createRandomReport(0), - type: CONST.REPORT.TYPE.EXPENSE, + type: CONST.REPORT.TYPE.IOU, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, ownerAccountID: currentUserAccountID, - }; - - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); - expect(result).toBe(true); - }); - - it('returns false if current user is not a policy admin and the report is approved', () => { - const currentUserLogin = approverEmail; - const currentUserAccountID = approverAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - role: CONST.POLICY.ROLE.USER, - approver: approverEmail, - employeeList: { - [employeeEmail]: {email: employeeEmail, role: CONST.POLICY.ROLE.USER}, - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - }, - }; - const report = { - ...createRandomReport(0), - type: CONST.REPORT.TYPE.EXPENSE, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - ownerAccountID: currentUserAccountID, - }; - - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); - expect(result).toBe(false); - }); - - it('returns true if current user is the approver and submitter is a member', () => { - const currentUserLogin = approverEmail; - const currentUserAccountID = approverAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const submitterLogin = employeeEmail; - const submitterAccountID = employeeAccountID; - - const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - approver: approverEmail, - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - [submitterLogin]: {email: submitterLogin, role: CONST.POLICY.ROLE.USER}, - }, - }; - const report = { - ...createRandomReport(0), - type: CONST.REPORT.TYPE.EXPENSE, managerID: approverAccountID, - ownerAccountID: submitterAccountID, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; - const result = isWorkspaceEligibleForReportChange(newPolicy, report, session); + const result = isWorkspaceEligibleForReportChange(newPolicy, report, policies); expect(result).toBe(true); }); - it('returns false if current user is approver but submitter not member', () => { - const currentUserLogin = approverEmail; - const currentUserAccountID = approverAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const newPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - }, - }; - const report = { - ...createRandomReport(0), - type: CONST.REPORT.TYPE.EXPENSE, - managerID: approverAccountID, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - ownerAccountID: employeeAccountID, - }; - - expect(isWorkspaceEligibleForReportChange(newPolicy, report, session)).toBe(false); - }); - - it('returns false if the report is approved and the current user is not an admin', () => { - const currentUserLogin = approverEmail; - const currentUserAccountID = approverAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; - - const newPolicy = { - ...createRandomPolicy(1), - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER}, - }, - }; - const report = { - ...createRandomReport(0), - ownerAccountID: employeeAccountID, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - }; - - expect(isWorkspaceEligibleForReportChange(newPolicy, report, session)).toBe(false); - }); - - it('returns true if the report is approved and the current user is an admin', () => { + it('returns true if policy is paid group policy and submitter is not a member but current user is admin', async () => { const currentUserLogin = adminEmail; - const currentUserAccountID = adminAccountID; - const session = {email: currentUserLogin, accountID: currentUserAccountID}; const newPolicy = { ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), role: CONST.POLICY.ROLE.ADMIN, employeeList: { [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN}, - [employeeEmail]: {email: employeeEmail, role: CONST.POLICY.ROLE.USER}, - }, - }; - const currentPolicy = { - ...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM), - role: CONST.POLICY.ROLE.ADMIN, - employeeList: { - [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN}, - [employeeEmail]: {email: employeeEmail, role: CONST.POLICY.ROLE.USER}, }, }; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`]: newPolicy}; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${newPolicy.id}`, newPolicy); const report = { ...createRandomReport(0), + type: CONST.REPORT.TYPE.IOU, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, ownerAccountID: employeeAccountID, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - type: CONST.REPORT.TYPE.EXPENSE, managerID: approverAccountID, - policyID: currentPolicy.id, }; - expect(isWorkspaceEligibleForReportChange(newPolicy, report, session, currentPolicy)).toBe(true); + const result = isWorkspaceEligibleForReportChange(newPolicy, report, policies); + expect(result).toBe(true); }); }); diff --git a/tests/unit/ReportSecondaryActionUtilsTest.ts b/tests/unit/ReportSecondaryActionUtilsTest.ts index 1e5d960e5956..64bb57256717 100644 --- a/tests/unit/ReportSecondaryActionUtilsTest.ts +++ b/tests/unit/ReportSecondaryActionUtilsTest.ts @@ -10,9 +10,7 @@ const MANAGER_ACCOUNT_ID = 2; const MANAGER_EMAIL = 'manager@mail.com'; const APPROVER_ACCOUNT_ID = 3; const APPROVER_EMAIL = 'approver@mail.com'; -const PAYER_ACCOUNT_ID = 4; -const PAYER_EMAIL = 'payer@mail.com'; -const ADMIN_ACCOUNT_ID = 5; +const ADMIN_ACCOUNT_ID = 4; const ADMIN_EMAIL = 'admin@mail.com'; const SESSION = { @@ -27,7 +25,7 @@ const PERSONAL_DETAILS = { const REPORT_ID = 1; const POLICY_ID = 'POLICY_ID'; - +const OLD_POLICY_ID = 'OLD_POLICY_ID'; describe('getSecondaryAction', () => { beforeAll(() => { Onyx.init({ @@ -401,13 +399,14 @@ describe('getSecondaryAction', () => { expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.HOLD)).toBe(true); }); - it('includes CHANGE_WORKSPACE option for IOU and both submitter and payer members', async () => { + it('includes CHANGE_WORKSPACE option for submitted IOU report and submitter being a member of the new policy', async () => { const report = { reportID: REPORT_ID, type: CONST.REPORT.TYPE.IOU, ownerAccountID: EMPLOYEE_ACCOUNT_ID, managerID: MANAGER_ACCOUNT_ID, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, } as unknown as Report; const personalDetails = { [EMPLOYEE_ACCOUNT_ID]: {login: EMPLOYEE_EMAIL}, @@ -421,12 +420,13 @@ describe('getSecondaryAction', () => { [MANAGER_EMAIL]: {email: MANAGER_EMAIL, role: CONST.POLICY.ROLE.USER}, }, } as unknown as Policy; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: policy}; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); await Onyx.merge(ONYXKEYS.SESSION, {email: EMPLOYEE_EMAIL, accountID: EMPLOYEE_ACCOUNT_ID}); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - const result = getSecondaryReportActions(report, [], {}, policy); + const result = getSecondaryReportActions(report, [], {}, policy, undefined, undefined, true, true, policies); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); }); @@ -437,6 +437,7 @@ describe('getSecondaryAction', () => { ownerAccountID: EMPLOYEE_ACCOUNT_ID, managerID: MANAGER_ACCOUNT_ID, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, } as unknown as Report; const personalDetails = { [ADMIN_ACCOUNT_ID]: {login: ADMIN_EMAIL}, @@ -450,12 +451,13 @@ describe('getSecondaryAction', () => { [ADMIN_EMAIL]: {email: ADMIN_EMAIL, role: CONST.POLICY.ROLE.ADMIN}, }, } as unknown as Policy; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: policy}; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); await Onyx.merge(ONYXKEYS.SESSION, {email: EMPLOYEE_EMAIL, accountID: EMPLOYEE_ACCOUNT_ID}); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - const result = getSecondaryReportActions(report, [], {}, policy); + const result = getSecondaryReportActions(report, [], {}, policy, undefined, undefined, true, true, policies); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); }); @@ -482,32 +484,28 @@ describe('getSecondaryAction', () => { [EMPLOYEE_EMAIL]: {email: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, }, } as unknown as Policy; - + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: policy}; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); await Onyx.merge(ONYXKEYS.SESSION, {email: EMPLOYEE_EMAIL, accountID: EMPLOYEE_ACCOUNT_ID}); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - const result = getSecondaryReportActions(report, [], {}, policy); + const result = getSecondaryReportActions(report, [], {}, policy, undefined, undefined, true, true, policies); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); }); - it('includes CHANGE_WORKSPACE option for submitter', async () => { - const report = { - reportID: REPORT_ID, - type: CONST.REPORT.TYPE.EXPENSE, - ownerAccountID: EMPLOYEE_ACCOUNT_ID, - managerID: MANAGER_ACCOUNT_ID, - statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - } as unknown as Report; - - const personalDetails = { - [EMPLOYEE_ACCOUNT_ID]: {login: EMPLOYEE_EMAIL}, - [MANAGER_ACCOUNT_ID]: {login: MANAGER_EMAIL}, - }; + it('includes CHANGE_WORKSPACE option for submitter, submitted report without approvals', async () => { + const oldPolicy = { + id: OLD_POLICY_ID, + type: CONST.POLICY.TYPE.TEAM, + approver: MANAGER_EMAIL, + employeeList: { + [MANAGER_EMAIL]: {email: MANAGER_EMAIL, role: CONST.POLICY.ROLE.USER}, + [EMPLOYEE_EMAIL]: {email: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, + }, + } as unknown as Policy; - const policy = { + const newPolicy = { id: POLICY_ID, type: CONST.POLICY.TYPE.TEAM, employeeList: { @@ -516,16 +514,6 @@ describe('getSecondaryAction', () => { }, } as unknown as Policy; - await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); - await Onyx.merge(ONYXKEYS.SESSION, {email: EMPLOYEE_EMAIL, accountID: EMPLOYEE_ACCOUNT_ID}); - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - - const result = getSecondaryReportActions(report, [], {}, policy); - expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); - }); - - it('includes CHANGE_WORKSPACE option for approver', async () => { const report = { reportID: REPORT_ID, type: CONST.REPORT.TYPE.EXPENSE, @@ -533,81 +521,79 @@ describe('getSecondaryAction', () => { managerID: MANAGER_ACCOUNT_ID, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + policyID: oldPolicy.id, } as unknown as Report; const personalDetails = { [EMPLOYEE_ACCOUNT_ID]: {login: EMPLOYEE_EMAIL}, - [MANAGER_ACCOUNT_ID]: {login: MANAGER_EMAIL}, - [APPROVER_ACCOUNT_ID]: {login: APPROVER_EMAIL}, + [MANAGER_ACCOUNT_ID]: {login: MANAGER_EMAIL, accountID: MANAGER_ACCOUNT_ID}, }; - const policy = { - id: POLICY_ID, + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`]: oldPolicy, [`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: newPolicy}; + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`, oldPolicy); + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, newPolicy); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); + await Onyx.merge(ONYXKEYS.SESSION, {email: EMPLOYEE_EMAIL, accountID: EMPLOYEE_ACCOUNT_ID}); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); + + const result = getSecondaryReportActions(report, [], {}, oldPolicy, undefined, undefined, true, true, policies); + expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); + }); + + it('includes CHANGE_WORKSPACE option for approver', async () => { + const oldPolicy = { + id: OLD_POLICY_ID, type: CONST.POLICY.TYPE.TEAM, approver: APPROVER_EMAIL, employeeList: { - [MANAGER_EMAIL]: {email: MANAGER_EMAIL, role: CONST.POLICY.ROLE.USER}, + [APPROVER_EMAIL]: {email: APPROVER_EMAIL, role: CONST.POLICY.ROLE.USER}, [EMPLOYEE_EMAIL]: {email: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, }, } as unknown as Policy; - await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); - await Onyx.merge(ONYXKEYS.SESSION, {email: APPROVER_EMAIL, accountID: APPROVER_ACCOUNT_ID}); - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - - const result = getSecondaryReportActions(report, [], {}, policy); - expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); - }); - - it('includes CHANGE_WORKSPACE option for payer', async () => { const report = { reportID: REPORT_ID, type: CONST.REPORT.TYPE.EXPENSE, ownerAccountID: EMPLOYEE_ACCOUNT_ID, - managerID: MANAGER_ACCOUNT_ID, + managerID: APPROVER_ACCOUNT_ID, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + policyID: oldPolicy.id, } as unknown as Report; const personalDetails = { [EMPLOYEE_ACCOUNT_ID]: {login: EMPLOYEE_EMAIL}, - [MANAGER_ACCOUNT_ID]: {login: MANAGER_EMAIL}, - [APPROVER_ACCOUNT_ID]: {login: APPROVER_EMAIL}, + [APPROVER_ACCOUNT_ID]: {login: APPROVER_EMAIL, accountID: APPROVER_ACCOUNT_ID}, }; const policy = { id: POLICY_ID, type: CONST.POLICY.TYPE.TEAM, approver: APPROVER_EMAIL, - reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, - // achAccount: { - // reimburser: PAYER_EMAIL, - // }, employeeList: { - [MANAGER_EMAIL]: {email: MANAGER_EMAIL, role: CONST.POLICY.ROLE.USER}, + [APPROVER_EMAIL]: {email: APPROVER_EMAIL, role: CONST.POLICY.ROLE.USER}, [EMPLOYEE_EMAIL]: {email: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, - [PAYER_EMAIL]: {email: PAYER_EMAIL, role: CONST.POLICY.ROLE.USER}, }, } as unknown as Policy; - + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: policy, [`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`]: oldPolicy}; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`, oldPolicy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); - await Onyx.merge(ONYXKEYS.SESSION, {email: PAYER_EMAIL, accountID: PAYER_ACCOUNT_ID}); + await Onyx.merge(ONYXKEYS.SESSION, {email: APPROVER_EMAIL, accountID: APPROVER_ACCOUNT_ID}); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - const result = getSecondaryReportActions(report, [], {}, policy); + const result = getSecondaryReportActions(report, [], {}, policy, undefined, undefined, true, true, policies); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); }); it('includes CHANGE_WORKSPACE option for admin', async () => { - const policy = { - id: POLICY_ID, + const oldPolicy = { + id: OLD_POLICY_ID, type: CONST.POLICY.TYPE.TEAM, role: CONST.POLICY.ROLE.ADMIN, employeeList: { [ADMIN_EMAIL]: {email: ADMIN_EMAIL, role: CONST.POLICY.ROLE.ADMIN}, - [EMPLOYEE_EMAIL]: {login: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, + [EMPLOYEE_EMAIL]: {email: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, }, } as unknown as Policy; @@ -618,20 +604,33 @@ describe('getSecondaryAction', () => { managerID: MANAGER_ACCOUNT_ID, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, - policyID: policy.id, + policyID: oldPolicy.id, } as unknown as Report; + const policy = { + id: POLICY_ID, + type: CONST.POLICY.TYPE.TEAM, + role: CONST.POLICY.ROLE.ADMIN, + employeeList: { + [ADMIN_EMAIL]: {email: ADMIN_EMAIL, role: CONST.POLICY.ROLE.ADMIN}, + [EMPLOYEE_EMAIL]: {login: EMPLOYEE_EMAIL, role: CONST.POLICY.ROLE.USER}, + }, + } as unknown as Policy; + const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`]: policy, [`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`]: oldPolicy}; + const personalDetails = { [EMPLOYEE_ACCOUNT_ID]: {login: EMPLOYEE_EMAIL}, [ADMIN_ACCOUNT_ID]: {login: ADMIN_EMAIL}, + [MANAGER_ACCOUNT_ID]: {login: MANAGER_EMAIL}, }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${OLD_POLICY_ID}`, oldPolicy); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); await Onyx.merge(ONYXKEYS.SESSION, {email: ADMIN_EMAIL, accountID: ADMIN_ACCOUNT_ID}); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails); - const result = getSecondaryReportActions(report, [], {}, policy); + const result = getSecondaryReportActions(report, [], {}, policy, undefined, undefined, true, true, policies); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.CHANGE_WORKSPACE)).toBe(true); });