From 9358f2e58c92789e2c78b3463c21cb4b94d0d6a4 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 10:41:48 +0700 Subject: [PATCH 1/6] refactor approveMoneyRequest to use amountOwed from useOnyx --- src/components/MoneyReportHeader.tsx | 3 +- src/components/ProcessMoneyReportHoldMenu.tsx | 2 + .../MoneyRequestReportPreviewContent.tsx | 1 + src/components/SettlementButton/index.tsx | 15 +- src/libs/PaymentUtils.ts | 16 +- src/libs/actions/IOU/index.ts | 3 +- tests/actions/IOUTest.ts | 16 +- tests/unit/PaymentUtilsTest.ts | 169 +++++++++++++++++- 8 files changed, 211 insertions(+), 14 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 459ad2bed56ed..4f2f53d5fe569 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -706,7 +706,7 @@ function MoneyReportHeader({ setIsHoldMenuVisible(true); } else { startApprovedAnimation(); - approveMoneyRequest(moneyRequestReport, policy, accountID, email ?? '', hasViolations, isASAPSubmitBetaEnabled, nextStep, betas, userBillingGraceEndPeriods, true); + approveMoneyRequest(moneyRequestReport, policy, accountID, email ?? '', hasViolations, isASAPSubmitBetaEnabled, nextStep, betas, userBillingGraceEndPeriods, amountOwed, true); } }; @@ -1888,6 +1888,7 @@ function MoneyReportHeader({ iouReportNextStep: nextStep, betas, userBillingGraceEndPeriods, + amountOwed, }); const showNextStepBar = shouldShowNextStep && !!(optimisticNextStep?.message?.length ?? (optimisticNextStep && 'messageKey' in optimisticNextStep)); diff --git a/src/components/ProcessMoneyReportHoldMenu.tsx b/src/components/ProcessMoneyReportHoldMenu.tsx index ea8f986e5cc63..b7f9481457ada 100644 --- a/src/components/ProcessMoneyReportHoldMenu.tsx +++ b/src/components/ProcessMoneyReportHoldMenu.tsx @@ -73,6 +73,7 @@ function ProcessMoneyReportHoldMenu({ const {isSmallScreenWidth} = useResponsiveLayout(); const [userBillingGraceEndPeriods] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED); const activePolicy = usePolicy(activePolicyID); const policy = usePolicy(moneyRequestReport?.policyID); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); @@ -106,6 +107,7 @@ function ProcessMoneyReportHoldMenu({ moneyRequestReportNextStep, betas, userBillingGraceEndPeriods, + amountOwed, full, ); } else if (chatReport && paymentType) { diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx index b4f8634c6a0ba..d07d575ba471c 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx @@ -360,6 +360,7 @@ function MoneyRequestReportPreviewContent({ iouReportNextStep, betas, userBillingGraceEndPeriods, + amountOwed, true, ); } diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 0c1cefb55061e..7bd937a6169ac 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -108,6 +108,7 @@ function SettlementButton({ const [conciergeReportID = ''] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const [iouReportNextStep] = useOnyx(`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}`); const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector}); + const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED); const policyEmployeeAccountIDs = getPolicyEmployeeAccountIDs(policy, accountID); const reportBelongsToWorkspace = policyID ? doesReportBelongToWorkspace(chatReport, policyEmployeeAccountIDs, policyID, conciergeReportID) : false; const policyIDKey = reportBelongsToWorkspace ? policyID : (iouReport?.policyID ?? CONST.POLICY.ID_FAKE); @@ -426,7 +427,19 @@ function SettlementButton({ if (confirmApproval) { confirmApproval(); } else { - approveMoneyRequest(iouReport, policy, accountID, email ?? '', hasViolations, isASAPSubmitBetaEnabled, iouReportNextStep, betas, userBillingGraceEndPeriods, false); + approveMoneyRequest( + iouReport, + policy, + accountID, + email ?? '', + hasViolations, + isASAPSubmitBetaEnabled, + iouReportNextStep, + betas, + userBillingGraceEndPeriods, + amountOwed, + false, + ); } return; } diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts index f5c747060373e..be4fb7a9cabff 100644 --- a/src/libs/PaymentUtils.ts +++ b/src/libs/PaymentUtils.ts @@ -44,6 +44,7 @@ type SelectPaymentTypeParams = { iouReportNextStep: OnyxEntry; betas: OnyxEntry; userBillingGraceEndPeriods: OnyxCollection; + amountOwed: OnyxEntry; }; /** @@ -181,6 +182,7 @@ const selectPaymentType = (params: SelectPaymentTypeParams) => { iouReportNextStep, betas, userBillingGraceEndPeriods, + amountOwed, } = params; if (policy && shouldRestrictUserBillableActions(policy.id, userBillingGraceEndPeriods)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id)); @@ -200,7 +202,19 @@ const selectPaymentType = (params: SelectPaymentTypeParams) => { if (confirmApproval) { confirmApproval(); } else { - approveMoneyRequest(iouReport, policy, currentAccountID, currentEmail, hasViolations, isASAPSubmitBetaEnabled, iouReportNextStep, betas, userBillingGraceEndPeriods, true); + approveMoneyRequest( + iouReport, + policy, + currentAccountID, + currentEmail, + hasViolations, + isASAPSubmitBetaEnabled, + iouReportNextStep, + betas, + userBillingGraceEndPeriods, + amountOwed, + true, + ); } return; } diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index ae71aade3154e..128d56400f776 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -10561,13 +10561,14 @@ function approveMoneyRequest( expenseReportCurrentNextStepDeprecated: OnyxEntry, betas: OnyxEntry, userBillingGraceEndPeriods: OnyxCollection, + amountOwed: OnyxEntry, full?: boolean, ) { if (!expenseReport) { return; } - if (expenseReport.policyID && shouldRestrictUserBillableActions(expenseReport.policyID, userBillingGraceEndPeriods)) { + if (expenseReport.policyID && shouldRestrictUserBillableActions(expenseReport.policyID, userBillingGraceEndPeriods, amountOwed)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID)); return; } diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 8a2f5c8a29a43..5191ce117d666 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -13474,7 +13474,7 @@ describe('actions/IOU', () => { }); // Admin approves the report - approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be approved since admin took control and is the last approver @@ -13512,7 +13512,7 @@ describe('actions/IOU', () => { }); // Manager approves the report - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be submitted to senior manager (normal flow) since take control was invalidated @@ -13546,7 +13546,7 @@ describe('actions/IOU', () => { }); // Admin approves the report - approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Get the optimistic next step @@ -13656,7 +13656,7 @@ describe('actions/IOU', () => { }); // Manager approves the report (no take control actions) - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be submitted to admin (next in approval chain) since manager is not the final approver @@ -13673,7 +13673,7 @@ describe('actions/IOU', () => { accountID: managerAccountID, }); - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be submitted to admin @@ -13688,7 +13688,7 @@ describe('actions/IOU', () => { accountID: adminAccountID, }); - approveMoneyRequest(updatedReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(updatedReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be fully approved @@ -13733,7 +13733,7 @@ describe('actions/IOU', () => { }); // Manager approves the report - approveMoneyRequest(singleApproverReport, singleApproverPolicy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined); + approveMoneyRequest(singleApproverReport, singleApproverPolicy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); await waitForBatchedUpdates(); // Should be fully approved since manager is the final approver in the chain @@ -13834,7 +13834,7 @@ describe('actions/IOU', () => { accountID: adminAccountID, }); - const newExpenseReportID = approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, false); + const newExpenseReportID = approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0, false); await waitForBatchedUpdates(); const newExpenseReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${newExpenseReportID}`); diff --git a/tests/unit/PaymentUtilsTest.ts b/tests/unit/PaymentUtilsTest.ts index 19bc6a590ed44..feec11e6f8f8b 100644 --- a/tests/unit/PaymentUtilsTest.ts +++ b/tests/unit/PaymentUtilsTest.ts @@ -1,10 +1,16 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {BankAccountMenuItem} from '@components/Search/types'; +import {setPersonalBankAccountContinueKYCOnSuccess} from '@libs/actions/BankAccounts'; +import {approveMoneyRequest} from '@libs/actions/IOU'; import Navigation from '@libs/Navigation/Navigation'; -import {getActivePaymentType, handleUnvalidatedAccount} from '@libs/PaymentUtils'; +import {getActivePaymentType, handleUnvalidatedAccount, selectPaymentType} from '@libs/PaymentUtils'; +import type {SelectPaymentTypeParams} from '@libs/PaymentUtils'; +import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import CONST from '@src/CONST'; import {calculateWalletTransferBalanceFee} from '@src/libs/PaymentUtils'; -import type {Report} from '@src/types/onyx'; +import ROUTES from '@src/ROUTES'; +import type {Policy, Report} from '@src/types/onyx'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import createRandomPolicy from '../utils/collections/policies'; jest.mock('@libs/Navigation/Navigation', () => ({ @@ -12,6 +18,18 @@ jest.mock('@libs/Navigation/Navigation', () => ({ getActiveRoute: jest.fn(), })); +jest.mock('@libs/SubscriptionUtils', () => ({ + shouldRestrictUserBillableActions: jest.fn(), +})); + +jest.mock('@libs/actions/BankAccounts', () => ({ + setPersonalBankAccountContinueKYCOnSuccess: jest.fn(), +})); + +jest.mock('@libs/actions/IOU', () => ({ + approveMoneyRequest: jest.fn(), +})); + describe('PaymentUtils', () => { it('Test rounding wallet transfer instant fee', () => { expect(calculateWalletTransferBalanceFee(2100, CONST.WALLET.TRANSFER_METHOD_TYPE.INSTANT)).toBe(32); @@ -151,4 +169,151 @@ describe('PaymentUtils', () => { expect(result.policyFromPaymentMethod).toBeUndefined(); }); }); + + describe('selectPaymentType', () => { + const mockNavigate = Navigation.navigate as jest.MockedFunction; + const mockShouldRestrict = shouldRestrictUserBillableActions as jest.MockedFunction; + const mockOnPress = jest.fn(); + const mockTriggerKYCFlow = jest.fn(); + const mockConfirmApproval = jest.fn(); + const testPolicy = createRandomPolicy(1) as OnyxEntry; + const testPolicyID = testPolicy?.id ?? ''; + + const baseParams: SelectPaymentTypeParams = { + event: undefined, + iouPaymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + triggerKYCFlow: mockTriggerKYCFlow, + policy: testPolicy, + onPress: mockOnPress, + currentAccountID: 1, + currentEmail: 'test@test.com', + hasViolations: false, + isASAPSubmitBetaEnabled: false, + isUserValidated: true, + iouReport: {reportID: '1'} as Report, + iouReportNextStep: undefined, + betas: [], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }; + + beforeEach(() => { + jest.clearAllMocks(); + mockShouldRestrict.mockReturnValue(false); + }); + + it('should navigate to restricted action page when billable actions are restricted', () => { + mockShouldRestrict.mockReturnValue(true); + const params = {...baseParams, amountOwed: 100}; + + selectPaymentType(params); + + expect(mockNavigate).toHaveBeenCalledWith(ROUTES.RESTRICTED_ACTION.getRoute(testPolicyID)); + expect(mockOnPress).not.toHaveBeenCalled(); + }); + + it('should not restrict when amountOwed is 0', () => { + mockShouldRestrict.mockReturnValue(false); + + selectPaymentType({...baseParams, amountOwed: 0}); + + expect(mockOnPress).toHaveBeenCalledWith({paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE}); + }); + + it('should trigger KYC flow for EXPENSIFY payment type when user is validated', () => { + const params: SelectPaymentTypeParams = {...baseParams, iouPaymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY as PaymentMethodType}; + + selectPaymentType(params); + + expect(mockTriggerKYCFlow).toHaveBeenCalledWith({event: undefined, iouPaymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY}); + expect(setPersonalBankAccountContinueKYCOnSuccess).toHaveBeenCalledWith(ROUTES.ENABLE_PAYMENTS); + }); + + it('should navigate to unvalidated account page for EXPENSIFY payment when user is not validated', () => { + const mockGetActiveRoute = Navigation.getActiveRoute as jest.MockedFunction; + mockGetActiveRoute.mockReturnValue('r/1'); + const params: SelectPaymentTypeParams = {...baseParams, iouPaymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY as PaymentMethodType, isUserValidated: false}; + + selectPaymentType(params); + + expect(mockTriggerKYCFlow).not.toHaveBeenCalled(); + expect(mockNavigate).toHaveBeenCalled(); + }); + + it('should call confirmApproval when payment type is APPROVE and confirmApproval is provided', () => { + const params: SelectPaymentTypeParams = { + ...baseParams, + iouPaymentType: CONST.IOU.REPORT_ACTION_TYPE.APPROVE as PaymentMethodType, + confirmApproval: mockConfirmApproval, + }; + + selectPaymentType(params); + + expect(mockConfirmApproval).toHaveBeenCalled(); + expect(approveMoneyRequest).not.toHaveBeenCalled(); + }); + + it('should call approveMoneyRequest with amountOwed when payment type is APPROVE and no confirmApproval', () => { + const params: SelectPaymentTypeParams = { + ...baseParams, + iouPaymentType: CONST.IOU.REPORT_ACTION_TYPE.APPROVE as PaymentMethodType, + amountOwed: 42, + }; + + selectPaymentType(params); + + expect(approveMoneyRequest).toHaveBeenCalledWith( + params.iouReport, + params.policy, + params.currentAccountID, + params.currentEmail, + params.hasViolations, + params.isASAPSubmitBetaEnabled, + params.iouReportNextStep, + params.betas, + params.userBillingGraceEndPeriods, + 42, + true, + ); + }); + + it('should pass amountOwed as undefined to approveMoneyRequest when amountOwed is undefined', () => { + const params: SelectPaymentTypeParams = { + ...baseParams, + iouPaymentType: CONST.IOU.REPORT_ACTION_TYPE.APPROVE as PaymentMethodType, + amountOwed: undefined, + }; + + selectPaymentType(params); + + expect(approveMoneyRequest).toHaveBeenCalledWith( + params.iouReport, + params.policy, + params.currentAccountID, + params.currentEmail, + params.hasViolations, + params.isASAPSubmitBetaEnabled, + params.iouReportNextStep, + params.betas, + params.userBillingGraceEndPeriods, + undefined, + true, + ); + }); + + it('should call onPress with payment type for other payment types', () => { + selectPaymentType({...baseParams, iouPaymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE as PaymentMethodType}); + + expect(mockOnPress).toHaveBeenCalledWith({paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE}); + }); + + it('should not restrict when policy is undefined', () => { + const params: SelectPaymentTypeParams = {...baseParams, policy: undefined, amountOwed: 100}; + + selectPaymentType(params); + + expect(mockShouldRestrict).not.toHaveBeenCalled(); + expect(mockOnPress).toHaveBeenCalledWith({paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE}); + }); + }); }); From deae97705b925013a49f24cc6ca6d5c9640747f6 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 11:12:03 +0700 Subject: [PATCH 2/6] lint fix --- src/components/MoneyReportHeader.tsx | 1 + .../MoneyRequestReportPreviewContent.tsx | 2 +- src/libs/actions/IOU/index.ts | 25 ++++++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 4f2f53d5fe569..5bd0d2a6ab30f 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -1644,6 +1644,7 @@ function MoneyReportHeader({ Navigation.setNavigationActionToMicrotaskQueue(() => { Navigation.goBack(backToRoute); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { deleteAppReport(moneyRequestReport, selfDMReport, email ?? '', accountID, reportTransactions, allTransactionViolations, bankAccountList, currentSearchHash); }); diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx index d07d575ba471c..819576a0d3be3 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx @@ -876,9 +876,9 @@ function MoneyRequestReportPreviewContent({ style={[styles.headerText]} testID="MoneyRequestReportPreview-reportName" > + {} {/* This will be fixed as follow up https://github.com/Expensify/App/pull/75357 */} {/* eslint-disable-next-line @typescript-eslint/no-deprecated */} - {} {getReportName({report: iouReport, reportAttributes}) || action.childReportName} diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 128d56400f776..78dad0cb0620d 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1903,6 +1903,7 @@ function buildOnyxDataForTestDriveIOU( transactionID: testDriveIOUParams.transaction.transactionID, reportActionID: testDriveIOUParams.iouOptimisticParams.action.reportActionID, }); + // eslint-disable-next-line @typescript-eslint/no-deprecated const text = Localize.translateLocal('testDrive.employeeInviteMessage', personalDetailsList?.[userAccountID]?.firstName ?? ''); const textComment = buildOptimisticAddCommentReportAction(text, undefined, userAccountID, undefined, undefined, testDriveIOUParams.testDriveCommentReportActionID); textComment.reportAction.created = DateUtils.subtractMillisecondsFromDateTime(testDriveIOUParams.iouOptimisticParams.createdAction.created, 1); @@ -2592,6 +2593,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iou.report.reportID}`, onyxMethod: Onyx.METHOD.SET, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: iou.report, predictedNextStatus: iou.report.statusNum ?? CONST.REPORT.STATE_NUM.OPEN, @@ -3646,6 +3648,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma iouReport.statusNum ?? (policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.OPEN); const hasViolations = hasViolationsReportUtils(iouReport.reportID, transactionViolations, currentUserAccountIDParam, currentUserEmailParam); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: iouReport, predictedNextStatus, @@ -3980,6 +3983,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const predictedNextStatus = iouReport.statusNum ?? (policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.OPEN); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: iouReport, predictedNextStatus, @@ -4990,6 +4994,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}`, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: moneyRequestReport, predictedNextStatus: iouReport?.statusNum ?? CONST.REPORT.STATUS_NUM.OPEN, @@ -6818,6 +6823,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation): {iouRep } if (shouldHandleNavigation) { + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransactionsByIDs(draftTransactionIDs)); const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID); @@ -6954,6 +6960,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); handleNavigateAfterExpenseCreate({activeReportID, transactionID: transaction.transactionID, isFromGlobalCreate, shouldHandleNavigation}); @@ -7353,6 +7360,7 @@ function submitPerDiemExpenseForSelfDM(submitPerDiemExpenseInformation: PerDiemE playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); dismissModalAndOpenReportInInboxTab(chatReport.reportID); @@ -7705,6 +7713,7 @@ function trackExpense(params: CreateTrackExpenseParams) { } if (shouldHandleNavigation) { + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransactions()); } @@ -7820,6 +7829,7 @@ function createSplitsAndOnyxData({ reportID: CONST.REPORT.SPLIT_REPORT_ID, comment, created, + // eslint-disable-next-line @typescript-eslint/no-deprecated merchant: merchant || Localize.translateLocal('iou.expense'), receipt, category, @@ -8124,6 +8134,7 @@ function createSplitsAndOnyxData({ reportID: oneOnOneIOUReport.reportID, comment, created, + // eslint-disable-next-line @typescript-eslint/no-deprecated merchant: merchant || Localize.translateLocal('iou.expense'), category, tag, @@ -8541,6 +8552,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest playSound(SOUNDS.DONE); API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; @@ -8776,6 +8788,7 @@ function prepareToCleanUpMoneyRequest( } const hasNonReimbursableTransactions = hasNonReimbursableTransactionsReportUtils(iouReport?.reportID); + // eslint-disable-next-line @typescript-eslint/no-deprecated const messageText = Localize.translateLocal( hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency), @@ -9062,6 +9075,7 @@ function cleanUpMoneyRequest( // First, update the reportActions to ensure related actions are not displayed. Onyx.update(reportActionsOnyxUpdates).then(() => { Navigation.goBack(urlToNavigateBack); + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { if (shouldDeleteIOUReport) { clearAllRelatedReportActionErrors(reportID, reportAction, originalReportID); @@ -10132,6 +10146,7 @@ function getPayMoneyRequestParams({ if (!isInvoiceReport) { currentNextStepDeprecated = iouReportCurrentNextStepDeprecated ?? null; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated optimisticNextStepDeprecated = buildNextStepNew({report: iouReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED}); optimisticNextStep = buildOptimisticNextStep({report: iouReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED}); } @@ -10935,6 +10950,7 @@ function reopenReport( const predictedNextStatus = CONST.REPORT.STATUS_NUM.OPEN; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.OPEN, @@ -11117,6 +11133,7 @@ function retractReport( const predictedNextStatus = CONST.REPORT.STATUS_NUM.OPEN; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.OPEN, @@ -11287,6 +11304,7 @@ function unapproveExpenseReport( const optimisticUnapprovedReportAction = buildOptimisticUnapprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.SUBMITTED, @@ -11469,7 +11487,8 @@ function submitReport( // buildOptimisticNextStep is used in parallel const optimisticNextStepDeprecated = isDEWPolicy ? null - : buildNextStepNew({ + : // eslint-disable-next-line @typescript-eslint/no-deprecated + buildNextStepNew({ report: expenseReport, predictedNextStatus: isSubmitAndClosePolicy ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.SUBMITTED, policy, @@ -11729,6 +11748,7 @@ function cancelPayment( const statusNum: ValueOf = approvalMode === CONST.POLICY.APPROVAL_MODE.OPTIONAL ? CONST.REPORT.STATUS_NUM.CLOSED : CONST.REPORT.STATUS_NUM.APPROVED; // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: expenseReport, predictedNextStatus: statusNum, @@ -11891,6 +11911,7 @@ function cancelPayment( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated value: buildNextStepNew({ report: expenseReport, predictedNextStatus: CONST.REPORT.STATUS_NUM.REIMBURSED, @@ -13574,6 +13595,7 @@ function assignReportToMe( const takeControlReportAction = buildOptimisticChangeApproverReportAction(accountID, accountID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: {...report, managerID: accountID}, predictedNextStatus: report.statusNum ?? CONST.REPORT.STATUS_NUM.SUBMITTED, @@ -13689,6 +13711,7 @@ function addReportApprover( const takeControlReportAction = buildOptimisticChangeApproverReportAction(newApproverAccountID, accountID); // buildOptimisticNextStep is used in parallel + // eslint-disable-next-line @typescript-eslint/no-deprecated const optimisticNextStepDeprecated = buildNextStepNew({ report: {...report, managerID: newApproverAccountID}, predictedNextStatus: report.statusNum ?? CONST.REPORT.STATUS_NUM.SUBMITTED, From 331d13a3f35a8a4c4dded089c395226edff8d1b4 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 11:18:57 +0700 Subject: [PATCH 3/6] lint fix --- src/components/MoneyReportHeader.tsx | 14 ++- src/components/ProcessMoneyReportHoldMenu.tsx | 14 +-- .../MoneyRequestReportPreviewContent.tsx | 16 +-- src/components/SettlementButton/index.tsx | 14 +-- src/libs/PaymentUtils.ts | 14 +-- src/libs/actions/IOU/index.ts | 40 ++++--- tests/actions/IOUTest.ts | 105 ++++++++++++++++-- 7 files changed, 166 insertions(+), 51 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 5bd0d2a6ab30f..3c919e4833dd6 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -706,7 +706,19 @@ function MoneyReportHeader({ setIsHoldMenuVisible(true); } else { startApprovedAnimation(); - approveMoneyRequest(moneyRequestReport, policy, accountID, email ?? '', hasViolations, isASAPSubmitBetaEnabled, nextStep, betas, userBillingGraceEndPeriods, amountOwed, true); + approveMoneyRequest({ + expenseReport: moneyRequestReport, + policy, + currentUserAccountIDParam: accountID, + currentUserEmailParam: email ?? '', + hasViolations, + isASAPSubmitBetaEnabled, + expenseReportCurrentNextStepDeprecated: nextStep, + betas, + userBillingGraceEndPeriods, + amountOwed, + full: true, + }); } }; diff --git a/src/components/ProcessMoneyReportHoldMenu.tsx b/src/components/ProcessMoneyReportHoldMenu.tsx index b7f9481457ada..cd5e2b1d70ec7 100644 --- a/src/components/ProcessMoneyReportHoldMenu.tsx +++ b/src/components/ProcessMoneyReportHoldMenu.tsx @@ -97,19 +97,19 @@ function ProcessMoneyReportHoldMenu({ if (startAnimation) { startAnimation(); } - approveMoneyRequest( - moneyRequestReport, - activePolicy, - currentUserDetails.accountID, - currentUserDetails.email ?? '', + approveMoneyRequest({ + expenseReport: moneyRequestReport, + policy: activePolicy, + currentUserAccountIDParam: currentUserDetails.accountID, + currentUserEmailParam: currentUserDetails.email ?? '', hasViolations, isASAPSubmitBetaEnabled, - moneyRequestReportNextStep, + expenseReportCurrentNextStepDeprecated: moneyRequestReportNextStep, betas, userBillingGraceEndPeriods, amountOwed, full, - ); + }); } else if (chatReport && paymentType) { if (startAnimation) { startAnimation(); diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx index 819576a0d3be3..dc905eb39d2c3 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx @@ -350,19 +350,19 @@ function MoneyRequestReportPreviewContent({ setIsHoldMenuVisible(true); } else { startApprovedAnimation(); - approveMoneyRequest( - iouReport, - activePolicy, - currentUserAccountID, - currentUserEmail, + approveMoneyRequest({ + expenseReport: iouReport, + policy: activePolicy, + currentUserAccountIDParam: currentUserAccountID, + currentUserEmailParam: currentUserEmail, hasViolations, isASAPSubmitBetaEnabled, - iouReportNextStep, + expenseReportCurrentNextStepDeprecated: iouReportNextStep, betas, userBillingGraceEndPeriods, amountOwed, - true, - ); + full: true, + }); } }; diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 7bd937a6169ac..0bc982d4be0a0 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -427,19 +427,19 @@ function SettlementButton({ if (confirmApproval) { confirmApproval(); } else { - approveMoneyRequest( - iouReport, + approveMoneyRequest({ + expenseReport: iouReport, policy, - accountID, - email ?? '', + currentUserAccountIDParam: accountID, + currentUserEmailParam: email ?? '', hasViolations, isASAPSubmitBetaEnabled, - iouReportNextStep, + expenseReportCurrentNextStepDeprecated: iouReportNextStep, betas, userBillingGraceEndPeriods, amountOwed, - false, - ); + full: false, + }); } return; } diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts index be4fb7a9cabff..ed9b766fc4551 100644 --- a/src/libs/PaymentUtils.ts +++ b/src/libs/PaymentUtils.ts @@ -202,19 +202,19 @@ const selectPaymentType = (params: SelectPaymentTypeParams) => { if (confirmApproval) { confirmApproval(); } else { - approveMoneyRequest( - iouReport, + approveMoneyRequest({ + expenseReport: iouReport, policy, - currentAccountID, - currentEmail, + currentUserAccountIDParam: currentAccountID, + currentUserEmailParam: currentEmail, hasViolations, isASAPSubmitBetaEnabled, - iouReportNextStep, + expenseReportCurrentNextStepDeprecated: iouReportNextStep, betas, userBillingGraceEndPeriods, amountOwed, - true, - ); + full: true, + }); } return; } diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 78dad0cb0620d..6951fb5ff1589 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -10566,19 +10566,33 @@ function getReportOriginalCreationTimestamp(expenseReport?: OnyxEntry, - policy: OnyxEntry, - currentUserAccountIDParam: number, - currentUserEmailParam: string, - hasViolations: boolean, - isASAPSubmitBetaEnabled: boolean, - expenseReportCurrentNextStepDeprecated: OnyxEntry, - betas: OnyxEntry, - userBillingGraceEndPeriods: OnyxCollection, - amountOwed: OnyxEntry, - full?: boolean, -) { +type ApproveMoneyRequestParam = { + expenseReport: OnyxEntry; + policy: OnyxEntry; + currentUserAccountIDParam: number; + currentUserEmailParam: string; + hasViolations: boolean; + isASAPSubmitBetaEnabled: boolean; + expenseReportCurrentNextStepDeprecated: OnyxEntry; + betas: OnyxEntry; + userBillingGraceEndPeriods: OnyxCollection; + amountOwed: OnyxEntry; + full?: boolean; +}; + +function approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam, + currentUserEmailParam, + hasViolations, + isASAPSubmitBetaEnabled, + expenseReportCurrentNextStepDeprecated, + betas, + userBillingGraceEndPeriods, + amountOwed, + full, +}: ApproveMoneyRequestParam) { if (!expenseReport) { return; } diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 5191ce117d666..d816a7b2f635f 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -13474,7 +13474,18 @@ describe('actions/IOU', () => { }); // Admin approves the report - approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: adminAccountID, + currentUserEmailParam: adminEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be approved since admin took control and is the last approver @@ -13512,7 +13523,18 @@ describe('actions/IOU', () => { }); // Manager approves the report - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: managerAccountID, + currentUserEmailParam: managerEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be submitted to senior manager (normal flow) since take control was invalidated @@ -13546,7 +13568,18 @@ describe('actions/IOU', () => { }); // Admin approves the report - approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: adminAccountID, + currentUserEmailParam: adminEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Get the optimistic next step @@ -13656,7 +13689,18 @@ describe('actions/IOU', () => { }); // Manager approves the report (no take control actions) - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: managerAccountID, + currentUserEmailParam: managerEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be submitted to admin (next in approval chain) since manager is not the final approver @@ -13673,7 +13717,18 @@ describe('actions/IOU', () => { accountID: managerAccountID, }); - approveMoneyRequest(expenseReport, policy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: managerAccountID, + currentUserEmailParam: managerEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be submitted to admin @@ -13688,7 +13743,18 @@ describe('actions/IOU', () => { accountID: adminAccountID, }); - approveMoneyRequest(updatedReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport: updatedReport, + policy, + currentUserAccountIDParam: adminAccountID, + currentUserEmailParam: adminEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be fully approved @@ -13733,7 +13799,18 @@ describe('actions/IOU', () => { }); // Manager approves the report - approveMoneyRequest(singleApproverReport, singleApproverPolicy, managerAccountID, managerEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0); + approveMoneyRequest({ + expenseReport: singleApproverReport, + policy: singleApproverPolicy, + currentUserAccountIDParam: managerAccountID, + currentUserEmailParam: managerEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + }); await waitForBatchedUpdates(); // Should be fully approved since manager is the final approver in the chain @@ -13834,7 +13911,19 @@ describe('actions/IOU', () => { accountID: adminAccountID, }); - const newExpenseReportID = approveMoneyRequest(expenseReport, policy, adminAccountID, adminEmail, false, false, undefined, [CONST.BETAS.ALL], undefined, 0, false); + const newExpenseReportID = approveMoneyRequest({ + expenseReport, + policy, + currentUserAccountIDParam: adminAccountID, + currentUserEmailParam: adminEmail, + hasViolations: false, + isASAPSubmitBetaEnabled: false, + expenseReportCurrentNextStepDeprecated: undefined, + betas: [CONST.BETAS.ALL], + userBillingGraceEndPeriods: undefined, + amountOwed: 0, + full: false, + }); await waitForBatchedUpdates(); const newExpenseReport = await getOnyxValue(`${ONYXKEYS.COLLECTION.REPORT}${newExpenseReportID}`); From 7a7d83dc305e07dd4d553d6ebf59917bc654358e Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 11:25:21 +0700 Subject: [PATCH 4/6] lint fix --- src/libs/actions/IOU/index.ts | 8 +++++++- tests/unit/PaymentUtilsTest.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 6951fb5ff1589..7c809c35d57d3 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -3553,6 +3553,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma const optimisticPolicyRecentlyUsedCategories = mergePolicyRecentlyUsedCategories(category, policyRecentlyUsedCategories); const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -3926,6 +3927,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const optimisticPolicyRecentlyUsedCategories = mergePolicyRecentlyUsedCategories(category, policyRecentlyUsedCategories); const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -4814,6 +4816,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U if (hasModifiedTag) { const optimisticPolicyRecentlyUsedTags = buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(iouReport?.policyID), policyRecentlyUsedTags, transactionTags: transactionChanges.tag, @@ -8201,6 +8204,7 @@ function createSplitsAndOnyxData({ const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? buildOptimisticPolicyRecentlyUsedTags({ // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated policyTags: getPolicyTagsData(participant.policyID), policyRecentlyUsedTags, transactionTags: tag, @@ -10543,7 +10547,7 @@ function getIOUReportActionToApproveOrPay( return false; } const iouReport = updatedIouReport?.reportID === action.childReportID ? updatedIouReport : getReportOrDraftReport(action.childReportID); - // This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 + // eslint-disable-next-line @typescript-eslint/no-deprecated -- This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850 const policy = getPolicy(iouReport?.policyID); // Only show to the actual payer, exclude admins with bank account access const shouldShowSettlementButton = @@ -12182,6 +12186,7 @@ function detachReceipt(transactionID: string | undefined, transactionPolicy: Ony if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( @@ -12308,6 +12313,7 @@ function replaceReceipt({transactionID, file, source, state, transactionPolicy, if (transactionPolicy && isPaidGroupPolicy(transactionPolicy) && newTransaction) { // TODO: Replace getPolicyTagsData (https://github.com/Expensify/App/issues/72721) and getPolicyRecentlyUsedTagsData (https://github.com/Expensify/App/issues/71491) with useOnyx hook + // eslint-disable-next-line @typescript-eslint/no-deprecated const policyTagList = getPolicyTagsData(transactionPolicy.id); const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; const violationsOnyxData = ViolationsUtils.getViolationsOnyxData( diff --git a/tests/unit/PaymentUtilsTest.ts b/tests/unit/PaymentUtilsTest.ts index feec11e6f8f8b..8d8794a0e8141 100644 --- a/tests/unit/PaymentUtilsTest.ts +++ b/tests/unit/PaymentUtilsTest.ts @@ -177,7 +177,7 @@ describe('PaymentUtils', () => { const mockTriggerKYCFlow = jest.fn(); const mockConfirmApproval = jest.fn(); const testPolicy = createRandomPolicy(1) as OnyxEntry; - const testPolicyID = testPolicy?.id ?? ''; + const testPolicyID = testPolicy?.id ?? CONST.DEFAULT_NUMBER_ID.toString(); const baseParams: SelectPaymentTypeParams = { event: undefined, From 8db51bbd2e80f6e7b0e552056dcd94e805bb748c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 11:38:22 +0700 Subject: [PATCH 5/6] update test --- tests/unit/PaymentUtilsTest.ts | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/unit/PaymentUtilsTest.ts b/tests/unit/PaymentUtilsTest.ts index 8d8794a0e8141..154056b5831e4 100644 --- a/tests/unit/PaymentUtilsTest.ts +++ b/tests/unit/PaymentUtilsTest.ts @@ -262,19 +262,19 @@ describe('PaymentUtils', () => { selectPaymentType(params); - expect(approveMoneyRequest).toHaveBeenCalledWith( - params.iouReport, - params.policy, - params.currentAccountID, - params.currentEmail, - params.hasViolations, - params.isASAPSubmitBetaEnabled, - params.iouReportNextStep, - params.betas, - params.userBillingGraceEndPeriods, - 42, - true, - ); + expect(approveMoneyRequest).toHaveBeenCalledWith({ + expenseReport: params.iouReport, + policy: params.policy, + currentUserAccountIDParam: params.currentAccountID, + currentUserEmailParam: params.currentEmail, + hasViolations: params.hasViolations, + isASAPSubmitBetaEnabled: params.isASAPSubmitBetaEnabled, + expenseReportCurrentNextStepDeprecated: params.iouReportNextStep, + betas: params.betas, + userBillingGraceEndPeriods: params.userBillingGraceEndPeriods, + amountOwed: 42, + full: true, + }); }); it('should pass amountOwed as undefined to approveMoneyRequest when amountOwed is undefined', () => { @@ -286,19 +286,19 @@ describe('PaymentUtils', () => { selectPaymentType(params); - expect(approveMoneyRequest).toHaveBeenCalledWith( - params.iouReport, - params.policy, - params.currentAccountID, - params.currentEmail, - params.hasViolations, - params.isASAPSubmitBetaEnabled, - params.iouReportNextStep, - params.betas, - params.userBillingGraceEndPeriods, - undefined, - true, - ); + expect(approveMoneyRequest).toHaveBeenCalledWith({ + expenseReport: params.iouReport, + policy: params.policy, + currentUserAccountIDParam: params.currentAccountID, + currentUserEmailParam: params.currentEmail, + hasViolations: params.hasViolations, + isASAPSubmitBetaEnabled: params.isASAPSubmitBetaEnabled, + expenseReportCurrentNextStepDeprecated: params.iouReportNextStep, + betas: params.betas, + userBillingGraceEndPeriods: params.userBillingGraceEndPeriods, + amountOwed: undefined, + full: true, + }); }); it('should call onPress with payment type for other payment types', () => { From 1a47d1f5cd9234b4bd1be30fb77fe57b02a961f1 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 5 Mar 2026 18:03:23 +0700 Subject: [PATCH 6/6] resolve comments --- .../MoneyRequestReportPreviewContent.tsx | 1 - src/libs/PaymentUtils.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx index dc905eb39d2c3..5c3559a90ca36 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx @@ -876,7 +876,6 @@ function MoneyRequestReportPreviewContent({ style={[styles.headerText]} testID="MoneyRequestReportPreview-reportName" > - {} {/* This will be fixed as follow up https://github.com/Expensify/App/pull/75357 */} {/* eslint-disable-next-line @typescript-eslint/no-deprecated */} {getReportName({report: iouReport, reportAttributes}) || action.childReportName} diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts index ed9b766fc4551..abe6d0fd46eb4 100644 --- a/src/libs/PaymentUtils.ts +++ b/src/libs/PaymentUtils.ts @@ -184,7 +184,7 @@ const selectPaymentType = (params: SelectPaymentTypeParams) => { userBillingGraceEndPeriods, amountOwed, } = params; - if (policy && shouldRestrictUserBillableActions(policy.id, userBillingGraceEndPeriods)) { + if (policy && shouldRestrictUserBillableActions(policy.id, userBillingGraceEndPeriods, amountOwed)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id)); return; }