From b56e76c16721d7e60109b0b85991fbdc947895b2 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 23 Mar 2026 11:50:15 +0800 Subject: [PATCH 1/3] removed getPolicy usages in workflow page actions --- src/libs/actions/Policy/Policy.ts | 165 +++--- ...ConnectExistingBusinessBankAccountPage.tsx | 2 + .../members/WorkspaceMemberDetailsPage.tsx | 2 +- .../rules/ExpenseReportRulesSection.tsx | 6 +- .../RulesAutoApproveReportsUnderPage.tsx | 2 +- .../rules/RulesAutoPayReportsUnderPage.tsx | 2 +- .../rules/RulesRandomReportAuditPage.tsx | 2 +- .../upgrade/WorkspaceUpgradePage.tsx | 11 +- .../WorkspaceAutoReportingFrequencyPage.tsx | 2 +- ...orkspaceAutoReportingMonthlyOffsetPage.tsx | 7 +- .../workflows/WorkspaceWorkflowsPage.tsx | 8 +- .../workflows/WorkspaceWorkflowsPayerPage.tsx | 2 +- src/types/onyx/Policy.ts | 2 +- src/types/onyx/index.ts | 3 +- tests/actions/IOUTest.ts | 29 +- tests/actions/IOUTest/SplitTest.ts | 21 +- tests/actions/PolicyTest.ts | 485 +++++++++++++++++- 17 files changed, 618 insertions(+), 133 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 6114b063e041..fcdbb5c0a6f0 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -127,7 +127,18 @@ import type { } from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {ErrorFields, Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {Attributes, CompanyAddress, CustomUnit, NetSuiteCustomList, NetSuiteCustomSegment, ProhibitedExpenses, Rate, TaxRate, UberReceiptPartner} from '@src/types/onyx/Policy'; +import type { + Attributes, + AutoReportingOffset, + CompanyAddress, + CustomUnit, + NetSuiteCustomList, + NetSuiteCustomSegment, + ProhibitedExpenses, + Rate, + TaxRate, + UberReceiptPartner, +} from '@src/types/onyx/Policy'; import type {CustomFieldType} from '@src/types/onyx/PolicyEmployee'; import type {NotificationPreference} from '@src/types/onyx/Report'; import type ReportNextStepDeprecated from '@src/types/onyx/ReportNextStepDeprecated'; @@ -229,6 +240,8 @@ type SetWorkspaceReimbursementActionParams = { state?: string; lastPaymentMethod?: LastPaymentMethodType | string; shouldUpdateLastPaymentMethod?: boolean; + currentReimbursementChoice: Policy['reimbursementChoice']; + currentAchAccount: Policy['achAccount']; bankAccountList?: BankAccountList; }; @@ -694,12 +707,15 @@ function setWorkspaceAutoHarvesting(policy: Policy, enabled: boolean) { API.write(WRITE_COMMANDS.SET_WORKSPACE_AUTO_HARVESTING, params, {optimisticData, failureData, successData}); } -function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - - const wasPolicyOnManualReporting = PolicyUtils.getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL; +function setWorkspaceAutoReportingFrequency( + policyID: string, + frequency: ValueOf, + currentAutoReportingFrequency: Policy['autoReportingFrequency'], + currentHarvesting: Policy['harvesting'], +) { + const wasPolicyOnManualReporting = + PolicyUtils.getCorrectedAutoReportingFrequency({autoReportingFrequency: currentAutoReportingFrequency, harvesting: currentHarvesting} as Policy) === + CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL; const optimisticData: Array> = [ { @@ -734,8 +750,8 @@ function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - autoReportingFrequency: policy?.autoReportingFrequency ?? null, - harvesting: policy?.harvesting ?? null, + autoReportingFrequency: currentAutoReportingFrequency ?? null, + harvesting: currentHarvesting ?? null, pendingFields: {autoReportingFrequency: null}, errorFields: {autoReportingFrequency: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.autoReportingFrequencyErrorMessage')}, }, @@ -756,14 +772,12 @@ function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf API.write(WRITE_COMMANDS.SET_WORKSPACE_AUTO_REPORTING_FREQUENCY, params, {optimisticData, failureData, successData}); } -function setWorkspaceAutoReportingMonthlyOffset(policyID: string | undefined, autoReportingOffset: number | ValueOf) { - if (!policyID) { - return; - } +function setWorkspaceAutoReportingMonthlyOffset( + policyID: string, + autoReportingOffset: number | ValueOf, + currentAutoReportingOffset: AutoReportingOffset | undefined, +) { const value = JSON.stringify({autoReportingOffset}); - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); const optimisticData: Array> = [ { @@ -781,7 +795,7 @@ function setWorkspaceAutoReportingMonthlyOffset(policyID: string | undefined, au onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - autoReportingOffset: policy?.autoReportingOffset ?? null, + autoReportingOffset: currentAutoReportingOffset ?? null, pendingFields: {autoReportingOffset: null}, errorFields: {autoReportingOffset: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.monthlyOffsetErrorMessage')}, }, @@ -802,11 +816,17 @@ function setWorkspaceAutoReportingMonthlyOffset(policyID: string | undefined, au API.write(WRITE_COMMANDS.SET_WORKSPACE_AUTO_REPORTING_MONTHLY_OFFSET, params, {optimisticData, failureData, successData}); } -function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMode: ValueOf, additionalData?: SetWorkspaceApprovalModeAdditionalData) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); +function setWorkspaceApprovalMode( + policy: OnyxEntry, + approver: string, + approvalMode: ValueOf, + additionalData?: SetWorkspaceApprovalModeAdditionalData, +) { + if (!policy) { + return; + } + const policyID = policy.id; const value = { approver, approvalMode, @@ -962,11 +982,7 @@ function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMo } } -function setWorkspacePayer(policyID: string, reimburserEmail: string) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - +function setWorkspacePayer(policyID: string, reimburserEmail: string, currentReimburser: string | undefined) { const optimisticData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -996,7 +1012,7 @@ function setWorkspacePayer(policyID: string, reimburserEmail: string) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - achAccount: {reimburser: policy?.achAccount?.reimburser ?? null}, + achAccount: {reimburser: currentReimburser ?? null}, errorFields: {reimburser: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsPayerPage.genericErrorMessage')}, pendingFields: {reimburser: null}, }, @@ -1091,11 +1107,10 @@ function setWorkspaceReimbursement({ state, lastPaymentMethod, shouldUpdateLastPaymentMethod, + currentReimbursementChoice, + currentAchAccount, bankAccountList = {}, }: SetWorkspaceReimbursementActionParams) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); const lastUsedPaymentMethod = typeof lastPaymentMethod === 'string' ? lastPaymentMethod : lastPaymentMethod?.expense?.name; const oldBankAccountID = Object.keys(bankAccountList ?? {}).find((accountID) => { @@ -1185,14 +1200,14 @@ function setWorkspaceReimbursement({ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { isLoadingWorkspaceReimbursement: false, - reimbursementChoice: policy?.reimbursementChoice ?? null, + reimbursementChoice: currentReimbursementChoice ?? null, achAccount: { - reimburser: policy?.achAccount?.reimburser ?? null, - bankAccountID: policy?.achAccount?.bankAccountID ?? null, - accountNumber: policy?.achAccount?.accountNumber ?? null, - addressName: policy?.achAccount?.addressName ?? null, - bankName: policy?.achAccount?.bankName ?? null, - state: policy?.achAccount?.state ?? null, + reimburser: currentAchAccount?.reimburser ?? null, + bankAccountID: currentAchAccount?.bankAccountID ?? null, + accountNumber: currentAchAccount?.accountNumber ?? null, + addressName: currentAchAccount?.addressName ?? null, + bankName: currentAchAccount?.bankName ?? null, + state: currentAchAccount?.state ?? null, }, errorFields: {reimbursementChoice: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, pendingFields: {reimbursementChoice: null}, @@ -6361,13 +6376,10 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) * Call the API to enable or disable self approvals for the reports * @param policyID - id of the policy to apply the naming pattern to * @param preventSelfApproval - flag whether to prevent workspace members from approving their own expense reports + * @param currentPreventSelfApproval - current value of preventSelfApproval */ -function setPolicyPreventSelfApproval(policyID: string, preventSelfApproval: boolean) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - - if (preventSelfApproval === policy?.preventSelfApproval) { +function setPolicyPreventSelfApproval(policyID: string, preventSelfApproval: boolean, currentPreventSelfApproval: boolean | undefined) { + if (preventSelfApproval === currentPreventSelfApproval) { return; } @@ -6402,7 +6414,7 @@ function setPolicyPreventSelfApproval(policyID: string, preventSelfApproval: boo onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - preventSelfApproval: policy?.preventSelfApproval ?? false, + preventSelfApproval: currentPreventSelfApproval ?? false, pendingFields: { preventSelfApproval: null, }, @@ -6429,16 +6441,13 @@ function setPolicyPreventSelfApproval(policyID: string, preventSelfApproval: boo * Call the API to apply automatic approval limit for the given policy * @param policyID - id of the policy to apply the limit to * @param limit - max amount for auto-approval of the reports in the given policy + * @param currentAutoApprovalLimit - current value of autoApproval.limit */ -function setPolicyAutomaticApprovalLimit(policyID: string, limit: string) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - +function setPolicyAutomaticApprovalLimit(policyID: string, limit: string, currentAutoApprovalLimit: number | undefined) { const fallbackLimit = limit === '' ? '0' : limit; const parsedLimit = CurrencyUtils.convertToBackendAmount(parseFloat(fallbackLimit)); - if (parsedLimit === (policy?.autoApproval?.limit ?? CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_DEFAULT_CENTS)) { + if (parsedLimit === (currentAutoApprovalLimit ?? CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_DEFAULT_CENTS)) { return; } @@ -6476,7 +6485,7 @@ function setPolicyAutomaticApprovalLimit(policyID: string, limit: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { autoApproval: { - limit: policy?.autoApproval?.limit ?? CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_DEFAULT_CENTS, + limit: currentAutoApprovalLimit ?? CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_DEFAULT_CENTS, pendingFields: { limit: null, }, @@ -6504,16 +6513,14 @@ function setPolicyAutomaticApprovalLimit(policyID: string, limit: string) { * Call the API to set the audit rate for the given policy * @param policyID - id of the policy to apply the limit to * @param auditRate - percentage of the reports to be qualified for a random audit + * @param currentAutoApprovalAuditRate - current value of autoApproval.auditRate */ -function setPolicyAutomaticApprovalRate(policyID: string, auditRate: string) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); +function setPolicyAutomaticApprovalRate(policyID: string, auditRate: string, currentAutoApprovalAuditRate: number | undefined) { const fallbackAuditRate = auditRate === '' ? '0' : auditRate; const parsedAuditRate = parseInt(fallbackAuditRate, 10) / 100; // The auditRate arrives as an int to this method so we will convert it to a float before sending it to the API. - if (parsedAuditRate === (policy?.autoApproval?.auditRate ?? CONST.POLICY.RANDOM_AUDIT_DEFAULT_PERCENTAGE)) { + if (parsedAuditRate === (currentAutoApprovalAuditRate ?? CONST.POLICY.RANDOM_AUDIT_DEFAULT_PERCENTAGE)) { return; } @@ -6553,7 +6560,7 @@ function setPolicyAutomaticApprovalRate(policyID: string, auditRate: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { autoApproval: { - auditRate: policy?.autoApproval?.auditRate ?? CONST.POLICY.RANDOM_AUDIT_DEFAULT_PERCENTAGE, + auditRate: currentAutoApprovalAuditRate ?? CONST.POLICY.RANDOM_AUDIT_DEFAULT_PERCENTAGE, pendingFields: { auditRate: null, }, @@ -6582,12 +6589,14 @@ function setPolicyAutomaticApprovalRate(policyID: string, auditRate: string) { * @param policyID - id of the policy to apply the limit to * @param enabled - whether auto-approve for the reports is enabled in the given policy */ -function enableAutoApprovalOptions(policyID: string, enabled: boolean) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - - if (enabled === policy?.shouldShowAutoApprovalOptions) { +function enableAutoApprovalOptions( + policyID: string, + enabled: boolean, + currentShouldShowAutoApprovalOptions: boolean | undefined, + currentAutoApprovalLimit: number | undefined, + currentAutoApprovalAuditRate: number | undefined, +) { + if (enabled === currentShouldShowAutoApprovalOptions) { return; } @@ -6595,7 +6604,7 @@ function enableAutoApprovalOptions(policyID: string, enabled: boolean) { auditRate: enabled ? CONST.POLICY.RANDOM_AUDIT_SUGGESTED_PERCENTAGE : 0, limit: enabled ? CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_SUGGESTED_CENTS : 0, }; - const autoApprovalFailureValues = {autoApproval: {limit: policy?.autoApproval?.limit, auditRate: policy?.autoApproval?.auditRate, pendingFields: null}}; + const autoApprovalFailureValues = {autoApproval: {limit: currentAutoApprovalLimit, auditRate: currentAutoApprovalAuditRate, pendingFields: null}}; const optimisticData: Array> = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -6635,7 +6644,7 @@ function enableAutoApprovalOptions(policyID: string, enabled: boolean) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { ...autoApprovalFailureValues, - shouldShowAutoApprovalOptions: policy?.shouldShowAutoApprovalOptions, + shouldShowAutoApprovalOptions: currentShouldShowAutoApprovalOptions, pendingFields: { shouldShowAutoApprovalOptions: null, }, @@ -6660,14 +6669,11 @@ function enableAutoApprovalOptions(policyID: string, enabled: boolean) { * @param policyID - id of the policy to apply the limit to * @param limit - max amount for auto-payment for the reports in the given policy */ -function setPolicyAutoReimbursementLimit(policyID: string, limit: string) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); +function setPolicyAutoReimbursementLimit(policyID: string, limit: string, currentAutoReimbursementLimit: number | undefined) { const fallbackLimit = limit === '' ? '0' : limit; const parsedLimit = CurrencyUtils.convertToBackendAmount(parseFloat(fallbackLimit)); - if (parsedLimit === (policy?.autoReimbursement?.limit ?? CONST.POLICY.AUTO_REIMBURSEMENT_LIMIT_DEFAULT_CENTS)) { + if (parsedLimit === (currentAutoReimbursementLimit ?? 0)) { return; } @@ -6707,7 +6713,7 @@ function setPolicyAutoReimbursementLimit(policyID: string, limit: string) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - autoReimbursement: {limit: policy?.autoReimbursement?.limit ?? policy?.autoReimbursementLimit, pendingFields: {limit: null}}, + autoReimbursement: {limit: currentAutoReimbursementLimit ?? 0, pendingFields: {limit: null}}, errorFields: { autoReimbursement: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), }, @@ -6733,16 +6739,17 @@ function setPolicyAutoReimbursementLimit(policyID: string, limit: string) { * @param policyID - id of the policy to apply the limit to * @param enabled - whether auto-payment for the reports is enabled in the given policy */ -function enablePolicyAutoReimbursementLimit(policyID: string, enabled: boolean) { - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policy = getPolicy(policyID); - - if (enabled === policy?.shouldShowAutoReimbursementLimitOption) { +function enablePolicyAutoReimbursementLimit( + policyID: string, + enabled: boolean, + currentShouldShowAutoReimbursementLimitOption: boolean | undefined, + currentAutoReimbursementLimit: number | undefined, +) { + if (enabled === currentShouldShowAutoReimbursementLimitOption) { return; } - const autoReimbursementFailureValues = {autoReimbursement: {limit: policy?.autoReimbursement?.limit, pendingFields: null}}; + const autoReimbursementFailureValues = {autoReimbursement: {limit: currentAutoReimbursementLimit, pendingFields: null}}; const autoReimbursementValues = {limit: enabled ? CONST.POLICY.AUTO_REIMBURSEMENT_LIMIT_SUGGESTED_CENTS : CONST.POLICY.AUTO_REIMBURSEMENT_LIMIT_DEFAULT_CENTS}; const optimisticData: Array> = [ { @@ -6783,7 +6790,7 @@ function enablePolicyAutoReimbursementLimit(policyID: string, enabled: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { ...autoReimbursementFailureValues, - shouldShowAutoReimbursementLimitOption: policy?.shouldShowAutoReimbursementLimitOption, + shouldShowAutoReimbursementLimitOption: currentShouldShowAutoReimbursementLimitOption, pendingFields: { shouldShowAutoReimbursementLimitOption: null, }, diff --git a/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx b/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx index 79e749d9baf6..7f2134683cb1 100644 --- a/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx +++ b/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx @@ -50,6 +50,8 @@ function ConnectExistingBusinessBankAccountPage({route}: ConnectExistingBusiness if (bankAccountList && methodID && !bankAccountList[methodID]?.accountData?.policyIDs?.includes(policyID)) { setWorkspaceReimbursement({ policyID, + currentAchAccount: policy?.achAccount, + currentReimbursementChoice: policy?.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: methodID ?? CONST.DEFAULT_NUMBER_ID, reimburserEmail: newReimburserEmail, diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index cf9182225e86..92995e60d447 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -168,7 +168,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const remainingEmployeeCount = previousEmployeesCount - 1; if (remainingEmployeeCount === 1 && policy?.preventSelfApproval) { // We can't let the "Prevent Self Approvals" enabled if there's only one workspace user - setPolicyPreventSelfApproval(policyID, false); + setPolicyPreventSelfApproval(policyID, false, policy.preventSelfApproval); } }; diff --git a/src/pages/workspace/rules/ExpenseReportRulesSection.tsx b/src/pages/workspace/rules/ExpenseReportRulesSection.tsx index 862f637099fa..3c495989b2bc 100644 --- a/src/pages/workspace/rules/ExpenseReportRulesSection.tsx +++ b/src/pages/workspace/rules/ExpenseReportRulesSection.tsx @@ -55,7 +55,7 @@ function ExpenseReportRulesSection({policyID}: ExpenseReportRulesSectionProps) { return; } - setPolicyPreventSelfApproval(policyID, isEnabled); + setPolicyPreventSelfApproval(policyID, isEnabled, policy?.preventSelfApproval); }, }, { @@ -77,7 +77,7 @@ function ExpenseReportRulesSection({policyID}: ExpenseReportRulesSectionProps) { return; } - enableAutoApprovalOptions(policyID, isEnabled); + enableAutoApprovalOptions(policyID, isEnabled, policy?.shouldShowAutoApprovalOptions, policy?.autoApproval?.limit, policy?.autoApproval?.auditRate); }, subMenuItems: [ { - setPolicyAutomaticApprovalLimit(policyID, maxExpenseAutoApprovalAmount); + setPolicyAutomaticApprovalLimit(policyID, maxExpenseAutoApprovalAmount, policy?.autoApproval?.limit); Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); }} submitButtonText={translate('common.save')} diff --git a/src/pages/workspace/rules/RulesAutoPayReportsUnderPage.tsx b/src/pages/workspace/rules/RulesAutoPayReportsUnderPage.tsx index ebee524cd66c..20a302fe598e 100644 --- a/src/pages/workspace/rules/RulesAutoPayReportsUnderPage.tsx +++ b/src/pages/workspace/rules/RulesAutoPayReportsUnderPage.tsx @@ -70,7 +70,7 @@ function RulesAutoPayReportsUnderPage({route}: RulesAutoPayReportsUnderPageProps formID={ONYXKEYS.FORMS.RULES_AUTO_PAY_REPORTS_UNDER_MODAL_FORM} validate={validateLimit} onSubmit={({maxExpenseAutoPayAmount}) => { - setPolicyAutoReimbursementLimit(policyID, maxExpenseAutoPayAmount); + setPolicyAutoReimbursementLimit(policyID, maxExpenseAutoPayAmount, policy?.autoReimbursement?.limit ?? policy?.autoReimbursementLimit); Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); }} submitButtonText={translate('common.save')} diff --git a/src/pages/workspace/rules/RulesRandomReportAuditPage.tsx b/src/pages/workspace/rules/RulesRandomReportAuditPage.tsx index f90f1a882b81..101b807a05ed 100644 --- a/src/pages/workspace/rules/RulesRandomReportAuditPage.tsx +++ b/src/pages/workspace/rules/RulesRandomReportAuditPage.tsx @@ -54,7 +54,7 @@ function RulesRandomReportAuditPage({route}: RulesRandomReportAuditPageProps) { style={[styles.flexGrow1, styles.mh5]} formID={ONYXKEYS.FORMS.RULES_RANDOM_REPORT_AUDIT_MODAL_FORM} onSubmit={({auditRatePercentage}) => { - setPolicyAutomaticApprovalRate(policyID, auditRatePercentage); + setPolicyAutomaticApprovalRate(policyID, auditRatePercentage, policy?.autoApproval?.auditRate); Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); }} submitButtonText={translate('common.save')} diff --git a/src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx b/src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx index 7deba2a1d5c8..7c357e9356d6 100644 --- a/src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx +++ b/src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx @@ -149,13 +149,13 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) { } switch (feature.id) { case CONST.UPGRADE_FEATURE_INTRO_MAPPING.preventSelfApproval.id: - setPolicyPreventSelfApproval(policyID, true); + setPolicyPreventSelfApproval(policyID, true, policy?.preventSelfApproval); break; case CONST.UPGRADE_FEATURE_INTRO_MAPPING.autoApproveCompliantReports.id: - enableAutoApprovalOptions(policyID, true); + enableAutoApprovalOptions(policyID, true, policy?.shouldShowAutoApprovalOptions, policy?.autoApproval?.limit, policy?.autoApproval?.auditRate); break; case CONST.UPGRADE_FEATURE_INTRO_MAPPING.autoPayApprovedReports.id: - enablePolicyAutoReimbursementLimit(policyID, true); + enablePolicyAutoReimbursementLimit(policyID, true, policy?.shouldShowAutoReimbursementLimitOption, policy?.autoReimbursement?.limit); break; case CONST.UPGRADE_FEATURE_INTRO_MAPPING.reportFields.id: switch (route.params.featureName) { @@ -195,7 +195,7 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) { enablePerDiem(policyID, true, perDiemCustomUnit?.customUnitID, false); break; case CONST.UPGRADE_FEATURE_INTRO_MAPPING.approvals.id: - setWorkspaceApprovalMode(policyID, defaultApprover, CONST.POLICY.APPROVAL_MODE.ADVANCED); + setWorkspaceApprovalMode(policy, defaultApprover, CONST.POLICY.APPROVAL_MODE.ADVANCED); break; default: } @@ -203,8 +203,7 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) { categoryId, feature, perDiemCustomUnit?.customUnitID, - policy?.connections?.xero?.config, - policy?.connections?.xero?.data, + policy, policyID, qboConfig?.syncClasses, qboConfig?.syncCustomers, diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx index 8e0a40998843..0b94b5a3e8a7 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx @@ -57,7 +57,7 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor if (!policy?.id) { return; } - setWorkspaceAutoReportingFrequency(policy.id, item.keyForList as AutoReportingFrequencyKey); + setWorkspaceAutoReportingFrequency(policy.id, item.keyForList as AutoReportingFrequencyKey, policy.autoReportingFrequency, policy.harvesting); if (item.keyForList === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY) { return; diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index e8c67caf12c1..167c6cfeb448 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -66,8 +66,11 @@ function WorkspaceAutoReportingMonthlyOffsetPage({policy, route}: WorkspaceAutoR const filteredDaysOfMonth = daysOfMonth.filter((dayItem) => dayItem.text.toLowerCase().includes(trimmedText)); const onSelectDayOfMonth = (item: WorkspaceAutoReportingMonthlyOffsetPageItem) => { - setWorkspaceAutoReportingMonthlyOffset(policy?.id, item.isNumber ? parseInt(item.keyForList, 10) : (item.keyForList as AutoReportingOffsetKeys)); - Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_AUTOREPORTING_FREQUENCY.getRoute(policy?.id)); + if (!policy?.id) { + return; + } + setWorkspaceAutoReportingMonthlyOffset(policy.id, item.isNumber ? parseInt(item.keyForList, 10) : (item.keyForList as AutoReportingOffsetKeys), policy.autoReportingOffset); + Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_AUTOREPORTING_FREQUENCY.getRoute(policy.id)); }; const textInputOptions = useMemo( () => ({ diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 38fc111be301..3eaefb02ad9b 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -171,12 +171,12 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { }, []); const confirmDisableApprovals = useCallback(() => { - setWorkspaceApprovalMode(route.params.policyID, policy?.owner ?? '', CONST.POLICY.APPROVAL_MODE.OPTIONAL, { + setWorkspaceApprovalMode(policy, policy?.owner ?? '', CONST.POLICY.APPROVAL_MODE.OPTIONAL, { reportNextSteps: allReportNextSteps, transactionViolations, betas, }); - }, [allReportNextSteps, betas, policy?.owner, route.params.policyID, transactionViolations]); + }, [allReportNextSteps, betas, policy, transactionViolations]); // User should be allowed to add new Approval Workflow only if he's upgraded to Control Plan, otherwise redirected to the Upgrade Page const addApprovalAction = useCallback(() => { @@ -311,7 +311,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { }); return; } - setWorkspaceApprovalMode(route.params.policyID, policy?.owner ?? '', isEnabled ? updateApprovalMode : CONST.POLICY.APPROVAL_MODE.OPTIONAL, { + setWorkspaceApprovalMode(policy, policy?.owner ?? '', isEnabled ? updateApprovalMode : CONST.POLICY.APPROVAL_MODE.OPTIONAL, { reportNextSteps: allReportNextSteps, transactionViolations, betas, @@ -399,6 +399,8 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const newReimburserEmail = policy?.achAccount?.reimburser ?? policy?.owner; setWorkspaceReimbursement({ policyID: route.params.policyID, + currentAchAccount: policy?.achAccount, + currentReimbursementChoice: policy?.reimbursementChoice, reimbursementChoice: newReimbursementChoice, reimburserEmail: newReimburserEmail ?? '', bankAccountID: policy?.achAccount?.bankAccountID, diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx index 314626847993..df1e15dc56d7 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx @@ -187,7 +187,7 @@ function WorkspaceWorkflowsPayerPage({route, policy, personalDetails, isLoadingR Navigation.closeRHPFlow(); return; } - setWorkspacePayer(policy?.id, authorizedPayerEmail); + setWorkspacePayer(policy.id, authorizedPayerEmail, policy.achAccount?.reimburser); Navigation.closeRHPFlow(); }; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 89f318f8bd80..68aa91853d81 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1548,7 +1548,7 @@ type ProhibitedExpenses = OnyxCommon.OnyxValueWithOfflineFeedback<{ }>; /** Day of the month to schedule submission */ -type AutoReportingOffset = number | ValueOf; +export type AutoReportingOffset = number | ValueOf; /** Types of policy report fields */ type PolicyReportFieldType = 'text' | 'date' | 'dropdown' | 'formula'; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index b2147e37f8a1..abac2de577ec 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -105,7 +105,7 @@ import type {PersonalDetailsList, PersonalDetailsMetadata} from './PersonalDetai import type PersonalDetails from './PersonalDetails'; import type PlaidData from './PlaidData'; import type Policy from './Policy'; -import type {PolicyConnectionName, PolicyConnectionSyncProgress, PolicyReportField, TaxRate, TaxRates, TaxRatesWithDefault} from './Policy'; +import type {AutoReportingOffset, PolicyConnectionName, PolicyConnectionSyncProgress, PolicyReportField, TaxRate, TaxRates, TaxRatesWithDefault} from './Policy'; import type {PolicyCategories, PolicyCategory} from './PolicyCategory'; import type {PolicyEmployeeList} from './PolicyEmployee'; import type PolicyEmployee from './PolicyEmployee'; @@ -260,6 +260,7 @@ export type { PolicyConnectionName, PolicyConnectionSyncProgress, PolicyOwnershipChangeChecks, + AutoReportingOffset, PolicyTag, PolicyTags, PolicyTagLists, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 5054f2febac2..3b300f93ceab 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -9440,7 +9440,7 @@ describe('actions/IOU', () => { let expenseReport: OnyxEntry; let chatReport: OnyxEntry; return waitForBatchedUpdates() - .then(() => { + .then(async () => { const policyID = generatePolicyID(); createWorkspace({ policyOwnerEmail: CARLOS_EMAIL, @@ -9454,8 +9454,9 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); return waitForBatchedUpdates(); }) .then( @@ -9585,7 +9586,7 @@ describe('actions/IOU', () => { let chatReport: OnyxEntry; return waitForBatchedUpdates() - .then(() => { + .then(async () => { const policyID = generatePolicyID(); createWorkspace({ policyOwnerEmail: CARLOS_EMAIL, @@ -9599,7 +9600,8 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); return waitForBatchedUpdates(); }) .then( @@ -10164,8 +10166,9 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); return waitForBatchedUpdates() - .then(() => { - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.DYNAMICEXTERNAL); + .then(async () => { + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.DYNAMICEXTERNAL, {}); return waitForBatchedUpdates(); }) .then( @@ -10389,7 +10392,7 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); await waitForBatchedUpdates(); let chatReport: OnyxEntry; @@ -12579,8 +12582,9 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); await waitForBatchedUpdates(); await getOnyxData({ key: ONYXKEYS.COLLECTION.REPORT, @@ -12753,8 +12757,9 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, RORY_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, RORY_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); await waitForBatchedUpdates(); await getOnyxData({ key: ONYXKEYS.COLLECTION.REPORT, @@ -12931,7 +12936,8 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); await waitForBatchedUpdates(); await getOnyxData({ @@ -13118,8 +13124,9 @@ describe('actions/IOU', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC, {}); await waitForBatchedUpdates(); await getOnyxData({ diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index e7e34fbde6fb..998c90ca4fdc 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -2067,7 +2067,8 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { isSelfTourViewed: false, hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ @@ -2539,8 +2540,9 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ key: ONYXKEYS.COLLECTION.REPORT, @@ -2713,8 +2715,9 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, RORY_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, RORY_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ key: ONYXKEYS.COLLECTION.REPORT, @@ -2891,7 +2894,8 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ @@ -3078,8 +3082,9 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { hasActiveAdminPolicies: false, }); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); // Change the approval mode for the policy since default is Submit and Close - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ @@ -3341,7 +3346,8 @@ describe('updateSplitTransactions', () => { isSelfTourViewed: false, hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ @@ -3469,7 +3475,8 @@ describe('updateSplitTransactions', () => { isSelfTourViewed: false, hasActiveAdminPolicies: false, }); - setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); await getOnyxData({ diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index 9a52f3aceabb..5df1a6623e94 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -2008,7 +2008,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); let policy: OnyxEntry = await new Promise((resolve) => { @@ -2081,7 +2081,7 @@ describe('actions/Policy', () => { // eslint-disable-next-line @typescript-eslint/no-deprecated -- We need a minimal ReportNextStepDeprecated shape to simulate rollback on failure. const currentNextStep2 = {type: 'neutral', icon: CONST.NEXT_STEP.ICONS.CHECKMARK, message: [{text: 'Old next step 2'}]} as never; - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL, { + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL, { reportNextSteps: { [nextStepKey1]: currentNextStep1, [nextStepKey2]: currentNextStep2, @@ -2134,7 +2134,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); expect(getAllPolicyReportsSpy).not.toHaveBeenCalled(); @@ -2182,7 +2182,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); const policy: OnyxEntry = await new Promise((resolve) => { @@ -2229,7 +2229,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); expect(apiWriteSpy).toHaveBeenCalledWith(WRITE_COMMANDS.DISABLE_POLICY_APPROVALS, expect.objectContaining({policyID}), expect.anything()); @@ -2254,7 +2254,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); expect(apiWriteSpy).toHaveBeenCalledWith(WRITE_COMMANDS.SET_WORKSPACE_APPROVAL_MODE, expect.objectContaining({policyID}), expect.anything()); @@ -2296,7 +2296,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); // optimisticMembersState should be empty for non-OPTIONAL mode @@ -2341,7 +2341,7 @@ describe('actions/Policy', () => { // Simulate API failure mockFetch?.fail?.(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); const policy: OnyxEntry = await new Promise((resolve) => { @@ -2398,7 +2398,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); const writeOptions = apiWriteSpy.mock.calls.at(0)?.at(2) as @@ -2448,7 +2448,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); const writeOptions = apiWriteSpy.mock.calls.at(0)?.at(2) as @@ -2485,7 +2485,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); let policy: OnyxEntry = await new Promise((resolve) => { @@ -2541,7 +2541,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); let policy: OnyxEntry = await new Promise((resolve) => { @@ -2594,7 +2594,7 @@ describe('actions/Policy', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); let policy: OnyxEntry = await new Promise((resolve) => { @@ -2651,7 +2651,7 @@ describe('actions/Policy', () => { mockFetch?.fail?.(); - Policy.setWorkspaceApprovalMode(policyID, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); + Policy.setWorkspaceApprovalMode(fakePolicy, ESH_EMAIL, CONST.POLICY.APPROVAL_MODE.OPTIONAL); await waitForBatchedUpdates(); const policy: OnyxEntry = await new Promise((resolve) => { @@ -3257,6 +3257,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3293,6 +3295,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3325,6 +3329,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3359,6 +3365,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3390,6 +3398,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3417,6 +3427,8 @@ describe('actions/Policy', () => { Policy.setWorkspaceReimbursement({ policyID: FAKE_POLICY_ID, + currentAchAccount: fakePolicy.achAccount, + currentReimbursementChoice: fakePolicy.reimbursementChoice, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: FAKE_BANK_ACCOUNT_ID, reimburserEmail: FAKE_REIMBURSER_EMAIL, @@ -3443,4 +3455,449 @@ describe('actions/Policy', () => { ); }); }); + + describe('setWorkspaceAutoReportingFrequency', () => { + it('should update auto reporting frequency optimistically and succeed', async () => { + // Given a workspace with immediate reporting frequency + const policy = { + ...createRandomPolicy(0), + autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE, + harvesting: {enabled: true}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting auto reporting frequency to monthly + Policy.setWorkspaceAutoReportingFrequency(policy.id, CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY, policy.autoReportingFrequency, policy.harvesting); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReportingFrequency).toBe(CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY); + expect(updatedPolicy?.pendingFields?.autoReportingFrequency).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.autoReportingFrequency).toBeUndefined(); + }); + + it('should revert auto reporting frequency when fail', async () => { + // Given a workspace with immediate reporting frequency + const policy = { + ...createRandomPolicy(0), + autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE, + harvesting: {enabled: true}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting auto reporting frequency to monthly but fail + mockFetch.fail(); + Policy.setWorkspaceAutoReportingFrequency(policy.id, CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY, policy.autoReportingFrequency, policy.harvesting.enabled); + await waitForBatchedUpdates(); + + // Then the frequency should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReportingFrequency).toBe(CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE); + expect(updatedPolicy?.pendingFields?.autoReportingFrequency).toBeUndefined(); + expect(updatedPolicy?.errorFields?.autoReportingFrequency).toBeTruthy(); + }); + }); + + describe('setWorkspaceAutoReportingMonthlyOffset', () => { + it('should update auto reporting monthly offset optimistically and succeed', async () => { + // Given a workspace with offset 1 + const policy = { + ...createRandomPolicy(0), + autoReportingOffset: 1, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting auto reporting offset to 2 + Policy.setWorkspaceAutoReportingMonthlyOffset(policy.id, 2, policy.autoReportingOffset); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReportingOffset).toBe(2); + expect(updatedPolicy?.pendingFields?.autoReportingOffset).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.autoReportingOffset).toBeUndefined(); + }); + + it('should revert auto reporting monthly offset when fail', async () => { + // Given a workspace with offset 1 + const policy = { + ...createRandomPolicy(0), + autoReportingOffset: 1, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting auto reporting offset to 2 but fail + mockFetch.fail(); + Policy.setWorkspaceAutoReportingMonthlyOffset(policy.id, 2, policy.autoReportingOffset); + await waitForBatchedUpdates(); + + // Then the offset should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReportingOffset).toBe(1); + expect(updatedPolicy?.pendingFields?.autoReportingOffset).toBeUndefined(); + expect(updatedPolicy?.errorFields?.autoReportingOffset).toBeTruthy(); + }); + }); + + describe('setWorkspacePayer', () => { + it('should update workspace payer optimistically and succeed', async () => { + // Given a workspace with a payer + const policy = { + ...createRandomPolicy(0), + reimburser: 'old@test.com', + achAccount: {reimburser: 'old@test.com'}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting workspace payer to new@test.com + Policy.setWorkspacePayer(policy.id, 'new@test.com', policy.reimburser); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.reimburser).toBe('new@test.com'); + expect(updatedPolicy?.achAccount?.reimburser).toBe('new@test.com'); + expect(updatedPolicy?.pendingFields?.reimburser).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.reimburser).toBeUndefined(); + }); + + it('should revert workspace payer when fail', async () => { + // Given a workspace with a payer + const policy = { + ...createRandomPolicy(0), + reimburser: 'old@test.com', + achAccount: {reimburser: 'old@test.com'}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting workspace payer to new@test.com but fail + mockFetch.fail(); + Policy.setWorkspacePayer(policy.id, 'new@test.com', policy.reimburser); + await waitForBatchedUpdates(); + + // Then the payer should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.achAccount?.reimburser).toBe('old@test.com'); + expect(updatedPolicy?.pendingFields?.reimburser).toBeUndefined(); + expect(updatedPolicy?.errorFields?.reimburser).toBeTruthy(); + }); + }); + + describe('setPolicyPreventSelfApproval', () => { + it('should update prevent self approval optimistically and succeed', async () => { + // Given a workspace with prevent self approval disabled + const policy = { + ...createRandomPolicy(0), + preventSelfApproval: false, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When enabling prevent self approval + Policy.setPolicyPreventSelfApproval(policy.id, true, policy.preventSelfApproval); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.preventSelfApproval).toBe(true); + expect(updatedPolicy?.pendingFields?.preventSelfApproval).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.preventSelfApproval).toBeUndefined(); + }); + + it('should revert prevent self approval when fail', async () => { + // Given a workspace with prevent self approval disabled + const policy = { + ...createRandomPolicy(0), + preventSelfApproval: false, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When enabling prevent self approval but fail + mockFetch.fail(); + Policy.setPolicyPreventSelfApproval(policy.id, true, policy.preventSelfApproval); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.preventSelfApproval).toBe(false); + expect(updatedPolicy?.pendingFields?.preventSelfApproval).toBeUndefined(); + expect(updatedPolicy?.errorFields?.preventSelfApproval).toBeTruthy(); + }); + }); + + describe('setPolicyAutomaticApprovalLimit', () => { + it('should update automatic approval limit optimistically and succeed', async () => { + // Given a workspace with auto approval limit 100 + const policy = { + ...createRandomPolicy(0), + autoApproval: {limit: 10000}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting automatic approval limit to 200 + Policy.setPolicyAutomaticApprovalLimit(policy.id, '200', policy.autoApproval.limit); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.limit).toBe(20000); + expect(updatedPolicy?.autoApproval?.pendingFields?.limit).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.pendingFields?.limit).toBeUndefined(); + }); + + it('should revert automatic approval limit when fail', async () => { + // Given a workspace with auto approval limit 100 + const policy = { + ...createRandomPolicy(0), + autoApproval: {limit: 10000}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting automatic approval limit to 200 but fail + mockFetch.fail(); + Policy.setPolicyAutomaticApprovalLimit(policy.id, '200', policy.autoApproval.limit); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.limit).toBe(10000); + expect(updatedPolicy?.autoApproval?.pendingFields?.limit).toBeUndefined(); + expect(updatedPolicy?.errorFields?.autoApproval).toBeTruthy(); + }); + }); + + describe('setPolicyAutomaticApprovalRate', () => { + it('should update automatic approval rate optimistically and succeed', async () => { + // Given a workspace with auto approval audit rate 0.5 + const policy = { + ...createRandomPolicy(0), + autoApproval: {auditRate: 0.5}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting automatic approval rate to 80% + Policy.setPolicyAutomaticApprovalRate(policy.id, '80', policy.autoApproval.auditRate); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.auditRate).toBe(0.8); + expect(updatedPolicy?.autoApproval?.pendingFields?.auditRate).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.pendingFields?.auditRate).toBeUndefined(); + }); + + it('should revert automatic approval rate when fail', async () => { + // Given a workspace with auto approval audit rate 0.5 + const policy = { + ...createRandomPolicy(0), + autoApproval: {auditRate: 0.5}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting automatic approval rate to 80% but fail + mockFetch.fail(); + Policy.setPolicyAutomaticApprovalRate(policy.id, '80', policy.autoApproval.auditRate); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoApproval?.auditRate).toBe(0.5); + expect(updatedPolicy?.autoApproval?.pendingFields?.auditRate).toBeUndefined(); + expect(updatedPolicy?.errorFields?.autoApproval).toBeTruthy(); + }); + }); + + describe('enableAutoApprovalOptions', () => { + it('should enable auto approval options optimistically and succeed', async () => { + // Given a workspace with auto approval options disabled + const policy = { + ...createRandomPolicy(0), + shouldShowAutoApprovalOptions: false, + autoApproval: {limit: 0, auditRate: 0}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When enabling auto approval options + Policy.enableAutoApprovalOptions(policy.id, true, policy.shouldShowAutoApprovalOptions, policy.autoApproval.limit, policy.autoApproval.auditRate); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.shouldShowAutoApprovalOptions).toBe(true); + expect(updatedPolicy?.autoApproval?.limit).toBe(CONST.POLICY.AUTO_APPROVE_REPORTS_UNDER_SUGGESTED_CENTS); + expect(updatedPolicy?.autoApproval?.auditRate).toBe(CONST.POLICY.RANDOM_AUDIT_SUGGESTED_PERCENTAGE); + expect(updatedPolicy?.pendingFields?.shouldShowAutoApprovalOptions).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.shouldShowAutoApprovalOptions).toBeUndefined(); + }); + + it('should revert auto approval options when fail', async () => { + // Given a workspace with auto approval options disabled + const policy = { + ...createRandomPolicy(0), + shouldShowAutoApprovalOptions: false, + autoApproval: {limit: 0, auditRate: 0}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When enabling auto approval options but fail + mockFetch.fail(); + Policy.enableAutoApprovalOptions(policy.id, true, policy.shouldShowAutoApprovalOptions, policy.autoApproval.limit, policy.autoApproval.auditRate); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.shouldShowAutoApprovalOptions).toBe(false); + expect(updatedPolicy?.autoApproval?.limit).toBe(0); + expect(updatedPolicy?.autoApproval?.auditRate).toBe(0); + expect(updatedPolicy?.pendingFields?.shouldShowAutoApprovalOptions).toBeUndefined(); + }); + }); + + describe('setPolicyAutoReimbursementLimit', () => { + it('should update auto reimbursement limit optimistically and succeed', async () => { + // Given a workspace with auto reimbursement limit 100 + const policy = { + ...createRandomPolicy(0), + autoReimbursement: {limit: 10000}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When setting auto reimbursement limit to 200 + Policy.setPolicyAutoReimbursementLimit(policy.id, '200', policy.autoReimbursement.limit); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReimbursement?.limit).toBe(20000); + expect(updatedPolicy?.autoReimbursement?.pendingFields?.limit).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReimbursement?.pendingFields?.limit).toBeUndefined(); + }); + + it('should revert auto reimbursement limit when fail', async () => { + // Given a workspace with auto reimbursement limit 100 + const policy = { + ...createRandomPolicy(0), + autoReimbursement: {limit: 10000}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When setting auto reimbursement limit to 200 but fail + mockFetch.fail(); + Policy.setPolicyAutoReimbursementLimit(policy.id, '200', policy.autoReimbursement.limit); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.autoReimbursement?.limit).toBe(10000); + expect(updatedPolicy?.autoReimbursement?.pendingFields?.limit).toBeUndefined(); + expect(updatedPolicy?.errorFields?.autoReimbursement).toBeTruthy(); + }); + }); + + describe('enablePolicyAutoReimbursementLimit', () => { + it('should enable auto reimbursement limit option optimistically and succeed', async () => { + // Given a workspace with auto reimbursement limit option disabled + const policy = { + ...createRandomPolicy(0), + shouldShowAutoReimbursementLimitOption: false, + autoReimbursement: {limit: 0}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + mockFetch.pause(); + + // When enabling auto reimbursement limit option + Policy.enablePolicyAutoReimbursementLimit(policy.id, true, policy.shouldShowAutoReimbursementLimitOption, policy.autoReimbursement.limit); + + // Then optimistic data should be set in Onyx + await waitForBatchedUpdates(); + let updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.shouldShowAutoReimbursementLimitOption).toBe(true); + expect(updatedPolicy?.autoReimbursement?.limit).toBe(CONST.POLICY.AUTO_REIMBURSEMENT_LIMIT_SUGGESTED_CENTS); + expect(updatedPolicy?.pendingFields?.shouldShowAutoReimbursementLimitOption).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + + // When the fetch resumes and succeeds + await mockFetch.resume(); + + // Then pendingFields should be cleared + updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.pendingFields?.shouldShowAutoReimbursementLimitOption).toBeUndefined(); + }); + + it('should revert auto reimbursement limit option when fail', async () => { + // Given a workspace with auto reimbursement limit option disabled + const policy = { + ...createRandomPolicy(0), + shouldShowAutoReimbursementLimitOption: false, + autoReimbursement: {limit: 0}, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); + + // When enabling auto reimbursement limit option but fail + mockFetch.fail(); + Policy.enablePolicyAutoReimbursementLimit(policy.id, true, policy.shouldShowAutoReimbursementLimitOption, policy.autoReimbursement.limit); + await waitForBatchedUpdates(); + + // Then it should be reverted + const updatedPolicy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`); + expect(updatedPolicy?.shouldShowAutoReimbursementLimitOption).toBe(false); + expect(updatedPolicy?.autoReimbursement?.limit).toBe(0); + expect(updatedPolicy?.pendingFields?.shouldShowAutoReimbursementLimitOption).toBeUndefined(); + }); + }); }); From d02d3feaf5a8b46fdd0083b248d8c2f475ac4ace Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 23 Mar 2026 12:08:53 +0800 Subject: [PATCH 2/3] lint --- src/types/onyx/Policy.ts | 3 ++- tests/actions/IOUTest.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 68aa91853d81..38a6c21e1c89 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1548,7 +1548,7 @@ type ProhibitedExpenses = OnyxCommon.OnyxValueWithOfflineFeedback<{ }>; /** Day of the month to schedule submission */ -export type AutoReportingOffset = number | ValueOf; +type AutoReportingOffset = number | ValueOf; /** Types of policy report fields */ type PolicyReportFieldType = 'text' | 'date' | 'dropdown' | 'formula'; @@ -2135,6 +2135,7 @@ type PolicyConnectionSyncProgress = { export default Policy; export type { + AutoReportingOffset, PolicyReportField, PolicyReportFieldType, Unit, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 3b300f93ceab..6a5b6fb6a39d 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -10167,7 +10167,7 @@ describe('actions/IOU', () => { }); return waitForBatchedUpdates() .then(async () => { - const policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + policy = await getOnyxValue(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); setWorkspaceApprovalMode(policy, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.DYNAMICEXTERNAL, {}); return waitForBatchedUpdates(); }) From 21e8bce87fd4a3f22ab332ecda6a3e1565a67678 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 23 Mar 2026 12:13:56 +0800 Subject: [PATCH 3/3] fix typecheck --- tests/actions/PolicyTest.ts | 2 +- tests/actions/ShareBankAccountAndWorkspacePayerTest.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index 5df1a6623e94..816eeb639f25 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -3495,7 +3495,7 @@ describe('actions/Policy', () => { // When setting auto reporting frequency to monthly but fail mockFetch.fail(); - Policy.setWorkspaceAutoReportingFrequency(policy.id, CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY, policy.autoReportingFrequency, policy.harvesting.enabled); + Policy.setWorkspaceAutoReportingFrequency(policy.id, CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY, policy.autoReportingFrequency, policy.harvesting); await waitForBatchedUpdates(); // Then the frequency should be reverted diff --git a/tests/actions/ShareBankAccountAndWorkspacePayerTest.ts b/tests/actions/ShareBankAccountAndWorkspacePayerTest.ts index b1e72cd8c44c..8815d7045098 100644 --- a/tests/actions/ShareBankAccountAndWorkspacePayerTest.ts +++ b/tests/actions/ShareBankAccountAndWorkspacePayerTest.ts @@ -83,7 +83,7 @@ describe('actions/ShareBankAccountAndWorkspacePayer', () => { const policyID = 'policy_abc'; const reimburserEmail = 'payer@example.com'; - setWorkspacePayer(policyID, reimburserEmail); + setWorkspacePayer(policyID, reimburserEmail, undefined); await waitForBatchedUpdates(); expect(write).toHaveBeenCalledWith(