From 7f8df5f273390252c31a1e712860303035feb1c8 Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Tue, 19 May 2026 13:54:47 +0000 Subject: [PATCH 1/7] Remove Manager McTest references from frontend App code Manager McTest is no longer supported on the backend. This removes all frontend references including constants, utility functions, special handling in money request flows, Quick Action Bar restrictions, and participant filtering logic. Co-authored-by: Ishpaul Singh --- src/CONST/index.ts | 5 - src/libs/OptionsListUtils/index.ts | 36 +----- src/libs/OptionsListUtils/types.ts | 1 - src/libs/QuickActionUtils.ts | 9 -- src/libs/ReportUtils.ts | 48 +------- src/libs/actions/IOU/MoneyRequest.ts | 32 +----- src/libs/actions/IOU/MoneyRequestBuilder.ts | 67 +---------- .../iou/request/ParticipantSearchResults.tsx | 11 -- .../step/IOURequestStepConfirmation.tsx | 12 +- .../components/MobileWebCameraView.tsx | 2 +- .../hooks/useReceiptScan.ts | 3 +- .../request/step/IOURequestStepScan/types.ts | 2 +- .../step/confirmation/useExpenseSubmission.ts | 10 +- tests/actions/IOU/MoneyRequestTest.ts | 46 -------- tests/actions/IOUTest.ts | 50 --------- tests/unit/OptionsListUtilsTest.tsx | 106 ------------------ .../PersonalDetailOptionsListUtilsTest.ts | 20 ---- tests/unit/QuickActionUtilsTest.ts | 32 ------ tests/unit/ReportUtilsTest.ts | 23 ---- tests/unit/hooks/useReceiptScan.test.ts | 3 +- 20 files changed, 16 insertions(+), 502 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 05be45d99317..91843dcd4d04 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -190,7 +190,6 @@ const EMAIL = { EXPENSIFY_EMAIL_DOMAIN: '@expensify.com', EXPENSIFY_TEAM_EMAIL_DOMAIN: '@team.expensify.com', TEAM: 'team@expensify.com', - MANAGER_MCTEST: 'manager_mctest@expensify.com', QA_GUIDE: 'qa.guide@team.expensify.com', }; @@ -888,7 +887,6 @@ const CONST = { REPORT_FIELDS_FEATURE: 'reportFieldsFeature', NETSUITE_USA_TAX: 'netsuiteUsaTax', PER_DIEM: 'newDotPerDiem', - NEWDOT_MANAGER_MCTEST: 'newDotManagerMcTest', IS_TRAVEL_VERIFIED: 'isTravelVerified', TRAVEL_INVOICING: 'travelInvoicing', EXPENSIFY_CARD_EU_UK: 'expensifyCardEuUk', @@ -3295,7 +3293,6 @@ const CONST = { REWARDS: Number(Config?.EXPENSIFY_ACCOUNT_ID_REWARDS ?? 11023767), // rewards@expensify.com STUDENT_AMBASSADOR: Number(Config?.EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR ?? 10476956), SVFG: Number(Config?.EXPENSIFY_ACCOUNT_ID_SVFG ?? 2012843), - MANAGER_MCTEST: Number(Config?.EXPENSIFY_ACCOUNT_ID_MANAGER_MCTEST ?? 18964612), QA_GUIDE: Number(Config?.EXPENSIFY_ACCOUNT_ID_QA_GUIDE ?? 14365522), }, @@ -4744,7 +4741,6 @@ const CONST = { EMAIL.STUDENT_AMBASSADOR, EMAIL.SVFG, EMAIL.TEAM, - EMAIL.MANAGER_MCTEST, EMAIL.QA_GUIDE, ] as string[], get EXPENSIFY_ACCOUNT_IDS() { @@ -4766,7 +4762,6 @@ const CONST = { this.ACCOUNT_ID.REWARDS, this.ACCOUNT_ID.STUDENT_AMBASSADOR, this.ACCOUNT_ID.SVFG, - this.ACCOUNT_ID.MANAGER_MCTEST, ].filter((id) => id !== -1); }, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 381a139e70cc..93d767a332a1 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -21,7 +21,6 @@ import MinHeap from '@libs/MinHeap'; import {getForReportAction} from '@libs/ModifiedExpenseMessage'; import Navigation from '@libs/Navigation/Navigation'; import Parser from '@libs/Parser'; -import Permissions from '@libs/Permissions'; import type {OptionData as PersonalDetailOptionData} from '@libs/PersonalDetailOptionsListUtils/types'; import {getDisplayNameOrDefault, getPersonalDetailByEmail, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import {addSMSDomainIfPhoneNumber, parsePhoneNumber} from '@libs/PhoneNumber'; @@ -410,9 +409,7 @@ function shouldShowLastActorDisplayName( !lastActorDetails || reportUtilsIsSelfDM(report) || (isDM(report) && lastActorDetails.accountID !== currentUserAccountIDParam) || - lastActionName === CONST.REPORT.ACTIONS.TYPE.IOU || - (lastActionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && - Object.keys(report?.participants ?? {})?.some((participantID) => participantID === CONST.ACCOUNT_ID.MANAGER_MCTEST.toString())) + lastActionName === CONST.REPORT.ACTIONS.TYPE.IOU ) { return false; } @@ -2279,17 +2276,6 @@ function prepareReportOptionsForDisplay( return validOptions; } -/** - * Returns a list of logins that should be restricted (i.e., hidden or excluded in the UI) - * based on dynamic business logic and feature flags. - * Centralizes restriction logic to avoid scattering conditions across the codebase. - */ -function getRestrictedLogins(config: GetOptionsConfig, options: OptionList, canShowManagerMcTest: boolean): Record { - return { - [CONST.EMAIL.MANAGER_MCTEST]: !canShowManagerMcTest || !Permissions.isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST, config.betas), - }; -} - /** * Options are reports and personal details. This function filters out the options that are not valid to be displayed. */ @@ -2311,7 +2297,6 @@ function getValidOptions( shouldSeparateSelfDMChat = false, shouldSeparateWorkspaceChat = false, excludeHidden = false, - canShowManagerMcTest = false, searchString, searchInputValue, maxElements, @@ -2327,14 +2312,11 @@ function getValidOptions( ...config }: GetOptionsConfig = {}, ): Options { - const restrictedLogins = getRestrictedLogins(config, options, canShowManagerMcTest); - // Gather shared configs: // Hard exclusions: cannot be selected at all const loginsToExclude: Record = { [CONST.EMAIL.NOTIFICATIONS]: true, ...excludeLogins, - ...restrictedLogins, }; // Soft exclusions: hidden from suggestions but can be manually entered (e.g., Guide/AM) @@ -3230,21 +3212,6 @@ function shouldUseBoldText(report: SearchOptionData): boolean { return report.isUnread === true && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.MUTE && !isHiddenForCurrentUser(notificationPreference); } -function getManagerMcTestParticipant(currentUserAccountID: number, personalDetails: OnyxEntry): Participant | undefined { - // Use O(1) cache lookup when using global personal details, fall back to O(n) search for custom personal details - const managerMcTestPersonalDetails = personalDetails - ? Object.values(personalDetails).find((personalDetail) => personalDetail?.login === CONST.EMAIL.MANAGER_MCTEST) - : getPersonalDetailByEmail(CONST.EMAIL.MANAGER_MCTEST); - const managerMcTestReport = - managerMcTestPersonalDetails?.accountID && currentUserAccountID ? getChatByParticipants([managerMcTestPersonalDetails?.accountID, currentUserAccountID]) : undefined; - return managerMcTestPersonalDetails - ? { - ...getParticipantsOption({...managerMcTestPersonalDetails, keyForList: `${managerMcTestPersonalDetails?.accountID}`}, personalDetails ?? {}), - reportID: managerMcTestReport?.reportID, - } - : undefined; -} - function shallowOptionsListCompare(a: OptionList, b: OptionList): boolean { if (!a || !b) { return false; @@ -3313,7 +3280,6 @@ export { getLastActorDisplayName, getLastActorDisplayNameFromLastVisibleActions, getLastMessageTextForReport, - getManagerMcTestParticipant, getParticipantsOption, getPersonalDetailsForAccountIDs, getPolicyExpenseReportOption, diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index 0c251c9d2e55..da68bb4bc6c3 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -203,7 +203,6 @@ type GetOptionsConfig = { includeSelectedOptions?: boolean; recentAttendees?: Option[]; excludeHidden?: boolean; - canShowManagerMcTest?: boolean; searchString?: string; searchInputValue?: string; maxElements?: number; diff --git a/src/libs/QuickActionUtils.ts b/src/libs/QuickActionUtils.ts index 35f85ea088cd..4867b7c0fe24 100644 --- a/src/libs/QuickActionUtils.ts +++ b/src/libs/QuickActionUtils.ts @@ -98,10 +98,6 @@ const getQuickActionTitle = (action: QuickActionName): TranslationPaths => { return '' as TranslationPaths; } }; -const isManagerMcTestQuickActionReport = (report: Report | undefined) => { - return !!report?.participants?.[CONST.ACCOUNT_ID.MANAGER_MCTEST]; -}; - const isQuickActionAllowed = ( quickAction: QuickAction, quickActionReport: Report | undefined, @@ -127,11 +123,6 @@ const isQuickActionAllowed = ( const iouType = getIOUType(quickAction?.action); if (iouType) { - // We're disabling QAB for Manager McTest reports to prevent confusion when submitting real data for Manager McTest - const isReportHasManagerMCTest = isManagerMcTestQuickActionReport(quickActionReport); - if (isReportHasManagerMCTest) { - return false; - } return canCreateRequest(quickActionReport, quickActionPolicy, iouType, isReportArchived, betas, isRestrictedToPreferredPolicy); } return true; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5804baaee5d1..402a7df57935 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -7139,22 +7139,6 @@ function buildOptimisticIOUReportAction(params: BuildOptimisticIOUReportActionPa message: getIOUReportActionMessage(iouReportID, type, amount, comment, currency, paymentType, isSettlingUp, bankAccountID, payAsBusiness), }; - const managerMcTestParticipant = participants.find((participant) => isSelectedManagerMcTest(participant.login)); - if (managerMcTestParticipant) { - return { - ...iouReportAction, - actorAccountID: managerMcTestParticipant.accountID, - avatar: managerMcTestParticipant.icons?.[0]?.source, - person: [ - { - style: 'strong', - text: getDisplayNameForParticipant({...managerMcTestParticipant, formatPhoneNumber: formatPhoneNumberPhoneUtils}), - type: 'TEXT', - }, - ], - }; - } - return iouReportAction; } @@ -7491,7 +7475,6 @@ function buildOptimisticReportPreview( const created = DateUtils.getDBTime(); const reportActorAccountID = (isInvoiceReport(iouReport) || isExpenseReport(iouReport) ? iouReport?.ownerAccountID : iouReport?.managerID) ?? -1; const delegateAccountDetails = getPersonalDetailByEmail(delegateEmail); - const isTestTransaction = isTestTransactionReport(iouReport); const isTestDriveTransaction = !!transaction?.receipt?.isTestDriveReceipt; const isScanRequest = transaction ? isScanRequestTransactionUtils(transaction) : false; return { @@ -7523,7 +7506,7 @@ function buildOptimisticReportPreview( childRecentReceiptTransactionIDs: hasReceipt && !isEmptyObject(transaction) && transaction?.transactionID ? {[transaction.transactionID]: created} : undefined, childOwnerAccountID: iouReport?.ownerAccountID, childManagerAccountID: iouReport?.managerID, - ...((isTestDriveTransaction || isTestTransaction) && !isScanRequest && {childStateNum: 2, childStatusNum: 4}), + ...(isTestDriveTransaction && !isScanRequest && {childStateNum: 2, childStatusNum: 4}), }; } @@ -10006,14 +9989,6 @@ function getMoneyRequestOptions( const policyOwnerAccountID = getPolicy(report?.policyID)?.ownerAccountID; const isPolicyOwnedByExpensifyAccounts = policyOwnerAccountID ? CONST.EXPENSIFY_ACCOUNT_IDS.includes(policyOwnerAccountID) : false; if (doParticipantsIncludeExpensifyAccounts && !isPolicyOwnedByExpensifyAccounts && !isPolicyExpenseChat(report) && !isExpenseReport(report)) { - // Allow create expense option for Manager McTest report - if ( - canRequestMoney(report, policy, otherParticipants) && - reportParticipants.some((accountID) => accountID === CONST.ACCOUNT_ID.MANAGER_MCTEST) && - Permissions.isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST, betas) - ) { - return [CONST.IOU.TYPE.SUBMIT]; - } return []; } @@ -10933,11 +10908,8 @@ function shouldDisableThread(reportAction: OnyxInputOrEntry, isThr const isWhisperActionLocal = isWhisperAction(reportAction) || isActionableTrackExpense(reportAction); const isDynamicWorkflowRoutedAction = isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.DYNAMIC_EXTERNAL_WORKFLOW_ROUTED); const isActionDisabled = CONST.REPORT.ACTIONS.THREAD_DISABLED.some((action: string) => action === reportAction?.actionName); - const isManagerMcTestOwner = reportAction?.actorAccountID === CONST.ACCOUNT_ID.MANAGER_MCTEST; - return ( isActionDisabled || - isManagerMcTestOwner || isSplitBillAction || (isDeletedActionLocal && !reportAction?.childVisibleActionCount) || (isReportArchived && !reportAction?.childVisibleActionCount) || @@ -12758,22 +12730,6 @@ function getReportMetadata(reportID: string | undefined) { return reportID ? allReportMetadataKeyValue[reportID] : undefined; } -/** - * Helper method to check if participant email is Manager McTest - */ -function isSelectedManagerMcTest(email: string | null | undefined): boolean { - return email === CONST.EMAIL.MANAGER_MCTEST; -} - -/** - * Helper method to check if the report is a test transaction report - */ -function isTestTransactionReport(report: OnyxEntry): boolean { - const managerID = report?.managerID ?? CONST.DEFAULT_NUMBER_ID; - const personalDetails = allPersonalDetails?.[managerID]; - return isSelectedManagerMcTest(personalDetails?.login); -} - function isWaitingForSubmissionFromCurrentUser(chatReport: OnyxEntry, policy: OnyxEntry) { return chatReport?.isOwnPolicyExpenseChat && !policy?.harvesting?.enabled; } @@ -13665,8 +13621,6 @@ export { getReportMetadata, buildOptimisticSelfDMReport, isHiddenForCurrentUser, - isSelectedManagerMcTest, - isTestTransactionReport, getReportSubtitlePrefix, computeOptimisticReportName, getPolicyChangeMessage, diff --git a/src/libs/actions/IOU/MoneyRequest.ts b/src/libs/actions/IOU/MoneyRequest.ts index 42aa204d0c9c..81711fd8bf5d 100644 --- a/src/libs/actions/IOU/MoneyRequest.ts +++ b/src/libs/actions/IOU/MoneyRequest.ts @@ -12,11 +12,10 @@ import {toLocaleDigit} from '@libs/LocaleDigitUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import {roundToTwoDecimalPlaces} from '@libs/NumberUtils'; -import {getManagerMcTestParticipant, getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; +import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; import {getCustomUnitID} from '@libs/PerDiemRequestUtils'; import {getDistanceRateCustomUnit} from '@libs/PolicyUtils'; import { - generateReportID, getPolicyExpenseChat, getReportOrDraftReport, isInvoiceRoom, @@ -135,7 +134,6 @@ type MoneyRequestStepScanParticipantsFlowParams = { policyRecentlyUsedCurrencies?: string[]; introSelected?: IntroSelected; files: ReceiptFile[]; - isTestTransaction?: boolean; locationPermissionGranted?: boolean; shouldGenerateTransactionThreadReport: boolean; selfDMReport: OnyxEntry; @@ -357,7 +355,6 @@ function handleMoneyRequestStepScanParticipants({ policyRecentlyUsedCurrencies, introSelected, files, - isTestTransaction = false, locationPermissionGranted = false, selfDMReport, isSelfTourViewed, @@ -375,28 +372,6 @@ function handleMoneyRequestStepScanParticipants({ return; } - if (isTestTransaction) { - const managerMcTestParticipant = getManagerMcTestParticipant(currentUserAccountID, personalDetails) ?? {}; - let reportIDParam = managerMcTestParticipant.reportID; - if (!managerMcTestParticipant.reportID && report?.reportID) { - reportIDParam = generateReportID(); - } - setMoneyRequestParticipants( - initialTransaction.transactionID, - [ - { - ...managerMcTestParticipant, - reportID: reportIDParam, - selected: true, - }, - ], - true, - ).then(() => { - navigateToConfirmationPage(iouType, initialTransaction.transactionID, reportID, backToReport, true, reportIDParam); - }); - return; - } - // If the user started this flow from using the + button in the composer inside a report // the participants can be automatically assigned from the report and the user can skip the participants step and go straight // to the confirmation step. @@ -1077,12 +1052,9 @@ function startDistanceRequest( } } -function setMoneyRequestParticipants(transactionID: string, participants: Participant[] = [], isTestTransaction = false) { - // We should change the reportID and isFromGlobalCreate of the test transaction since this flow can start inside an existing report +function setMoneyRequestParticipants(transactionID: string, participants: Participant[] = []) { return Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, { participants, - isFromGlobalCreate: isTestTransaction ? true : undefined, - reportID: isTestTransaction ? participants?.at(0)?.reportID : undefined, }); } diff --git a/src/libs/actions/IOU/MoneyRequestBuilder.ts b/src/libs/actions/IOU/MoneyRequestBuilder.ts index 633b4e6b3d8c..2ba4d214ebdf 100644 --- a/src/libs/actions/IOU/MoneyRequestBuilder.ts +++ b/src/libs/actions/IOU/MoneyRequestBuilder.ts @@ -11,7 +11,6 @@ import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import {translateLocal} from '@libs/Localize'; import {buildNextStepNew, buildOptimisticNextStep} from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; -import {getManagerMcTestParticipant} from '@libs/OptionsListUtils'; import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber'; import {hasDependentTags, isPaidGroupPolicy} from '@libs/PolicyUtils'; import {getOriginalMessage, isReportPreviewAction} from '@libs/ReportActionsUtils'; @@ -34,9 +33,7 @@ import { isInvoiceReport as isInvoiceReportReportUtils, isOneTransactionReport, isPolicyExpenseChat as isPolicyExpenseChatReportUtil, - isSelectedManagerMcTest, isSelfDM, - isTestTransactionReport, populateOptimisticReportFormula, shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, updateReportPreview, @@ -422,7 +419,6 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR const isTimeRequest = isTimeRequestTransactionUtils(transaction); const outstandingChildRequest = getOutstandingChildRequest(iou.report); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); - const isMoneyRequestToManagerMcTest = isTestTransactionReport(iou.report); const onyxData: OnyxData = { optimisticData: [], successData: [], @@ -618,63 +614,8 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR onyxData.failureData?.push(...testDriveFailureData); } - let iouAction = iou.action; - let iouReport = iou.report; - if (isMoneyRequestToManagerMcTest) { - const isTestReceipt = transaction.receipt?.isTestReceipt ?? false; - const managerMcTestParticipant = getManagerMcTestParticipant(currentUserAccountIDParam, personalDetails) ?? {}; - const optimisticIOUReportAction = buildOptimisticIOUReportAction({ - type: isScanRequest && !isTestReceipt ? CONST.IOU.REPORT_ACTION_TYPE.CREATE : CONST.IOU.REPORT_ACTION_TYPE.PAY, - amount: iou.report?.total ?? 0, - currency: iou.report?.currency ?? '', - comment: '', - participants: [managerMcTestParticipant], - paymentType: isScanRequest && !isTestReceipt ? undefined : CONST.IOU.PAYMENT_TYPE.ELSEWHERE, - iouReportID: iou.report.reportID, - transactionID: transaction.transactionID, - reportActionID: iou.action.reportActionID, - }); - iouAction = optimisticIOUReportAction; - iouReport = { - ...iouReport, - ...(!isScanRequest || isTestReceipt - ? {lastActionType: CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED} - : undefined), - hasOutstandingChildRequest: false, - lastActorAccountID: deprecatedCurrentUserPersonalDetails?.accountID, - }; - - onyxData.optimisticData?.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iou.report.reportID}`, - value: { - ...iou.report, - ...(!isScanRequest || isTestReceipt - ? {lastActionType: CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED} - : undefined), - hasOutstandingChildRequest: false, - lastActorAccountID: deprecatedCurrentUserPersonalDetails?.accountID, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iou.report.reportID}`, - value: { - [iou.action.reportActionID]: { - ...(optimisticIOUReportAction as OnyxTypes.ReportAction), - }, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, - value: { - ...transaction, - }, - }, - ); - } + const iouAction = iou.action; + const iouReport = iou.report; const redundantParticipants: Record = {}; if (!isEmptyObject(personalDetailListAction)) { @@ -1325,7 +1266,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma odometerStart, odometerEnd, }, - isDemoTransactionParam: isSelectedManagerMcTest(participant.login) || transactionParams.receipt?.isTestDriveReceipt, + isDemoTransactionParam: transactionParams.receipt?.isTestDriveReceipt, }); iouReport.transactionCount = (iouReport.transactionCount ?? 0) + 1; @@ -1389,7 +1330,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma payeeEmail, participants: [participant], transactionID: optimisticTransaction.transactionID, - paymentType: isSelectedManagerMcTest(participant.login) || transactionParams.receipt?.isTestDriveReceipt ? CONST.IOU.PAYMENT_TYPE.ELSEWHERE : undefined, + paymentType: transactionParams.receipt?.isTestDriveReceipt ? CONST.IOU.PAYMENT_TYPE.ELSEWHERE : undefined, existingTransactionThreadReportID: linkedTrackedExpenseReportAction?.childReportID, optimisticCreatedReportActionID, linkedTrackedExpenseReportAction, diff --git a/src/pages/iou/request/ParticipantSearchResults.tsx b/src/pages/iou/request/ParticipantSearchResults.tsx index b2b6f6e473bb..152f18924a5b 100644 --- a/src/pages/iou/request/ParticipantSearchResults.tsx +++ b/src/pages/iou/request/ParticipantSearchResults.tsx @@ -24,7 +24,6 @@ import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap'; import useReportAttributes from '@hooks/useReportAttributes'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useSearchSelector from '@hooks/useSearchSelector'; -import useTransactionDraftValues from '@hooks/useTransactionDraftValues'; import useUserToInviteReports from '@hooks/useUserToInviteReports'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import goToSettings from '@libs/goToSettings'; @@ -152,22 +151,13 @@ function ParticipantSearchResults({ const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED); - const [hasBeenAddedToNudgeMigration] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, { - selector: (tryNewDot) => !!tryNewDot?.nudgeMigration?.timestamp, - }); const {isRestrictedToPreferredPolicy, preferredPolicyID} = usePreferredPolicy(); - const optimisticTransactions = useTransactionDraftValues(); const {isDismissed: isDismissedReferralBanner} = useDismissedReferralBanners({referralContentType: CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE}); const isPaidGroupPolicy = isPaidGroupPolicyUtil(policy); const activeAdminWorkspaces = getActiveAdminWorkspaces(allPolicies, currentUserLogin); - // This is necessary to prevent showing the Manager McTest when there are multiple transactions being created - const hasMultipleTransactions = optimisticTransactions.length > 1; - const isCurrentUserMemberOfAnyPolicy = Object.values(allPolicies ?? {}).some((pol) => pol?.isPolicyExpenseChatEnabled && pol?.id && pol.id !== CONST.POLICY.ID_FAKE); - const canShowManagerMcTest = !hasBeenAddedToNudgeMigration && action !== CONST.IOU.ACTION.SUBMIT && !hasMultipleTransactions && !isCurrentUserMemberOfAnyPolicy; - const getValidOptionsConfig = { selectedOptions: participants as Participant[], excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, @@ -179,7 +169,6 @@ function ParticipantSearchResults({ shouldSeparateSelfDMChat: iouType !== CONST.IOU.TYPE.INVOICE, shouldSeparateWorkspaceChat: true, includeSelfDM: !isMovingTransactionFromTrackExpense(action) && iouType !== CONST.IOU.TYPE.INVOICE, - canShowManagerMcTest, isPerDiemRequest, isTimeRequest, showRBR: false, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index ad1da43a3e92..3523417acdff 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -54,14 +54,7 @@ import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTop import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; -import { - findSelfDMReportID, - getPolicyExpenseChat, - getReportOrDraftReport, - isMoneyRequestReport, - isPolicyExpenseChat as isPolicyExpenseChatUtils, - isSelectedManagerMcTest, -} from '@libs/ReportUtils'; +import {findSelfDMReportID, getPolicyExpenseChat, getReportOrDraftReport, isMoneyRequestReport, isPolicyExpenseChat as isPolicyExpenseChatUtils} from '@libs/ReportUtils'; import {buildCannedSearchQuery, getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; import shouldUseDefaultExpensePolicy from '@libs/shouldUseDefaultExpensePolicy'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; @@ -229,9 +222,8 @@ function IOURequestStepConfirmation({ const isSharingTrackExpense = action === CONST.IOU.ACTION.SHARE; const isCategorizingTrackExpense = action === CONST.IOU.ACTION.CATEGORIZE; const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseIOUUtils(action); - const isTestTransaction = transaction?.participants?.some((participant) => isSelectedManagerMcTest(participant.login)); - const gpsRequired = transaction?.amount === 0 && iouType !== CONST.IOU.TYPE.SPLIT && Object.values(receiptFiles).length && !isTestTransaction && isScanRequest(transaction); + const gpsRequired = transaction?.amount === 0 && iouType !== CONST.IOU.TYPE.SPLIT && Object.values(receiptFiles).length && isScanRequest(transaction); const [isStitchingReceipt, setIsStitchingReceipt] = useState(false); const [stitchError, setStitchError] = useState(''); const headerTitle = useMemo(() => { diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index 2102bfd8b68e..9e8d193bcf7f 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -51,7 +51,7 @@ type MobileWebCameraViewProps = { isEditing: boolean; validateFiles: (files: FileObject[], items?: DataTransferItem[]) => void; setReceiptFiles: React.Dispatch>; - navigateToConfirmationStep: (files: ReceiptFile[], locationPermissionGranted?: boolean, isTestTransaction?: boolean) => void; + navigateToConfirmationStep: (files: ReceiptFile[], locationPermissionGranted?: boolean) => void; shouldSkipConfirmation: boolean; setStartLocationPermissionFlow: (value: boolean) => void; onBackButtonPress: () => void; diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index 10577fa25d68..f082badda897 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -97,7 +97,7 @@ function useReceiptScan({ ); const participantsPolicyTags = useParticipantsPolicyTags(participants); - function navigateToConfirmationStep(files: ReceiptFile[], locationPermissionGranted = false, isTestTransaction = false) { + function navigateToConfirmationStep(files: ReceiptFile[], locationPermissionGranted = false) { startSpan(CONST.TELEMETRY.SPAN_SCAN_PROCESS_AND_NAVIGATE, { name: CONST.TELEMETRY.SPAN_SCAN_PROCESS_AND_NAVIGATE, op: CONST.TELEMETRY.SPAN_SCAN_PROCESS_AND_NAVIGATE, @@ -137,7 +137,6 @@ function useReceiptScan({ policyRecentlyUsedCurrencies, introSelected, files, - isTestTransaction, locationPermissionGranted, selfDMReport, policyForMovingExpenses, diff --git a/src/pages/iou/request/step/IOURequestStepScan/types.ts b/src/pages/iou/request/step/IOURequestStepScan/types.ts index 8c739e180909..2001add4a617 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/types.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/types.ts @@ -67,7 +67,7 @@ type UseMobileReceiptScanParams = { receiptFiles: ReceiptFile[]; /** Callback to navigate to the confirmation step */ - navigateToConfirmationStep: (files: ReceiptFile[], locationPermissionGranted?: boolean, isTestTransaction?: boolean) => void; + navigateToConfirmationStep: (files: ReceiptFile[], locationPermissionGranted?: boolean) => void; /** Whether the confirmation step should be skipped */ shouldSkipConfirmation: boolean; diff --git a/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts index b9d0b2f006b6..c9655ecce11f 100644 --- a/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts +++ b/src/pages/iou/request/step/confirmation/useExpenseSubmission.ts @@ -26,7 +26,7 @@ import navigateAfterExpenseCreate from '@libs/Navigation/helpers/navigateAfterEx import Navigation from '@libs/Navigation/Navigation'; import {rand64, roundToTwoDecimalPlaces} from '@libs/NumberUtils'; import {isTaxTrackingEnabled} from '@libs/PolicyUtils'; -import {findSelfDMReportID, generateReportID, getReportOrDraftReport, hasViolations as hasViolationsReportUtils, isMoneyRequestReport, isSelectedManagerMcTest} from '@libs/ReportUtils'; +import {findSelfDMReportID, generateReportID, getReportOrDraftReport, hasViolations as hasViolationsReportUtils, isMoneyRequestReport} from '@libs/ReportUtils'; import {endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans'; import markSubmitExpenseEnd from '@libs/telemetry/markSubmitExpenseEnd'; import { @@ -840,13 +840,7 @@ function useExpenseSubmission(params: UseExpenseSubmissionParams) { if (Object.values(receiptFiles).filter((receipt) => !!receipt).length && !!transaction) { // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. - if ( - transaction.amount === 0 && - !isSharingTrackExpense && - !isCategorizingTrackExpense && - locationPermissionGranted && - !selectedParticipantsArg.some((participant) => isSelectedManagerMcTest(participant.login)) - ) { + if (transaction.amount === 0 && !isSharingTrackExpense && !isCategorizingTrackExpense && locationPermissionGranted) { if (userLocation) { requestMoney(selectedParticipantsArg, shouldHandleNavigation, { lat: userLocation.latitude, diff --git a/tests/actions/IOU/MoneyRequestTest.ts b/tests/actions/IOU/MoneyRequestTest.ts index 0adb927a1767..abdce1aed17e 100644 --- a/tests/actions/IOU/MoneyRequestTest.ts +++ b/tests/actions/IOU/MoneyRequestTest.ts @@ -538,8 +538,6 @@ describe('MoneyRequest', () => { const fileObj = new File([new Blob(['test'])], 'test.jpg', {type: 'image/jpeg'}); const fakeReceiptFile: ReceiptFile = {transactionID: fakeTransaction.transactionID, file: fileObj, source: 12345}; const backTo = ROUTES.REPORT_WITH_ID.getRoute('123'); - const managerMcTestAccountID = 444; - const selfDMReport = createSelfDM(Number(SELF_DM_REPORT_ID), TEST_USER_ACCOUNT_ID); const baseParams: MoneyRequestStepScanParticipantsFlowParams = { @@ -630,50 +628,6 @@ describe('MoneyRequest', () => { expect(Navigation.goBack).toHaveBeenCalledWith(backTo); }); - it('should set manager mc test participant for the test transaction and navigate to confirmation page', async () => { - jest.spyOn(ReportUtils, 'generateReportID').mockReturnValue('123'); - - await Onyx.set(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`, { - [managerMcTestAccountID]: { - accountID: managerMcTestAccountID, - login: CONST.EMAIL.MANAGER_MCTEST, - displayName: 'Manager MC Test', - }, - }); - - handleMoneyRequestStepScanParticipants({ - ...baseParams, - isTestTransaction: true, - allTransactionDrafts: {}, - personalDetails: { - ...baseParams.personalDetails, - [managerMcTestAccountID]: { - accountID: managerMcTestAccountID, - login: CONST.EMAIL.MANAGER_MCTEST, - displayName: 'Manager MC Test', - }, - }, - }); - - await waitForBatchedUpdates(); - - const updatedTransaction = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${baseParams.initialTransaction.transactionID}`); - expect(updatedTransaction).toMatchObject({ - participants: [ - expect.objectContaining({ - accountID: managerMcTestAccountID, - login: CONST.EMAIL.MANAGER_MCTEST, - selected: true, - }), - ], - isFromGlobalCreate: true, - }); - - expect(Navigation.navigate).toHaveBeenCalledWith( - ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.ACTION.SUBMIT, baseParams.initialTransaction.transactionID, '123'), - ); - }); - it('should startSplitBill for SPLIT iouType when not from global create menu and skipping confirmation', async () => { handleMoneyRequestStepScanParticipants({ ...baseParams, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 177197afb816..5f81ed9e7616 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -37,7 +37,6 @@ import Log from '@libs/Log'; import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import {rand64} from '@libs/NumberUtils'; -import {getManagerMcTestParticipant} from '@libs/OptionsListUtils'; import type * as PolicyUtils from '@libs/PolicyUtils'; import {getAllReportActions, getIOUActionForReportID, getOriginalMessage, isActionableTrackExpense, isActionOfType, isMoneyRequestAction} from '@libs/ReportActionsUtils'; import {buildOptimisticIOUReportAction, createDraftTransactionAndNavigateToParticipantSelector, getReportOrDraftReport} from '@libs/ReportUtils'; @@ -6301,55 +6300,6 @@ describe('actions/IOU', () => { }); }); - describe('getManagerMcTestParticipant', () => { - it('should return manager mctest participant when personalDetails contains manager_mctest', () => { - // Given personalDetails that include manager_mctest - const managerMcTestAccountID = CONST.ACCOUNT_ID.MANAGER_MCTEST; - const personalDetailsList: PersonalDetailsList = { - [managerMcTestAccountID]: { - accountID: managerMcTestAccountID, - login: CONST.EMAIL.MANAGER_MCTEST, - displayName: 'Manager McTest', - }, - }; - - // When calling getManagerMcTestParticipant with personalDetails - const result = getManagerMcTestParticipant(RORY_ACCOUNT_ID, personalDetailsList); - - // Then it should return a participant with the manager mctest account ID - expect(result).toBeDefined(); - expect(result?.accountID).toBe(managerMcTestAccountID); - }); - - it('should return undefined when personalDetails does not contain manager_mctest', () => { - // Given personalDetails without manager_mctest - const personalDetailsList: PersonalDetailsList = { - [RORY_ACCOUNT_ID]: { - accountID: RORY_ACCOUNT_ID, - login: RORY_EMAIL, - displayName: 'Rory', - }, - }; - - // When calling getManagerMcTestParticipant with personalDetails - const result = getManagerMcTestParticipant(RORY_ACCOUNT_ID, personalDetailsList); - - // Then it should return undefined since manager_mctest is not in the provided personalDetails - expect(result).toBeUndefined(); - }); - - it('should return undefined when personalDetails is empty', () => { - // Given empty personalDetails - const personalDetailsList: PersonalDetailsList = {}; - - // When calling getManagerMcTestParticipant with empty personalDetails - const result = getManagerMcTestParticipant(RORY_ACCOUNT_ID, personalDetailsList); - - // Then it should return undefined - expect(result).toBeUndefined(); - }); - }); - describe('Report Totals Calculation for Split Expenses', () => { function calculateReportTotalsForSplitExpenses( expenseReport: Report | undefined, diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index a642dc212c3d..bcd13147b407 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -429,22 +429,6 @@ describe('OptionsListUtils', () => { }, }; - const REPORTS_WITH_MANAGER_MCTEST: OnyxCollection = { - ...REPORTS, - '18': { - lastReadTime: '2021-01-14 11:25:39.302', - lastVisibleActionCreated: '2022-11-22 03:26:02.022', - isPinned: false, - reportID: '18', - participants: { - 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, - 1003: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, - }, - reportName: 'Manager McTest', - type: CONST.REPORT.TYPE.CHAT, - }, - }; - const activePolicyID = 'DEF456'; // And a set of personalDetails some with existing reports and some without @@ -567,17 +551,6 @@ describe('OptionsListUtils', () => { }, }; - const PERSONAL_DETAILS_WITH_MANAGER_MCTEST: PersonalDetailsList = { - ...PERSONAL_DETAILS, - '1003': { - accountID: 1003, - displayName: 'Manager McTest', - login: CONST.EMAIL.MANAGER_MCTEST, - keyForList: CONST.EMAIL.MANAGER_MCTEST, - reportID: '', - }, - }; - const PERSONAL_DETAILS_WITH_PERIODS: PersonalDetailsList = { ...PERSONAL_DETAILS, @@ -734,13 +707,10 @@ describe('OptionsListUtils', () => { const MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CHRONOS = createMockReportAttributesDerived(REPORTS_WITH_CHRONOS, PERSONAL_DETAILS_WITH_CHRONOS, CURRENT_USER_ACCOUNT_ID); const MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_RECEIPTS = createMockReportAttributesDerived(REPORTS_WITH_RECEIPTS, PERSONAL_DETAILS_WITH_RECEIPTS, CURRENT_USER_ACCOUNT_ID); const MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_WORKSPACE_ROOM = createMockReportAttributesDerived(REPORTS_WITH_WORKSPACE_ROOMS, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID); - const MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_MANAGER_MCTEST = createMockReportAttributesDerived(REPORTS_WITH_MANAGER_MCTEST, PERSONAL_DETAILS_WITH_MANAGER_MCTEST, CURRENT_USER_ACCOUNT_ID); - let OPTIONS_WITH_CONCIERGE: OptionList; let OPTIONS_WITH_CHRONOS: OptionList; let OPTIONS_WITH_RECEIPTS: OptionList; let OPTIONS_WITH_WORKSPACE_ROOM: OptionList; - let OPTIONS_WITH_MANAGER_MCTEST: OptionList; // Set the currently logged in user, report data, and personal details beforeAll(async () => { @@ -791,13 +761,6 @@ describe('OptionsListUtils', () => { undefined, MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_WORKSPACE_ROOM, ); - OPTIONS_WITH_MANAGER_MCTEST = createOptionList( - PERSONAL_DETAILS_WITH_MANAGER_MCTEST, - EMPTY_PRIVATE_IS_ARCHIVED_MAP, - REPORTS_WITH_MANAGER_MCTEST, - undefined, - MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_MANAGER_MCTEST, - ); }); describe('getSearchOptions()', () => { @@ -1259,56 +1222,6 @@ describe('OptionsListUtils', () => { expect(results.personalDetails).not.toEqual(expect.arrayContaining([expect.objectContaining({login: 'receipts@expensify.com'})])); }); - it('should include Manager McTest in results by default', () => { - // Given a set of reports and personalDetails that includes Manager McTest - // When we call getValidOptions() - const result = getValidOptions( - {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - allPolicies, - {}, - loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - undefined, - { - includeP2P: true, - canShowManagerMcTest: true, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - sortedActions: undefined, - }, - ); - - // Then the result should include all personalDetails except the currently logged in user - expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 1); - // Then the result should include Manager McTest - expect(result.personalDetails).toEqual(expect.arrayContaining([expect.objectContaining({login: CONST.EMAIL.MANAGER_MCTEST})])); - }); - - it('should exclude Manager McTest from results if flag is set to false', () => { - // Given a set of reports and personalDetails that includes Manager McTest and a config object that excludes Manager McTest - // When we call getValidOptions() - const result = getValidOptions( - {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - allPolicies, - {}, - loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - undefined, - { - includeP2P: true, - canShowManagerMcTest: false, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - sortedActions: undefined, - }, - ); - - // Then the result should include all personalDetails except the currently logged in user and Manager McTest - expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 2); - // Then the result should not include Manager McTest - expect(result.personalDetails).not.toEqual(expect.arrayContaining([expect.objectContaining({login: CONST.EMAIL.MANAGER_MCTEST})])); - }); - it('should keep admin rooms if specified', () => { // Given an admin room report search option const adminRoom: SearchOption = { @@ -2047,25 +1960,6 @@ describe('OptionsListUtils', () => { expect(result).toBe(false); }); - it('should return false when the last action is a REPORT_PREVIEW with MANAGER_MCTEST as participant', () => { - // Given a report with a REPORT_PREVIEW last action and MANAGER_MCTEST as participant - const report = { - ...REPORTS['1'], - participants: { - 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, - [CONST.ACCOUNT_ID.MANAGER_MCTEST]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, - }, - } as Report; - const lastActorDetails = PERSONAL_DETAILS['2']; - const lastAction: ReportAction = { - ...createRandomReportAction(1), - actionName: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW, - }; - - const result = shouldShowLastActorDisplayName(report, lastActorDetails, lastAction, currentUserAccountID); - expect(result).toBe(false); - }); - it('should return false when getLastActorDisplayName returns empty string', () => { renderLocaleContextProvider(); // Given a report with lastActorDetails that has no displayName or firstName diff --git a/tests/unit/PersonalDetailOptionsListUtilsTest.ts b/tests/unit/PersonalDetailOptionsListUtilsTest.ts index c007636bfe5e..cb57564b4a6e 100644 --- a/tests/unit/PersonalDetailOptionsListUtilsTest.ts +++ b/tests/unit/PersonalDetailOptionsListUtilsTest.ts @@ -294,15 +294,6 @@ describe('PersonalDetailOptionsListUtils', () => { }, }; - const PERSONAL_DETAILS_WITH_MANAGER_MCTEST: PersonalDetailsList = { - ...PERSONAL_DETAILS, - '1003': { - accountID: 1003, - displayName: 'Manager McTest', - login: CONST.EMAIL.MANAGER_MCTEST, - }, - }; - const ACCOUNT_ID_TO_REPORT_ID_MAP: Record = { 1: '3', 2: '17', // Self-DM @@ -344,7 +335,6 @@ describe('PersonalDetailOptionsListUtils', () => { let OPTIONS_WITH_CONCIERGE: OptionList; let OPTIONS_WITH_CHRONOS: OptionList; let OPTIONS_WITH_RECEIPTS: OptionList; - let OPTIONS_WITH_MANAGER_MCTEST: OptionList; let OPTIONS_WITH_SELF_DM: OptionList; function translateReportObjectToOnyxCollection(reports: OnyxCollection): OnyxCollection { @@ -398,15 +388,6 @@ describe('PersonalDetailOptionsListUtils', () => { {}, formatPhoneNumber, ); - OPTIONS_WITH_MANAGER_MCTEST = createOptionList( - currentUserAccountID, - PERSONAL_DETAILS_WITH_MANAGER_MCTEST, - ACCOUNT_ID_TO_REPORT_ID_MAP, - translateReportObjectToOnyxCollection(REPORTS), - undefined, - {}, - formatPhoneNumber, - ); }); describe('Basic option list test', () => { @@ -416,7 +397,6 @@ describe('PersonalDetailOptionsListUtils', () => { expect(OPTIONS_WITH_CONCIERGE.options.length).toBe(Object.keys(PERSONAL_DETAILS_WITH_CONCIERGE).length); expect(OPTIONS_WITH_CHRONOS.options.length).toBe(Object.keys(PERSONAL_DETAILS_WITH_CHRONOS).length); expect(OPTIONS_WITH_RECEIPTS.options.length).toBe(Object.keys(PERSONAL_DETAILS_WITH_RECEIPTS).length); - expect(OPTIONS_WITH_MANAGER_MCTEST.options.length).toBe(Object.keys(PERSONAL_DETAILS_WITH_MANAGER_MCTEST).length); }); it('should have created the expected current user option', () => { diff --git a/tests/unit/QuickActionUtilsTest.ts b/tests/unit/QuickActionUtilsTest.ts index 70b498ebe0ba..29c8f4b7815c 100644 --- a/tests/unit/QuickActionUtilsTest.ts +++ b/tests/unit/QuickActionUtilsTest.ts @@ -15,38 +15,6 @@ const mockedPolicyUtils = PolicyUtils as jest.Mocked; describe('QuickActionUtils', () => { describe('isQuickActionAllowed', () => { - describe('Manager McTest restrictions', () => { - const requestScanAction = { - action: CONST.QUICK_ACTIONS.REQUEST_SCAN, - isFirstQuickAction: false, - }; - - // Given a report with Manager McTest - const reportWithManagerMcTest: Report = { - reportID: '1', - participants: { - [CONST.ACCOUNT_ID.MANAGER_MCTEST]: { - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, - }, - }, - }; - - beforeEach(() => { - jest.clearAllMocks(); - mockedPolicyUtils.isControlPolicy.mockReturnValue(true); - }); - - it('should return false when report contains Manager McTest', () => { - mockedPolicyUtils.shouldShowPolicy.mockReturnValue(false); - - // When the report contains Manager McTest - const result = isQuickActionAllowed(requestScanAction, reportWithManagerMcTest, undefined, undefined, [CONST.BETAS.ALL]); - - // Then it should return false - expect(result).toBe(false); - }); - }); - describe('Preferred policy restrictions', () => { const requestManualAction = { action: CONST.QUICK_ACTIONS.REQUEST_MANUAL, diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index ccc0854acb2e..a0bf33b201c7 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -4488,29 +4488,6 @@ describe('ReportUtils', () => { expect(shouldDisableThread(reportAction, true)).toBeTruthy(); }); - it('should disable thread for messages sent by MANAGER_MCTEST', () => { - // Given a report action from MANAGER_MCTEST - const reportAction = { - actorAccountID: CONST.ACCOUNT_ID.MANAGER_MCTEST, - message: [ - { - translationKey: '', - type: 'COMMENT', - html: 'Test message from Manager McTest', - text: 'Test message from Manager McTest', - }, - ], - actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, - } as ReportAction; - - // When it's checked to see if the thread should be disabled - const isThreadDisabled = shouldDisableThread(reportAction, false); - - // Then the thread should be disabled - // This ensures "Reply in thread" and "Join thread" context menu options won't be shown - expect(isThreadDisabled).toBeTruthy(); - }); - it('should disable on a DYNAMIC_EXTERNAL_WORKFLOW_ROUTED action', () => { const reportAction = { actionName: CONST.REPORT.ACTIONS.TYPE.DYNAMIC_EXTERNAL_WORKFLOW_ROUTED, diff --git a/tests/unit/hooks/useReceiptScan.test.ts b/tests/unit/hooks/useReceiptScan.test.ts index 7ee38640e129..d6396ac94fe6 100644 --- a/tests/unit/hooks/useReceiptScan.test.ts +++ b/tests/unit/hooks/useReceiptScan.test.ts @@ -459,13 +459,12 @@ describe('useReceiptScan', () => { const files = [{file: {uri: 'receipt.jpg'}, source: 'file://receipt.jpg', transactionID: INITIAL_TRANSACTION_ID}]; await act(async () => { - result.current.navigateToConfirmationStep(files, false, false); + result.current.navigateToConfirmationStep(files, false); }); expect(mockHandleMoneyRequestStepScanParticipants).toHaveBeenCalledWith( expect.objectContaining({ files, - isTestTransaction: false, locationPermissionGranted: false, }), ); From ceee0555a01b310b9912ec403ca15ed458ee25dc Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Tue, 19 May 2026 14:15:29 +0000 Subject: [PATCH 2/7] Fix QuickActionUtilsTest: mock isControlPolicy instead of isPaidGroupPolicy and spy canCreateRequest The per diem test mocked isPaidGroupPolicy but the source code calls isControlPolicy. Both per diem and time tracking positive tests also need canCreateRequest mocked since the minimal test data doesn't satisfy the real canCreateRequest conditions. Co-authored-by: Ishpaul Singh --- tests/unit/QuickActionUtilsTest.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/QuickActionUtilsTest.ts b/tests/unit/QuickActionUtilsTest.ts index 29c8f4b7815c..5e872ba13fc4 100644 --- a/tests/unit/QuickActionUtilsTest.ts +++ b/tests/unit/QuickActionUtilsTest.ts @@ -1,6 +1,7 @@ import Onyx from 'react-native-onyx'; import * as PolicyUtils from '@libs/PolicyUtils'; import {isQuickActionAllowed} from '@libs/QuickActionUtils'; +import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report} from '@src/types/onyx'; @@ -133,6 +134,7 @@ describe('QuickActionUtils', () => { jest.clearAllMocks(); }); it('should allow per diem action when policy has per diem rates', () => { + jest.spyOn(ReportUtils, 'canCreateRequest').mockReturnValue(true); const perDiemCustomUnit = { name: CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL, customUnitID: 'ABCDEF', @@ -152,7 +154,7 @@ describe('QuickActionUtils', () => { ABCDEF: perDiemCustomUnit, }, } as unknown as Policy; - mockedPolicyUtils.isPaidGroupPolicy.mockReturnValue(true); + mockedPolicyUtils.isControlPolicy.mockReturnValue(true); expect(isQuickActionAllowed(perDiemAction, report, policy, false, [CONST.BETAS.ALL], false)).toBe(true); }); @@ -200,6 +202,7 @@ describe('QuickActionUtils', () => { describe('Policy with time tracking', () => { it('should allow requestTime action when policy has time tracking enabled', () => { mockedPolicyUtils.isTimeTrackingEnabled.mockReturnValue(true); + jest.spyOn(ReportUtils, 'canCreateRequest').mockReturnValue(true); expect( isQuickActionAllowed( {action: CONST.QUICK_ACTIONS.REQUEST_TIME}, From 8c3b4bb52634246e995def3b35bb696c1284ffbc Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Tue, 19 May 2026 14:36:56 +0000 Subject: [PATCH 3/7] Fix: pass full Policy object to shouldRestrictUserBillableActions instead of policy ID string After merging main, the new shouldRestrictUserBillableActions calls from PR \#88363 were passing defaultExpensePolicy.id (a string) where the function expects OnyxEntry. This fixes all 5 call sites. Co-authored-by: Ishpaul Singh --- src/components/MoneyRequestHeaderSecondaryActions.tsx | 2 +- src/hooks/useExpenseActions.ts | 4 ++-- src/hooks/useSearchBulkActions.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestHeaderSecondaryActions.tsx b/src/components/MoneyRequestHeaderSecondaryActions.tsx index cb81dd69f6aa..4d0ce7c2e739 100644 --- a/src/components/MoneyRequestHeaderSecondaryActions.tsx +++ b/src/components/MoneyRequestHeaderSecondaryActions.tsx @@ -359,7 +359,7 @@ function MoneyRequestHeaderSecondaryActions({reportID, onBackButtonPress}: Money iconFill: isDuplicateActive ? undefined : theme.icon, value: CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.DUPLICATE, onSelected: () => { - if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { + if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { dropdownMenuRef.current?.setIsMenuVisible(false); Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id)); return; diff --git a/src/hooks/useExpenseActions.ts b/src/hooks/useExpenseActions.ts index ebf4d214d461..132028c047e0 100644 --- a/src/hooks/useExpenseActions.ts +++ b/src/hooks/useExpenseActions.ts @@ -322,7 +322,7 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic iconFill: isDuplicateActive ? undefined : theme.icon, value: CONST.REPORT.SECONDARY_ACTIONS.DUPLICATE_EXPENSE, onSelected: () => { - if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { + if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { onDuplicateReset?.(); Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id)); return; @@ -383,7 +383,7 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic const isSourcePolicyValid = !!policy && isPolicyAccessible(policy, currentUserLogin ?? ''); const targetPolicyForDuplicate = isSourcePolicyValid ? policy : defaultExpensePolicy; - if (targetPolicyForDuplicate && shouldRestrictUserBillableActions(targetPolicyForDuplicate.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { + if (targetPolicyForDuplicate && shouldRestrictUserBillableActions(targetPolicyForDuplicate, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { onDuplicateReset?.(); Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(targetPolicyForDuplicate.id)); return; diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 93775f43c2e5..a80c3ab6b7a4 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -1134,7 +1134,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { value: CONST.SEARCH.BULK_ACTION_TYPES.DUPLICATE, shouldCloseModalOnSelect: true, onSelected: () => { - if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { + if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id)); return; } @@ -1483,7 +1483,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { value: CONST.SEARCH.BULK_ACTION_TYPES.DUPLICATE, shouldCloseModalOnSelect: true, onSelected: () => { - if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { + if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id)); return; } From 6026826161d19d0e7dbc20438125bbf77fbd12e0 Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Tue, 19 May 2026 14:42:46 +0000 Subject: [PATCH 4/7] Fix: remove unused imports and variables left over from Manager McTest removal Co-authored-by: Ishpaul Singh --- src/libs/OptionsListUtils/index.ts | 1 - src/libs/actions/IOU/MoneyRequestBuilder.ts | 2 -- tests/actions/IOU/MoneyRequestTest.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 93d767a332a1..44a6b474373b 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -117,7 +117,6 @@ import type {OptionData} from '@libs/ReportUtils'; import { canUserPerformWriteAction, formatReportLastMessageText, - getChatByParticipants, getChatRoomSubtitle, getDeletedParentActionMessageForChatReport, getDeletedTransactionMessage, diff --git a/src/libs/actions/IOU/MoneyRequestBuilder.ts b/src/libs/actions/IOU/MoneyRequestBuilder.ts index 2ba4d214ebdf..9ab324b67a43 100644 --- a/src/libs/actions/IOU/MoneyRequestBuilder.ts +++ b/src/libs/actions/IOU/MoneyRequestBuilder.ts @@ -384,7 +384,6 @@ function getTransactionWithPreservedLocalReceiptSource(transaction: OnyxTypes.Tr function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyRequestParams): OnyxData { const allReports = getAllReports(); - const deprecatedCurrentUserPersonalDetails = getCurrentUserPersonalDetails(); const { isNewChatReport, shouldCreateNewMoneyRequestReport, @@ -400,7 +399,6 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR currentUserEmailParam, hasViolations, quickAction, - personalDetails, } = moneyRequestParams; const {policy, policyCategories, policyTagList} = policyParams; const { diff --git a/tests/actions/IOU/MoneyRequestTest.ts b/tests/actions/IOU/MoneyRequestTest.ts index abdce1aed17e..b72af0c18534 100644 --- a/tests/actions/IOU/MoneyRequestTest.ts +++ b/tests/actions/IOU/MoneyRequestTest.ts @@ -17,7 +17,6 @@ import type * as IOU from '../../../src/libs/actions/IOU'; import * as Split from '../../../src/libs/actions/IOU/Split'; import * as TrackExpense from '../../../src/libs/actions/IOU/TrackExpense'; import DistanceRequestUtils from '../../../src/libs/DistanceRequestUtils'; -import * as ReportUtils from '../../../src/libs/ReportUtils'; import createRandomPolicy from '../../utils/collections/policies'; import {createRandomReport, createSelfDM} from '../../utils/collections/reports'; import createRandomTransaction from '../../utils/collections/transaction'; From f0695570b0aea97ebf0b2b02748615ee35b38057 Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Thu, 21 May 2026 17:00:24 +0000 Subject: [PATCH 5/7] Address review feedback: clean up leftover Manager McTest references - Update JSDoc comment on isTestReceipt in Transaction.ts (remove manager_mctest reference) - Delete dangling EXPENSIFY_ACCOUNT_ID_MANAGER_MCTEST from .env.example - Restore eslint-disable comment in useSearchBulkActions.ts (unrelated removal) Co-authored-by: Ishpaul Singh --- .env.example | 1 - src/hooks/useSearchBulkActions.ts | 1 + src/types/onyx/Transaction.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 6b457132e6d2..78cc6d5b192c 100644 --- a/.env.example +++ b/.env.example @@ -35,7 +35,6 @@ EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1 EXPENSIFY_ACCOUNT_ID_REWARDS=-1 EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1 EXPENSIFY_ACCOUNT_ID_SVFG=-1 -EXPENSIFY_ACCOUNT_ID_MANAGER_MCTEST=-1 FB_API_KEY=YOUR_API_KEY FB_APP_ID=YOUR_APP_ID diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index a80c3ab6b7a4..8bcf2b9def2f 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/refs */ import {useCallback, useEffect, useMemo, useRef, useState} from 'react'; // eslint-disable-next-line no-restricted-imports import {InteractionManager} from 'react-native'; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 4e97adf153f9..43f31daf017e 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -235,7 +235,7 @@ type Receipt = { /** Collection of reservations */ reservationList?: Reservation[]; - /** Receipt is manager_mctest@expensify.com testing receipt */ + /** Whether this is a test receipt */ isTestReceipt?: true; /** Receipt is Test Drive testing receipt */ From 7e2592db345aa858aa2686563475676f08500d12 Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Sat, 23 May 2026 21:16:16 +0000 Subject: [PATCH 6/7] Merge main and add justification to eslint-disable comment Synced with main and added a justification comment to the react-hooks/refs eslint-disable directive in useSearchBulkActions.ts per review feedback. Co-authored-by: Ishpaul Singh --- src/hooks/useSearchBulkActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 7c08badccd66..77cb29ee147d 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -1,4 +1,4 @@ -/* eslint-disable react-hooks/refs */ +/* eslint-disable react-hooks/refs -- Refs in this hook are used inside callbacks that capture stable references; the lint rule flags false positives for these patterns */ import {useCallback, useEffect, useMemo, useRef, useState} from 'react'; // eslint-disable-next-line no-restricted-imports import {InteractionManager} from 'react-native'; From a1c2f0b8e9aa05355a7c8fadd291689aff21b359 Mon Sep 17 00:00:00 2001 From: "Ishpaul Singh (via MelvinBot)" Date: Sat, 23 May 2026 21:32:05 +0000 Subject: [PATCH 7/7] Remove unused getCurrentUserPersonalDetails import The import was left behind after removing Manager McTest code that was the only consumer. This fixes the ESLint no-unused-vars error. Co-authored-by: Ishpaul Singh --- src/libs/actions/IOU/MoneyRequestBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU/MoneyRequestBuilder.ts b/src/libs/actions/IOU/MoneyRequestBuilder.ts index b142df4c0987..af49c08fb58e 100644 --- a/src/libs/actions/IOU/MoneyRequestBuilder.ts +++ b/src/libs/actions/IOU/MoneyRequestBuilder.ts @@ -63,7 +63,7 @@ import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Receipt, TransactionChanges, TransactionCustomUnit, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import {getAllPersonalDetails, getAllReportActionsFromIOU, getAllReportNameValuePairs, getAllReports, getCurrentUserPersonalDetails} from './index'; +import {getAllPersonalDetails, getAllReportActionsFromIOU, getAllReportNameValuePairs, getAllReports} from './index'; import type {ReplaceReceipt} from './Receipt'; import {getSearchOnyxUpdate} from './SearchUpdate'; import type {StartSplitBilActionParams} from './Split';